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