OpenTTD Source 20250312-master-gcdcc6b491d
dbg_helpers.h
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
7
10#ifndef DBG_HELPERS_H
11#define DBG_HELPERS_H
12
13#include <stack>
14
15#include "../direction_type.h"
16#include "../signal_type.h"
17#include "../tile_type.h"
18#include "../track_type.h"
19
21template <typename T> struct ArrayT;
22
24template <typename T, size_t N> struct ArrayT<T[N]> {
25 static const size_t length = N;
26 using Item = T;
27};
28
29
34template <typename E, typename T>
35inline typename ArrayT<T>::Item ItemAtT(E idx, const T &t, typename ArrayT<T>::Item t_unk)
36{
37 if (static_cast<size_t>(idx) >= ArrayT<T>::length) {
38 return t_unk;
39 }
40 return t[idx];
41}
42
48template <typename E, typename T>
49inline typename ArrayT<T>::Item ItemAtT(E idx, const T &t, typename ArrayT<T>::Item t_unk, E idx_inv, typename ArrayT<T>::Item t_inv)
50{
51 if (static_cast<size_t>(idx) < ArrayT<T>::length) {
52 return t[idx];
53 }
54 if (idx == idx_inv) {
55 return t_inv;
56 }
57 return t_unk;
58}
59
66template <typename E, typename T>
67inline std::string ComposeNameT(E value, T &t, const char *t_unk, E val_inv, const char *name_inv)
68{
69 std::string out;
70 if (value == val_inv) {
71 out = name_inv;
72 } else if (value == 0) {
73 out = "<none>";
74 } else {
75 for (size_t i = 0; i < ArrayT<T>::length; i++) {
76 if ((value & (1 << i)) == 0) continue;
77 out += (!out.empty() ? "+" : "");
78 out += t[i];
79 value &= ~(E)(1 << i);
80 }
81 if (value != 0) {
82 out += (!out.empty() ? "+" : "");
83 out += t_unk;
84 }
85 }
86 return out;
87}
88
94template <typename E>
95inline std::string ComposeNameT(E value, std::span<const std::string_view> names, std::string_view unknown_name)
96{
97 std::string out;
98 if (value.base() == 0) {
99 out = "<none>";
100 } else {
101 for (size_t i = 0; i < std::size(names); ++i) {
102 if (!value.Test(static_cast<E::EnumType>(i))) continue;
103 out += (!out.empty() ? "+" : "");
104 out += names[i];
105 value.Reset(static_cast<E::EnumType>(i));
106 }
107 if (value.base() != 0) {
108 out += (!out.empty() ? "+" : "");
109 out += unknown_name;
110 }
111 }
112 return out;
113}
114
115std::string ValueStr(Trackdir td);
116std::string ValueStr(TrackdirBits td_bits);
117std::string ValueStr(DiagDirection dd);
118std::string ValueStr(SignalType t);
119
122
125 size_t m_type_id;
126 const void *m_ptr;
127
128 KnownStructKey(size_t type_id, const void *ptr)
129 : m_type_id(type_id)
130 , m_ptr(ptr)
131 {}
132
133 bool operator<(const KnownStructKey &other) const
134 {
135 if ((size_t)m_ptr < (size_t)other.m_ptr) return true;
136 if ((size_t)m_ptr > (size_t)other.m_ptr) return false;
137 if (m_type_id < other.m_type_id) return true;
138 return false;
139 }
140 };
141
142 typedef std::map<KnownStructKey, std::string> KNOWN_NAMES;
143
144 std::string m_out;
146 std::stack<std::string> m_cur_struct;
147 KNOWN_NAMES m_known_names;
148
149 DumpTarget()
150 : m_indent(0)
151 {}
152
153 static size_t &LastTypeId();
154 std::string GetCurrentStructName();
155 bool FindKnownName(size_t type_id, const void *ptr, std::string &name);
156
157 void WriteIndent();
158
159 void WriteValue(const std::string &name, int value);
160 void WriteValue(const std::string &name, const std::string &value_str);
161 void WriteTile(const std::string &name, TileIndex t);
162
164 template <typename E> void WriteEnumT(const std::string &name, E e)
165 {
166 WriteValue(name, ValueStr(e));
167 }
168
169 void BeginStruct(size_t type_id, const std::string &name, const void *ptr);
170 void EndStruct();
171
173 template <typename S> void WriteStructT(const std::string &name, const S *s)
174 {
175 static size_t type_id = ++LastTypeId();
176
177 if (s == nullptr) {
178 /* No need to dump nullptr struct. */
179 WriteValue(name, "<null>");
180 return;
181 }
182 std::string known_as;
183 if (FindKnownName(type_id, s, known_as)) {
184 /* We already know this one, no need to dump it. */
185 std::string known_as_str = std::string("known_as.") + known_as;
186 WriteValue(name, known_as_str);
187 } else {
188 /* Still unknown, dump it */
189 BeginStruct(type_id, name, s);
190 s->Dump(*this);
191 EndStruct();
192 }
193 }
194
196 template <typename S> void WriteStructT(const std::string &name, const std::deque<S> *s)
197 {
198 static size_t type_id = ++LastTypeId();
199
200 if (s == nullptr) {
201 /* No need to dump nullptr struct. */
202 WriteValue(name, "<null>");
203 return;
204 }
205 std::string known_as;
206 if (FindKnownName(type_id, s, known_as)) {
207 /* We already know this one, no need to dump it. */
208 std::string known_as_str = std::string("known_as.") + known_as;
209 WriteValue(name, known_as_str);
210 } else {
211 /* Still unknown, dump it */
212 BeginStruct(type_id, name, s);
213 size_t num_items = s->size();
214 this->WriteValue("num_items", std::to_string(num_items));
215 for (size_t i = 0; i < num_items; i++) {
216 const auto &item = (*s)[i];
217 this->WriteStructT(fmt::format("item[{}]", i), &item);
218 }
219 EndStruct();
220 }
221 }
222};
223
224#endif /* DBG_HELPERS_H */
std::string ValueStr(Trackdir td)
Return name of given Trackdir.
ArrayT< T >::Item ItemAtT(E idx, const T &t, typename ArrayT< T >::Item t_unk)
Helper template function that returns item of array at given index or t_unk when index is out of boun...
Definition dbg_helpers.h:35
std::string ComposeNameT(E value, T &t, const char *t_unk, E val_inv, const char *name_inv)
Helper template function that returns compound bitfield name that is concatenation of names of each s...
Definition dbg_helpers.h:67
DiagDirection
Enumeration for diagonal directions.
SignalType
Type of signal, i.e.
Definition signal_type.h:23
Helper template class that provides C array length and item type.
Definition dbg_helpers.h:21
Used as a key into map of known object instances.
Class that represents the dump-into-string target.
int m_indent
current indent/nesting level
void WriteEnumT(const std::string &name, E e)
Dump given enum value (as a number and as named value)
std::string m_out
the output string
void WriteValue(const std::string &name, int value)
Write 'name = value' with indent and new-line.
std::stack< std::string > m_cur_struct
here we will track the current structure name
void BeginStruct(size_t type_id, const std::string &name, const void *ptr)
Open new structure (one level deeper than the current one) 'name = {<LF>'.
std::string GetCurrentStructName()
Return structured name of the current class/structure.
KNOWN_NAMES m_known_names
map of known object instances and their structured names
bool FindKnownName(size_t type_id, const void *ptr, std::string &name)
Find the given instance in our anti-recursion repository.
void WriteTile(const std::string &name, TileIndex t)
Write name & TileIndex to the output.
void WriteIndent()
Write some leading spaces into the output.
static size_t & LastTypeId()
Keep track of the last assigned type_id.
void EndStruct()
Close structure '}<LF>'.
void WriteStructT(const std::string &name, const S *s)
Dump nested object (or only its name if this instance is already known).
void WriteStructT(const std::string &name, const std::deque< S > *s)
Dump nested object (or only its name if this instance is already known).
Trackdir
Enumeration for tracks and directions.
Definition track_type.h:67
TrackdirBits
Allow incrementing of Trackdir variables.
Definition track_type.h:98