OpenTTD Source 20250524-master-gc366e6a48e
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#include "../core/format.hpp"
20
22template <typename T> struct ArrayT;
23
25template <typename T, size_t N> struct ArrayT<T[N]> {
26 static const size_t length = N;
27 using Item = T;
28};
29
30
35template <typename E, typename T>
36inline typename ArrayT<T>::Item ItemAtT(E idx, const T &t, typename ArrayT<T>::Item t_unk)
37{
38 if (static_cast<size_t>(idx) >= ArrayT<T>::length) {
39 return t_unk;
40 }
41 return t[idx];
42}
43
49template <typename E, typename T>
50inline 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)
51{
52 if (static_cast<size_t>(idx) < ArrayT<T>::length) {
53 return t[idx];
54 }
55 if (idx == idx_inv) {
56 return t_inv;
57 }
58 return t_unk;
59}
60
67template <typename E, typename T>
68inline std::string ComposeNameT(E value, T &t, std::string_view t_unk, E val_inv, std::string_view name_inv)
69{
70 std::string out;
71 if (value == val_inv) {
72 out = name_inv;
73 } else if (value == 0) {
74 out = "<none>";
75 } else {
76 for (size_t i = 0; i < ArrayT<T>::length; i++) {
77 if ((value & (1 << i)) == 0) continue;
78 out += (!out.empty() ? "+" : "");
79 out += t[i];
80 value &= ~(E)(1 << i);
81 }
82 if (value != 0) {
83 out += (!out.empty() ? "+" : "");
84 out += t_unk;
85 }
86 }
87 return out;
88}
89
95template <typename E>
96inline std::string ComposeNameT(E value, std::span<const std::string_view> names, std::string_view unknown_name)
97{
98 std::string out;
99 if (value.base() == 0) {
100 out = "<none>";
101 } else {
102 for (size_t i = 0; i < std::size(names); ++i) {
103 if (!value.Test(static_cast<E::EnumType>(i))) continue;
104 out += (!out.empty() ? "+" : "");
105 out += names[i];
106 value.Reset(static_cast<E::EnumType>(i));
107 }
108 if (value.base() != 0) {
109 out += (!out.empty() ? "+" : "");
110 out += unknown_name;
111 }
112 }
113 return out;
114}
115
116std::string ValueStr(Trackdir td);
117std::string ValueStr(TrackdirBits td_bits);
118std::string ValueStr(DiagDirection dd);
119std::string ValueStr(SignalType t);
120
123
126 size_t m_type_id;
127 const void *m_ptr;
128
129 KnownStructKey(size_t type_id, const void *ptr)
130 : m_type_id(type_id)
131 , m_ptr(ptr)
132 {}
133
134 bool operator<(const KnownStructKey &other) const
135 {
136 if ((size_t)m_ptr < (size_t)other.m_ptr) return true;
137 if ((size_t)m_ptr > (size_t)other.m_ptr) return false;
138 if (m_type_id < other.m_type_id) return true;
139 return false;
140 }
141 };
142
143 typedef std::map<KnownStructKey, std::string> KNOWN_NAMES;
144
145 std::string m_out;
147 std::stack<std::string> m_cur_struct;
148 KNOWN_NAMES m_known_names;
149
150 DumpTarget()
151 : m_indent(0)
152 {}
153
154 static size_t &LastTypeId();
155 std::string GetCurrentStructName();
156 bool FindKnownName(size_t type_id, const void *ptr, std::string &name);
157
158 void WriteIndent();
159
161 void WriteValue(std::string_view name, const auto &value)
162 {
163 WriteIndent();
164 format_append(m_out, "{} = {}\n", name, value);
165 }
166
167 void WriteTile(std::string_view name, TileIndex t);
168
170 template <typename E> void WriteEnumT(std::string_view name, E e)
171 {
172 WriteValue(name, ValueStr(e));
173 }
174
175 void BeginStruct(size_t type_id, std::string_view name, const void *ptr);
176 void EndStruct();
177
179 template <typename S> void WriteStructT(std::string_view name, const S *s)
180 {
181 static const size_t type_id = ++LastTypeId();
182
183 if (s == nullptr) {
184 /* No need to dump nullptr struct. */
185 WriteValue(name, "<null>");
186 return;
187 }
188 std::string known_as;
189 if (FindKnownName(type_id, s, known_as)) {
190 /* We already know this one, no need to dump it. */
191 std::string known_as_str = std::string("known_as.") + known_as;
192 WriteValue(name, known_as_str);
193 } else {
194 /* Still unknown, dump it */
195 BeginStruct(type_id, name, s);
196 s->Dump(*this);
197 EndStruct();
198 }
199 }
200
202 template <typename S> void WriteStructT(std::string_view name, const std::deque<S> *s)
203 {
204 static const size_t type_id = ++LastTypeId();
205
206 if (s == nullptr) {
207 /* No need to dump nullptr struct. */
208 WriteValue(name, "<null>");
209 return;
210 }
211 std::string known_as;
212 if (FindKnownName(type_id, s, known_as)) {
213 /* We already know this one, no need to dump it. */
214 std::string known_as_str = std::string("known_as.") + known_as;
215 WriteValue(name, known_as_str);
216 } else {
217 /* Still unknown, dump it */
218 BeginStruct(type_id, name, s);
219 size_t num_items = s->size();
220 this->WriteValue("num_items", num_items);
221 for (size_t i = 0; i < num_items; i++) {
222 const auto &item = (*s)[i];
223 this->WriteStructT(fmt::format("item[{}]", i), &item);
224 }
225 EndStruct();
226 }
227 }
228};
229
230#endif /* DBG_HELPERS_H */
std::string ComposeNameT(E value, T &t, std::string_view t_unk, E val_inv, std::string_view name_inv)
Helper template function that returns compound bitfield name that is concatenation of names of each s...
Definition dbg_helpers.h:68
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:36
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:22
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
std::string m_out
the output string
void WriteTile(std::string_view name, TileIndex t)
Write name & TileIndex to the output.
std::stack< std::string > m_cur_struct
here we will track the current structure name
void BeginStruct(size_t type_id, std::string_view name, const void *ptr)
Open new structure (one level deeper than the current one) 'name = {<LF>'.
void WriteStructT(std::string_view name, const std::deque< S > *s)
Dump nested object (or only its name if this instance is already known).
std::string GetCurrentStructName()
Return structured name of the current class/structure.
void WriteStructT(std::string_view name, const S *s)
Dump nested object (or only its name if this instance is already known).
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 WriteEnumT(std::string_view name, E e)
Dump given enum value (as a number and as named value)
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 WriteValue(std::string_view name, const auto &value)
Write 'name = value' with indent and new-line.
Trackdir
Enumeration for tracks and directions.
Definition track_type.h:66
TrackdirBits
Allow incrementing of Trackdir variables.
Definition track_type.h:97