1#ifndef _TCUFORMATUTIL_HPP
2#define _TCUFORMATUTIL_HPP
3/*-------------------------------------------------------------------------
4 * drawElements Quality Program Tester Core
5 * ----------------------------------------
6 *
7 * Copyright 2014 The Android Open Source Project
8 *
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 *      http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 *
21 *//*!
22 * \file
23 * \brief String format utilities.
24 *//*--------------------------------------------------------------------*/
25
26#include "tcuDefs.hpp"
27#include "deString.h"
28
29#include <ostream>
30#include <string>
31
32namespace tcu
33{
34namespace Format
35{
36
37// Hexadecimal value formatter.
38template <int NumDigits>
39class Hex
40{
41public:
42	Hex (deUint64 value_) : value(value_) {}
43
44	std::ostream& toStream (std::ostream& stream) const
45	{
46		return stream << this->toString();
47	}
48
49	std::string toString (void) const
50	{
51		DE_STATIC_ASSERT(0 < NumDigits && NumDigits <= 16);
52
53		const char longFmt[]	= {'0', 'x', '%', '0', '0' + NumDigits/10, '0' + NumDigits%10, 'l', 'l', 'x', 0};
54		const char shortFmt[]	= {'0', 'x', '%', '0', '0' + NumDigits, 'l', 'l', 'x', 0};
55
56		char buf[sizeof(deUint64)*2 + 3];
57		deSprintf(buf, sizeof(buf), NumDigits > 9 ? longFmt : shortFmt, value);
58
59		return std::string(buf);
60	}
61
62private:
63	deUint64 value;
64};
65
66template <int NumDigits>
67std::ostream& operator<< (std::ostream& stream, tcu::Format::Hex<NumDigits> hex)
68{
69	return hex.toStream(stream);
70}
71
72// Bitfield formatter.
73
74class BitDesc
75{
76public:
77	deUint64	bit;
78	const char*	name;
79
80	BitDesc (deUint64 bit_, const char* name_) : bit(bit_), name(name_) {}
81};
82
83#define TCU_BIT_DESC(BIT) tcu::Format::BitDesc(BIT, #BIT)
84
85template <int BitfieldSize>
86class Bitfield
87{
88public:
89	Bitfield (deUint64 value, const BitDesc* begin, const BitDesc* end)
90		: m_value	(value)
91		, m_begin	(begin)
92		, m_end		(end)
93	{
94	}
95
96	std::ostream& toStream (std::ostream& stream)
97	{
98		deUint64 bitsLeft = m_value;
99		for (const BitDesc* curDesc = m_begin; curDesc != m_end; curDesc++)
100		{
101			if (curDesc->bit & bitsLeft)
102			{
103				if (bitsLeft != m_value)
104					stream << "|";
105				stream << curDesc->name;
106				bitsLeft ^= curDesc->bit;
107			}
108		}
109
110		if (bitsLeft != 0)
111		{
112			if (bitsLeft != m_value)
113				stream << "|";
114			stream << Hex<BitfieldSize/4>(bitsLeft);
115		}
116
117		return stream;
118	}
119
120private:
121	deUint64			m_value;
122	const BitDesc*		m_begin;
123	const BitDesc*		m_end;
124};
125
126template <int BitfieldSize>
127inline std::ostream& operator<< (std::ostream& stream, Bitfield<BitfieldSize> decoder)
128{
129	return decoder.toStream(stream);
130}
131
132// Enum formatter.
133// \todo [2012-10-30 pyry] Use template for GetName.
134
135class Enum
136{
137public:
138	typedef const char* (*GetNameFunc) (int value);
139
140	Enum (GetNameFunc getName, int value)
141		: m_getName	(getName)
142		, m_value	(value)
143	{
144	}
145
146	std::ostream& toStream (std::ostream& stream) const
147	{
148		const char* name = m_getName(m_value);
149		if (name)
150			return stream << name;
151		else
152			return stream << Hex<sizeof(int)*2>(m_value);
153	}
154
155	std::string toString (void) const
156	{
157		const char* name = m_getName(m_value);
158		if (name)
159			return std::string(name);
160		else
161			return Hex<sizeof(int)*2>(m_value).toString();
162	}
163
164private:
165	GetNameFunc		m_getName;
166	int				m_value;
167};
168
169inline std::ostream& operator<< (std::ostream& stream, Enum fmt) { return fmt.toStream(stream); }
170
171// Array formatters.
172
173template <typename Iterator>
174class Array
175{
176public:
177	Iterator	begin;
178	Iterator	end;
179
180	Array (const Iterator& begin_, const Iterator& end_) : begin(begin_), end(end_) {}
181};
182
183template <typename T>
184class ArrayPointer
185{
186public:
187	const T*	arr;
188	int			size;
189
190	ArrayPointer (const T* arr_, int size_) : arr(arr_), size(size_) {}
191};
192
193template <typename Iterator>
194std::ostream& operator<< (std::ostream& str, const Array<Iterator>& fmt)
195{
196	str << "{ ";
197	for (Iterator cur = fmt.begin; cur != fmt.end; ++cur)
198	{
199		if (cur != fmt.begin)
200			str << ", ";
201		str << *cur;
202	}
203	str << " }";
204	return str;
205}
206
207template <typename T>
208std::ostream& operator<< (std::ostream& str, const ArrayPointer<T>& fmt)
209{
210	if (fmt.arr != DE_NULL)
211		return str << Array<const T*>(fmt.arr, fmt.arr+fmt.size);
212	else
213		return str << "(null)";
214}
215
216// Hex format iterator (useful for combining with ArrayFormatter).
217// \todo [2012-10-30 pyry] Implement more generic format iterator.
218
219template <typename T, typename Iterator = const T*>
220class HexIterator
221{
222public:
223										HexIterator			(Iterator iter) : m_iter(iter) {}
224
225	HexIterator<T, Iterator>&			operator++			(void)	{ ++m_iter; return *this;		}
226	HexIterator<T, Iterator>			operator++			(int)	{ return HexIterator(m_iter++);	}
227
228	bool								operator==			(const HexIterator<T, Iterator>& other) const { return m_iter == other.m_iter; }
229	bool								operator!=			(const HexIterator<T, Iterator>& other) const { return m_iter != other.m_iter; }
230
231#if !defined(__INTELLISENSE__)
232	// Intellisense in VS2013 crashes when parsing this.
233	Hex<sizeof(T)*2>					operator*			(void) const { return Hex<sizeof(T)*2>(*m_iter);	}
234#endif
235
236private:
237	Iterator							m_iter;
238};
239
240} // Format
241
242template <int Bits>		inline deUint64 makeMask64			(void)				{ return (1ull<<Bits)-1;								}
243template <>				inline deUint64 makeMask64<64>		(void)				{ return ~0ull;											}
244template <typename T>	inline deUint64	toUint64			(T value)			{ return (deUint64)value & makeMask64<sizeof(T)*8>();	}
245
246/** Format value as hexadecimal number. */
247template <int NumDigits, typename T>
248inline Format::Hex<NumDigits> toHex (T value)
249{
250	return Format::Hex<NumDigits>(toUint64(value));
251}
252
253/** Format value as hexadecimal number. */
254template <typename T>
255inline Format::Hex<sizeof(T)*2> toHex (T value)
256{
257	return Format::Hex<sizeof(T)*2>(toUint64(value));
258}
259
260/** Decode and format bitfield. */
261template <typename T, size_t Size>
262inline Format::Bitfield<sizeof(T)*8> formatBitfield (T value, const Format::BitDesc (&desc)[Size])
263{
264	return Format::Bitfield<sizeof(T)*8>((deUint64)value, &desc[0], &desc[Size]);
265}
266
267/** Format array contents. */
268template <typename Iterator>
269inline Format::Array<Iterator> formatArray (const Iterator& begin, const Iterator& end)
270{
271	return Format::Array<Iterator>(begin, end);
272}
273
274/** Format array contents. */
275template <typename T>
276inline Format::ArrayPointer<T> formatArray (const T* arr, int size)
277{
278	return Format::ArrayPointer<T>(arr, size);
279}
280
281} // tcu
282
283#endif // _TCUFORMATUTIL_HPP
284