OpenTTD Source 20260218-master-g2123fca5ea
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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
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
29template <typename E>
30inline std::string_view ItemAt(E idx, std::span<const std::string_view> names, std::string_view unknown_name)
31{
32 if (static_cast<size_t>(idx) >= std::size(names)) {
33 return unknown_name;
34 }
35 return names[idx];
36}
37
49template <typename E>
50inline std::string_view ItemAt(E idx, std::span<const std::string_view> names, std::string_view unknown_name, E invalid_index, std::string_view invalid_name)
51{
52 if (idx == invalid_index) {
53 return invalid_name;
54 }
55 return ItemAt(idx, names, unknown_name);
56}
57
70template <typename E>
71inline std::string ComposeName(E value, std::span<const std::string_view> names, std::string_view unknown_name, E invalid_index, std::string_view invalid_name)
72{
73 std::string out;
74 if (value == invalid_index) {
75 out = invalid_name;
76 } else if (value == 0) {
77 out = "<none>";
78 } else {
79 for (size_t i = 0; i < std::size(names); i++) {
80 if ((value & (1 << i)) == 0) continue;
81 out += (!out.empty() ? "+" : "");
82 out += names[i];
83 value &= ~(E)(1 << i);
84 }
85 if (value != 0) {
86 out += (!out.empty() ? "+" : "");
87 out += unknown_name;
88 }
89 }
90 return out;
91}
92
102template <typename E>
103inline std::string ComposeName(E value, std::span<const std::string_view> names, std::string_view unknown_name)
104{
105 std::string out;
106 if (value.base() == 0) {
107 out = "<none>";
108 } else {
109 for (size_t i = 0; i < std::size(names); ++i) {
110 if (!value.Test(static_cast<E::EnumType>(i))) continue;
111 out += (!out.empty() ? "+" : "");
112 out += names[i];
113 value.Reset(static_cast<E::EnumType>(i));
114 }
115 if (value.base() != 0) {
116 out += (!out.empty() ? "+" : "");
117 out += unknown_name;
118 }
119 }
120 return out;
121}
122
123std::string ValueStr(Trackdir td);
124std::string ValueStr(TrackdirBits td_bits);
125std::string ValueStr(DiagDirection dd);
126std::string ValueStr(SignalType t);
127
132 size_t type_id;
133 const void *ptr;
134
140 KnownStructKey(size_t type_id, const void *ptr) : type_id(type_id), ptr(ptr) {}
141
142 bool operator<(const KnownStructKey &other) const
143 {
144 if (reinterpret_cast<size_t>(this->ptr) < reinterpret_cast<size_t>(other.ptr)) return true;
145 if (reinterpret_cast<size_t>(this->ptr) > reinterpret_cast<size_t>(other.ptr)) return false;
146 if (this->type_id < other.type_id) return true;
147 return false;
148 }
149 };
150
152 using KnownNamesMap = std::map<KnownStructKey, std::string>;
153
154 std::string output_buffer;
155 int indent = 0;
156 std::stack<std::string> cur_struct;
158
159 static size_t NewTypeId();
160 std::string GetCurrentStructName();
161 std::optional<std::string> FindKnownAsName(size_t type_id, const void *ptr);
162
163 void WriteIndent();
164
170 void WriteValue(std::string_view name, const auto &value)
171 {
172 this->WriteIndent();
173 format_append(this->output_buffer, "{} = {}\n", name, value);
174 }
175
176 void WriteTile(std::string_view name, TileIndex t);
177
183 template <typename E> void WriteEnumT(std::string_view name, E e)
184 {
185 this->WriteValue(name, ValueStr(e));
186 }
187
188 void BeginStruct(size_t type_id, std::string_view name, const void *ptr);
189 void EndStruct();
190
196 template <typename S> void WriteStructT(std::string_view name, const S *s)
197 {
198 static const size_t type_id = this->NewTypeId();
199
200 if (s == nullptr) {
201 /* No need to dump nullptr struct. */
202 this->WriteValue(name, "<null>");
203 return;
204 }
205 if (auto known_as = this->FindKnownAsName(type_id, s); known_as.has_value()) {
206 /* We already know this one, no need to dump it. */
207 this->WriteValue(name, *known_as);
208 } else {
209 /* Still unknown, dump it */
210 this->BeginStruct(type_id, name, s);
211 s->Dump(*this);
212 this->EndStruct();
213 }
214 }
215
221 template <typename S> void WriteStructT(std::string_view name, const std::deque<S> *s)
222 {
223 static const size_t type_id = this->NewTypeId();
224
225 if (s == nullptr) {
226 /* No need to dump nullptr struct. */
227 this->WriteValue(name, "<null>");
228 return;
229 }
230 if (auto known_as = this->FindKnownAsName(type_id, s); known_as.has_value()) {
231 /* We already know this one, no need to dump it. */
232 this->WriteValue(name, *known_as);
233 } else {
234 /* Still unknown, dump it */
235 this->BeginStruct(type_id, name, s);
236 size_t num_items = s->size();
237 this->WriteValue("num_items", num_items);
238 for (size_t i = 0; i < num_items; i++) {
239 const auto &item = (*s)[i];
240 this->WriteStructT(fmt::format("item[{}]", i), &item);
241 }
242 this->EndStruct();
243 }
244 }
245};
246
247#endif /* DBG_HELPERS_H */
std::string ComposeName(E value, std::span< const std::string_view > names, std::string_view unknown_name, E invalid_index, std::string_view invalid_name)
Helper template function that returns compound bitfield name that is concatenation of names of each s...
Definition dbg_helpers.h:71
std::string ValueStr(Trackdir td)
Return name of given Trackdir.
std::string_view ItemAt(E idx, std::span< const std::string_view > names, std::string_view unknown_name)
Helper template function that returns item of array at given index or unknown_name when index is out ...
Definition dbg_helpers.h:30
Different types to 'show' directions.
DiagDirection
Enumeration for diagonal directions.
String formatting functions and helpers.
Types and classes related to signals.
SignalType
Type of signal, i.e.
Definition signal_type.h:23
Used as a key into map of known object instances.
const void * ptr
Pointer to the structure.
KnownStructKey(size_t type_id, const void *ptr)
Create the key.
size_t type_id
Unique identifier of the type.
Class that represents the dump-into-string target.
std::map< KnownStructKey, std::string > KnownNamesMap
Mapping of the KnownStructKey to the name for that structure.
KnownNamesMap known_names
Map of known object instances and their structured names.
std::stack< std::string > cur_struct
Tracker of the current structure name.
void WriteTile(std::string_view name, TileIndex t)
Write name & TileIndex to the output.
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>'.
int indent
Current indent/nesting level.
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.
std::string output_buffer
The output string.
void WriteStructT(std::string_view name, const S *s)
Dump nested object (or only its name if this instance is already known).
std::optional< std::string > FindKnownAsName(size_t type_id, const void *ptr)
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.
void EndStruct()
Close structure '}<LF>'.
void WriteValue(std::string_view name, const auto &value)
Write 'name = value' with indent and new-line.
static size_t NewTypeId()
Create a new type_id.
Types related to tiles.
StrongType::Typedef< uint32_t, struct TileIndexTag, StrongType::Compare, StrongType::Integer, StrongType::Compatible< int32_t >, StrongType::Compatible< int64_t > > TileIndex
The index/ID of a Tile.
Definition tile_type.h:92
All types related to tracks.
Trackdir
Enumeration for tracks and directions.
Definition track_type.h:66
TrackdirBits
Allow incrementing of Trackdir variables.
Definition track_type.h:97