blob: a45c728f56f4966a8b5a4e73858a4296127e6e8a [file] [log] [blame]
#ifndef _TCUFORMATUTIL_HPP
#define _TCUFORMATUTIL_HPP
/*-------------------------------------------------------------------------
* drawElements Quality Program Tester Core
* ----------------------------------------
*
* Copyright 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*//*!
* \file
* \brief String format utilities.
*//*--------------------------------------------------------------------*/
#include "tcuDefs.hpp"
#include "deString.h"
#include <ostream>
#include <string>
namespace tcu
{
namespace Format
{
// Hexadecimal value formatter.
template <size_t NumDigits>
class Hex
{
public:
Hex (deUint64 value_) : value(value_) {}
std::ostream& toStream (std::ostream& stream) const
{
return stream << this->toString();
}
std::string toString (void) const
{
DE_STATIC_ASSERT(0 < NumDigits && NumDigits <= 16);
const char longFmt[] = {'0', 'x', '%', '0', '0' + NumDigits/10, '0' + NumDigits%10, 'l', 'l', 'x', 0};
const char shortFmt[] = {'0', 'x', '%', '0', '0' + NumDigits, 'l', 'l', 'x', 0};
char buf[sizeof(deUint64)*2 + 3];
deSprintf(buf, sizeof(buf), NumDigits > 9 ? longFmt : shortFmt, value);
return std::string(buf);
}
private:
deUint64 value;
};
template <size_t NumDigits>
std::ostream& operator<< (std::ostream& stream, tcu::Format::Hex<NumDigits> hex)
{
return hex.toStream(stream);
}
// Bitfield formatter.
class BitDesc
{
public:
deUint64 bit;
const char* name;
BitDesc (deUint64 bit_, const char* name_) : bit(bit_), name(name_) {}
};
#define TCU_BIT_DESC(BIT) tcu::Format::BitDesc(BIT, #BIT)
template <size_t BitfieldSize>
class Bitfield
{
public:
Bitfield (deUint64 value, const BitDesc* begin, const BitDesc* end)
: m_value (value)
, m_begin (begin)
, m_end (end)
{
}
std::ostream& toStream (std::ostream& stream)
{
deUint64 bitsLeft = m_value;
for (const BitDesc* curDesc = m_begin; curDesc != m_end; curDesc++)
{
if (curDesc->bit & bitsLeft)
{
if (bitsLeft != m_value)
stream << "|";
stream << curDesc->name;
bitsLeft ^= curDesc->bit;
}
}
if (bitsLeft != 0)
{
if (bitsLeft != m_value)
stream << "|";
stream << Hex<BitfieldSize/4>(bitsLeft);
}
return stream;
}
private:
deUint64 m_value;
const BitDesc* m_begin;
const BitDesc* m_end;
};
template <size_t BitfieldSize>
inline std::ostream& operator<< (std::ostream& stream, Bitfield<BitfieldSize> decoder)
{
return decoder.toStream(stream);
}
// Enum formatter.
// \todo [2012-10-30 pyry] Use template for GetName.
template <typename T, size_t NumBytes = sizeof(T)>
class Enum
{
public:
typedef const char* (*GetNameFunc) (T value);
Enum (GetNameFunc getName, T value)
: m_getName (getName)
, m_value (value)
{
}
std::ostream& toStream (std::ostream& stream) const
{
const char* name = m_getName(m_value);
if (name)
return stream << name;
else
return stream << Hex<NumBytes*2>((deUint64)m_value);
}
std::string toString (void) const
{
const char* name = m_getName(m_value);
if (name)
return std::string(name);
else
return Hex<NumBytes*2>((deUint64)m_value).toString();
}
private:
const GetNameFunc m_getName;
const T m_value;
};
template <typename T, size_t NumBytes>
inline std::ostream& operator<< (std::ostream& stream, const Enum<T, NumBytes>& fmt) { return fmt.toStream(stream); }
// Array formatters.
template <typename Iterator>
class Array
{
public:
Iterator begin;
Iterator end;
Array (const Iterator& begin_, const Iterator& end_) : begin(begin_), end(end_) {}
};
template <typename T>
class ArrayPointer
{
public:
const T* arr;
int size;
ArrayPointer (const T* arr_, int size_) : arr(arr_), size(size_) {}
};
template <typename Iterator>
std::ostream& operator<< (std::ostream& str, const Array<Iterator>& fmt)
{
str << "{ ";
for (Iterator cur = fmt.begin; cur != fmt.end; ++cur)
{
if (cur != fmt.begin)
str << ", ";
str << *cur;
}
str << " }";
return str;
}
template <typename T>
std::ostream& operator<< (std::ostream& str, const ArrayPointer<T>& fmt)
{
if (fmt.arr != DE_NULL)
return str << Array<const T*>(fmt.arr, fmt.arr+fmt.size);
else
return str << "(null)";
}
// Hex format iterator (useful for combining with ArrayFormatter).
// \todo [2012-10-30 pyry] Implement more generic format iterator.
template <typename T, typename Iterator = const T*>
class HexIterator
{
public:
HexIterator (Iterator iter) : m_iter(iter) {}
HexIterator<T, Iterator>& operator++ (void) { ++m_iter; return *this; }
HexIterator<T, Iterator> operator++ (int) { return HexIterator(m_iter++); }
bool operator== (const HexIterator<T, Iterator>& other) const { return m_iter == other.m_iter; }
bool operator!= (const HexIterator<T, Iterator>& other) const { return m_iter != other.m_iter; }
#if !defined(__INTELLISENSE__)
// Intellisense in VS2013 crashes when parsing this.
Hex<sizeof(T)*2> operator* (void) const { return Hex<sizeof(T)*2>(*m_iter); }
#endif
private:
Iterator m_iter;
};
} // Format
template <int Bits> inline deUint64 makeMask64 (void) { return (1ull<<Bits)-1; }
template <> inline deUint64 makeMask64<64> (void) { return ~0ull; }
template <typename T> inline deUint64 toUint64 (T value) { return (deUint64)value & makeMask64<sizeof(T)*8>(); }
/** Format value as hexadecimal number. */
template <size_t NumDigits, typename T>
inline Format::Hex<NumDigits> toHex (T value)
{
return Format::Hex<NumDigits>(toUint64(value));
}
/** Format value as hexadecimal number. */
template <typename T>
inline Format::Hex<sizeof(T)*2> toHex (T value)
{
return Format::Hex<sizeof(T)*2>(toUint64(value));
}
/** Decode and format bitfield. */
template <typename T, size_t Size>
inline Format::Bitfield<sizeof(T)*8> formatBitfield (T value, const Format::BitDesc (&desc)[Size])
{
return Format::Bitfield<sizeof(T)*8>((deUint64)value, &desc[0], &desc[Size]);
}
/** Format array contents. */
template <typename Iterator>
inline Format::Array<Iterator> formatArray (const Iterator& begin, const Iterator& end)
{
return Format::Array<Iterator>(begin, end);
}
/** Format array contents. */
template <typename T>
inline Format::ArrayPointer<T> formatArray (const T* arr, int size)
{
return Format::ArrayPointer<T>(arr, size);
}
/** Format array contents. */
template <typename T, int Size>
inline Format::ArrayPointer<T> formatArray (const T (&arr)[Size])
{
return Format::ArrayPointer<T>(arr, Size);
}
} // tcu
#endif // _TCUFORMATUTIL_HPP