blob: 3912c7ffbd953e4e4f25dd2a1c4a9ab7c87ce219 [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>
#include <sstream>
#include <iomanip>
namespace tcu
{
namespace Format
{
// Hexadecimal value formatter.
template <size_t NumDigits>
class Hex
{
public:
Hex(uint64_t value_) : value(value_)
{
}
std::ostream &toStream(std::ostream &stream) const
{
DE_STATIC_ASSERT(0 < NumDigits && NumDigits <= 16);
return stream << "0x" << std::right << std::setfill('0') << std::setw(NumDigits) << std::hex << value;
}
std::string toString(void) const
{
std::stringstream stream;
toStream(stream);
return stream.str();
}
private:
uint64_t 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:
uint64_t bit;
const char *name;
BitDesc(uint64_t 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(uint64_t value, const BitDesc *begin, const BitDesc *end) : m_value(value), m_begin(begin), m_end(end)
{
}
std::ostream &toStream(std::ostream &stream)
{
uint64_t 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:
uint64_t 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>((uint64_t)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>((uint64_t)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;
};
} // namespace Format
template <int Bits>
inline uint64_t makeMask64(void)
{
return (1ull << Bits) - 1;
}
template <>
inline uint64_t makeMask64<64>(void)
{
return ~0ull;
}
template <typename T>
inline uint64_t toUint64(T value)
{
return (uint64_t)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>((uint64_t)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);
}
} // namespace tcu
#endif // _TCUFORMATUTIL_HPP