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