167 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			167 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* $Id$ */
 | 
						|
 | 
						|
/** @file dbg_helpers.h Functions to be used for debug printings. */
 | 
						|
 | 
						|
#ifndef DBG_HELPERS
 | 
						|
#define DBG_HELPERS
 | 
						|
 | 
						|
#include <new>
 | 
						|
#include <map>
 | 
						|
#include <stack>
 | 
						|
 | 
						|
#include "blob.hpp"
 | 
						|
#include "str.hpp"
 | 
						|
 | 
						|
/** Helper template class that provides C array length and item type */
 | 
						|
template <typename T> struct ArrayT;
 | 
						|
 | 
						|
/** Helper template class that provides C array length and item type */
 | 
						|
template <typename T, size_t N> struct ArrayT<T[N]> {
 | 
						|
	static const size_t length = N;
 | 
						|
	typedef T item_t;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
* Helper template function that returns item of array at given index
 | 
						|
* or t_unk when index is out of bounds.
 | 
						|
*/
 | 
						|
template <typename E, typename T>
 | 
						|
inline typename ArrayT<T>::item_t ItemAtT(E idx, T &t, typename ArrayT<T>::item_t t_unk)
 | 
						|
{
 | 
						|
	if ((size_t)idx >= ArrayT<T>::length) {
 | 
						|
		return t_unk;
 | 
						|
	}
 | 
						|
	return t[idx];
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
* Helper template function that returns item of array at given index
 | 
						|
* or t_inv when index == idx_inv
 | 
						|
* or t_unk when index is out of bounds.
 | 
						|
*/
 | 
						|
template <typename E, typename T>
 | 
						|
inline typename ArrayT<T>::item_t ItemAtT(E idx, T &t, typename ArrayT<T>::item_t t_unk, E idx_inv, typename ArrayT<T>::item_t t_inv)
 | 
						|
{
 | 
						|
	if ((size_t)idx < ArrayT<T>::length) {
 | 
						|
		return t[idx];
 | 
						|
	}
 | 
						|
	if (idx == idx_inv) {
 | 
						|
		return t_inv;
 | 
						|
	}
 | 
						|
	return t_unk;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
* Helper template function that returns compound bitfield name that is
 | 
						|
* concatenation of names of each set bit in the given value
 | 
						|
* or t_inv when index == idx_inv
 | 
						|
* or t_unk when index is out of bounds.
 | 
						|
*/
 | 
						|
template <typename E, typename T>
 | 
						|
inline CStrA ComposeNameT(E value, T &t, const char* t_unk, E val_inv, const char* name_inv)
 | 
						|
{
 | 
						|
	CStrA out;
 | 
						|
	if (value == val_inv) {
 | 
						|
		out = name_inv;
 | 
						|
	} else if (value == 0) {
 | 
						|
		out = "<none>";
 | 
						|
	} else {
 | 
						|
		for (size_t i = 0; i < ArrayT<T>::length; i++) {
 | 
						|
			if ((value & (1 << i)) == 0) continue;
 | 
						|
			out.AddFormat("%s%s", (out.Size() > 0 ? "+" : ""), t[i]);
 | 
						|
			value &= ~(E)(1 << i);
 | 
						|
		}
 | 
						|
		if (value != 0) out.AddFormat("%s%s", (out.Size() > 0 ? "+" : ""), t_unk);
 | 
						|
	}
 | 
						|
	return out.Transfer();
 | 
						|
}
 | 
						|
 | 
						|
CStrA ValueStr(Trackdir td);
 | 
						|
CStrA ValueStr(TrackdirBits td_bits);
 | 
						|
CStrA ValueStr(DiagDirection dd);
 | 
						|
CStrA ValueStr(SignalType t);
 | 
						|
 | 
						|
/** Class that represents the dump-into-string target. */
 | 
						|
struct DumpTarget {
 | 
						|
 | 
						|
	/** Used as a key into map of known object instances. */
 | 
						|
	struct KnownStructKey {
 | 
						|
		size_t      m_type_id;
 | 
						|
		const void *m_ptr;
 | 
						|
 | 
						|
		KnownStructKey(size_t type_id, const void *ptr)
 | 
						|
			: m_type_id(type_id)
 | 
						|
			, m_ptr(ptr)
 | 
						|
		{}
 | 
						|
 | 
						|
		KnownStructKey(const KnownStructKey &src)
 | 
						|
		{
 | 
						|
			m_type_id = src.m_type_id;
 | 
						|
			m_ptr = src.m_ptr;
 | 
						|
		}
 | 
						|
 | 
						|
		bool operator < (const KnownStructKey &other) const
 | 
						|
		{
 | 
						|
			if ((size_t)m_ptr < (size_t)other.m_ptr) return true;
 | 
						|
			if ((size_t)m_ptr > (size_t)other.m_ptr) return false;
 | 
						|
			if (m_type_id < other.m_type_id) return true;
 | 
						|
			return false;
 | 
						|
		}
 | 
						|
	};
 | 
						|
 | 
						|
	typedef std::map<KnownStructKey, CStrA> KNOWN_NAMES;
 | 
						|
 | 
						|
	CStrA              m_out;         ///< the output string
 | 
						|
	int                m_indent;      ///< current indent/nesting level
 | 
						|
	std::stack<CStrA>  m_cur_struct;  ///< here we will track the current structure name
 | 
						|
	KNOWN_NAMES        m_known_names; ///< map of known object instances and their structured names
 | 
						|
 | 
						|
	DumpTarget()
 | 
						|
		: m_indent(0)
 | 
						|
	{}
 | 
						|
 | 
						|
	static size_t& LastTypeId();
 | 
						|
	CStrA GetCurrentStructName();
 | 
						|
	bool FindKnownName(size_t type_id, const void* ptr, CStrA &name);
 | 
						|
 | 
						|
	void WriteIndent();
 | 
						|
 | 
						|
	void WriteLine(const char *format, ...);
 | 
						|
	void WriteValue(const char *name, const char *value_str);
 | 
						|
	void WriteTile(const char *name, TileIndex t);
 | 
						|
 | 
						|
	/** Dump given enum value (as a number and as named value) */
 | 
						|
	template <typename E> void WriteEnumT(const char *name, E e)
 | 
						|
	{
 | 
						|
		WriteValue(name, ValueStr(e).Data());
 | 
						|
	}
 | 
						|
 | 
						|
	void BeginStruct(size_t type_id, const char *name, const void *ptr);
 | 
						|
	void EndStruct();
 | 
						|
 | 
						|
	/** Dump nested object (or only its name if this instance is already known). */
 | 
						|
	template <typename S> void WriteStructT(const char *name, const S *s)
 | 
						|
	{
 | 
						|
		static size_t type_id = ++LastTypeId();
 | 
						|
 | 
						|
		if (s == NULL) {
 | 
						|
			/* No need to dump NULL struct. */
 | 
						|
			WriteLine("%s = <null>", name);
 | 
						|
			return;
 | 
						|
		}
 | 
						|
		CStrA known_as;
 | 
						|
		if (FindKnownName(type_id, s, known_as)) {
 | 
						|
			/* We already know this one, no need to dump it. */
 | 
						|
			WriteLine("%s = known_as.%s", name, known_as.Data());
 | 
						|
		} else {
 | 
						|
			/* Still unknown, dump it */
 | 
						|
			BeginStruct(type_id, name, s);
 | 
						|
			s->Dump(*this);
 | 
						|
			EndStruct();
 | 
						|
		}
 | 
						|
	}
 | 
						|
};
 | 
						|
 | 
						|
#endif /* DBG_HELPERS */
 |