Easy Navigation
Loading...
Searching...
No Matches
NavState.hpp
Go to the documentation of this file.
1// Copyright 2025 Intelligent Robotics Lab
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
21
22#ifndef EASYNAV__TYPES__NAVSTATE_HPP_
23#define EASYNAV__TYPES__NAVSTATE_HPP_
24
25#include <string>
26#include <unordered_map>
27#include <memory>
28#include <mutex>
29#include <stdexcept>
30#include <sstream>
31#include <type_traits>
32#include <iostream>
33#include <functional>
34#include <execinfo.h>
35#include <typeinfo>
36#include <cxxabi.h>
37#include <execinfo.h>
38
39namespace easynav
40{
41
45inline std::string demangle(const char * name)
46{
47 int status = 0;
48 char * p = abi::__cxa_demangle(name, nullptr, nullptr, &status);
49 std::string out = (status == 0 && p) ? p : name;
50 std::free(p);
51 return out;
52}
53
58inline std::string stacktrace(std::size_t skip = 1, std::size_t max_frames = 64)
59{
60 void * buf[128];
61 const int n = backtrace(buf, static_cast<int>(std::min<std::size_t>(max_frames, 128)));
62 char ** syms = backtrace_symbols(buf, n);
63 std::ostringstream oss;
64 for (int i = static_cast<int>(skip); i < n; ++i) {
65 oss << "#" << (i - static_cast<int>(skip)) << " " << syms[i] << "\n";
66 }
67 std::free(syms);
68 return oss.str();
69}
70
82{
83public:
89
91 virtual ~NavState() = default;
92
102 template<typename T>
103 void set(const std::string & key, const T & value)
104 {
105 std::lock_guard<std::mutex> lock(mutex_);
106 auto it = values_.find(key);
107
108 if (it == values_.end()) {
109 values_[key] = std::make_shared<T>(value);
110 types_[key] = typeid(T).hash_code();
111 } else {
112 if (types_[key] != typeid(T).hash_code()) {
113 std::ostringstream oss;
114 oss << "Type mismatch in set(\"" << key << "\")\n"
115 << " expected(hash): " << types_[key] << "\n"
116 << " provided : " << demangle(typeid(T).name()) << "\n"
117 << "Backtrace:\n" << stacktrace(1);
118 throw std::runtime_error(oss.str());
119 }
120
121 auto ptr = std::static_pointer_cast<T>(it->second);
122 *ptr = value;
123 }
124 }
125
135 template<typename T>
136 void set(const std::string & key, const std::shared_ptr<T> value_ptr)
137 {
138 std::lock_guard<std::mutex> lock(mutex_);
139 auto it = values_.find(key);
140
141 if (it == values_.end()) {
142 values_[key] = std::shared_ptr<T>(value_ptr);
143 types_[key] = typeid(T).hash_code();
144 } else {
145 if (types_[key] != typeid(T).hash_code()) {
146 std::ostringstream oss;
147 oss << "Type mismatch in set(\"" << key << "\")\n"
148 << " expected(hash): " << types_[key] << "\n"
149 << " provided : " << demangle(typeid(T).name()) << "\n"
150 << "Backtrace:\n" << stacktrace(1);
151 throw std::runtime_error(oss.str());
152 }
153
154 auto ptr = std::static_pointer_cast<T>(it->second);
155 ptr = std::shared_ptr<T>(value_ptr);
156 }
157 }
158
167 template<typename T>
168 const T & get(const std::string & key) const
169 {
170 std::lock_guard<std::mutex> lock(mutex_);
171 auto it = values_.find(key);
172
173 if (it == values_.end()) {
174 throw std::runtime_error("Key not found in get: " + key);
175 }
176
177 if (types_.at(key) != typeid(T).hash_code()) {
178 throw std::runtime_error("Type mismatch in get for key: " + key);
179 }
180
181 auto ptr = std::static_pointer_cast<T>(it->second);
182 return *ptr;
183 }
184
193 template<typename T>
194 const std::shared_ptr<T> get_ptr(const std::string & key) const
195 {
196 std::lock_guard<std::mutex> lock(mutex_);
197 auto it = values_.find(key);
198
199 if (it == values_.end()) {
200 throw std::runtime_error("Key not found in get: " + key);
201 }
202
203 if (types_.at(key) != typeid(T).hash_code()) {
204 throw std::runtime_error("Type mismatch in get for key: " + key);
205 }
206
207 return std::static_pointer_cast<T>(it->second);
208 }
209
213 bool has(const std::string & key) const
214 {
215 return values_.find(key) != values_.end();
216 }
217
222 using AnyPrinter = std::function<std::string(std::shared_ptr<void>)>;
223
228 template<typename T>
229 static void register_printer(std::function<std::string(const T &)> printer)
230 {
231 auto wrapper = [printer](std::shared_ptr<void> base_ptr) -> std::string {
232 auto typed_ptr = std::static_pointer_cast<T>(base_ptr);
233 return printer(*typed_ptr);
234 };
235 type_printers_[typeid(T).hash_code()] = wrapper;
236 }
237
243 std::string debug_string() const
244 {
245 std::stringstream ss;
246 for (const auto & kv : values_) {
247 ss << kv.first << " = ";
248 auto ptr = kv.second;
249 if (ptr) {
250 auto type_it = types_.find(kv.first);
251 if (type_it != types_.end()) {
252 auto printer_it = type_printers_.find(type_it->second);
253 if (printer_it != type_printers_.end()) {
254 ss << "[" << ptr.get() << "] : " << printer_it->second(ptr);
255 } else {
256 ss << "[" << ptr.get() << "] : " << type_it->second << "]";
257 }
258 } else {
259 ss << "[" << ptr.get() << "] : unknown]";
260 }
261 } else {
262 ss << "[null]";
263 }
264 ss << std::endl;
265 }
266 return ss.str();
267 }
268
271 static void print_stacktrace()
272 {
273 void *array[50];
274 int size = backtrace(array, 50);
275 char **strings = backtrace_symbols(array, size);
276 std::cerr << "\nStack trace:\n";
277 for (int i = 0; i < size; ++i) {
278 std::cerr << strings[i] << std::endl;
279 }
280 std::cerr << std::endl;
281 free(strings);
282 }
283
288 {
289 register_printer<int>([](const int & v) {return std::to_string(v);});
290 register_printer<float>([](const float & v) {return std::to_string(v);});
291 register_printer<double>([](const double & v) {return std::to_string(v);});
292 register_printer<std::string>([](const std::string & v) {return v;});
293 register_printer<bool>([](const bool & v) {return v ? "true" : "false";});
294 register_printer<char>([](const char & v) {return std::string(1, v);});
295 }
296
297private:
298 mutable std::mutex mutex_;
299
301 mutable std::unordered_map<std::string, std::shared_ptr<void>> values_;
302
304 mutable std::unordered_map<std::string, size_t> types_;
305
307 static inline std::unordered_map<size_t, AnyPrinter> type_printers_;
308};
309
310} // namespace easynav
311
312#endif // EASYNAV__TYPES__NAVSTATE_HPP_
const T & get(const std::string &key) const
Retrieves a const reference to the stored value of type T for key.
Definition NavState.hpp:168
const std::shared_ptr< T > get_ptr(const std::string &key) const
Retrieves the shared_ptr to the stored value of type T for key.
Definition NavState.hpp:194
std::function< std::string(std::shared_ptr< void >)> AnyPrinter
Type alias for a generic printer functor used by debug_string().
Definition NavState.hpp:222
void set(const std::string &key, const std::shared_ptr< T > value_ptr)
Stores a value of type T associated with key (by shared pointer).
Definition NavState.hpp:136
static void print_stacktrace()
Prints the current C++ stack trace to std::cerr.
Definition NavState.hpp:271
static void register_basic_printers()
Registers default printers for common scalar types.
Definition NavState.hpp:287
void set(const std::string &key, const T &value)
Stores a value of type T associated with key (by copy).
Definition NavState.hpp:103
static void register_printer(std::function< std::string(const T &)> printer)
Registers a pretty-printer for type T used by debug_string().
Definition NavState.hpp:229
NavState()
Constructs an empty NavState and registers basic type printers.
Definition NavState.hpp:85
virtual ~NavState()=default
Destructor.
bool has(const std::string &key) const
Checks whether key exists in the state.
Definition NavState.hpp:213
std::string debug_string() const
Generates a human-readable dump of all stored keys and values.
Definition NavState.hpp:243
Definition CircularBuffer.hpp:23
std::string stacktrace(std::size_t skip=1, std::size_t max_frames=64)
Captures a C/C++ stack trace as a string.
Definition NavState.hpp:58
std::string demangle(const char *name)
Demangles a C++ RTTI type name if possible.
Definition NavState.hpp:45