22#ifndef EASYNAV__TYPES__NAVSTATE_HPP_
23#define EASYNAV__TYPES__NAVSTATE_HPP_
26#include <unordered_map>
27#include <unordered_set>
49 char * p = abi::__cxa_demangle(name,
nullptr,
nullptr, &status);
50 std::string out = (status == 0 && p) ? p : name;
59inline std::string
stacktrace(std::size_t skip = 1, std::size_t max_frames = 64)
62 const int n = backtrace(buf,
static_cast<int>(std::min<std::size_t>(max_frames, 128)));
63 char ** syms = backtrace_symbols(buf, n);
64 std::ostringstream oss;
65 for (
int i =
static_cast<int>(skip); i < n; ++i) {
66 oss <<
"#" << (i -
static_cast<int>(skip)) <<
" " << syms[i] <<
"\n";
104 void set(
const std::string & key,
const T & value)
106 std::lock_guard<std::mutex> lock(state_mutex_);
107 auto it = values_.find(key);
109 if (it == values_.end()) {
110 values_[key] = std::make_shared<T>(value);
111 types_[key] =
typeid(T).hash_code();
112 type_names_[key] =
demangle(
typeid(T).name());
114 if (types_[key] !=
typeid(T).hash_code()) {
115 std::ostringstream oss;
116 oss <<
"Type mismatch in set(\"" << key <<
"\")\n"
117 <<
" stored type : " << type_names_[key] <<
"\n"
118 <<
" provided type: " <<
demangle(
typeid(T).name()) <<
"\n"
120 throw std::runtime_error(oss.str());
123 auto ptr = std::static_pointer_cast<T>(it->second);
138 void set(
const std::string & key,
const std::shared_ptr<T> value_ptr)
140 std::lock_guard<std::mutex> lock(state_mutex_);
141 auto it = values_.find(key);
143 if (it == values_.end()) {
144 values_[key] = std::shared_ptr<T>(value_ptr);
145 types_[key] =
typeid(T).hash_code();
146 type_names_[key] =
demangle(
typeid(T).name());
148 if (types_[key] !=
typeid(T).hash_code()) {
149 std::ostringstream oss;
150 oss <<
"Type mismatch in set(\"" << key <<
"\")\n"
151 <<
" stored type : " << type_names_[key] <<
"\n"
152 <<
" provided type: " <<
demangle(
typeid(T).name()) <<
"\n"
154 throw std::runtime_error(oss.str());
157 it->second = value_ptr;
169 void set_group(
const std::string & key,
const std::vector<std::string> & group_keys)
171 std::lock_guard<std::mutex> lock(group_mutex_);
172 groups_[key] = group_keys;
187 const T &
get(
const std::string & key)
const
189 std::lock_guard<std::mutex> lock(state_mutex_);
190 auto it = values_.find(key);
192 if (it == values_.end()) {
193 throw std::runtime_error(
"Key not found in get: " + key);
196 if (types_.at(key) !=
typeid(T).hash_code()) {
197 std::ostringstream oss;
198 oss <<
"Type mismatch in get(\"" << key <<
"\")\n"
199 <<
" stored type : " << type_names_.at(key) <<
"\n"
200 <<
" requested type: " <<
demangle(
typeid(T).name());
201 throw std::runtime_error(oss.str());
204 auto ptr = std::static_pointer_cast<T>(it->second);
217 const std::shared_ptr<T>
get_ptr(
const std::string & key)
const
219 std::lock_guard<std::mutex> lock(state_mutex_);
220 auto it = values_.find(key);
222 if (it == values_.end()) {
223 throw std::runtime_error(
"Key not found in get: " + key);
226 if (types_.at(key) !=
typeid(T).hash_code()) {
227 std::ostringstream oss;
228 oss <<
"Type mismatch in get_ptr(\"" << key <<
"\")\n"
229 <<
" stored type : " << type_names_.at(key) <<
"\n"
230 <<
" requested type: " <<
demangle(
typeid(T).name());
231 throw std::runtime_error(oss.str());
234 return std::static_pointer_cast<T>(it->second);
246 const std::vector<std::shared_ptr<T>>
get_group(
const std::string & group_key)
const
248 std::lock_guard<std::mutex> lock(group_mutex_);
249 auto group_it = groups_.find(group_key);
251 if (group_it == groups_.end()) {
252 throw std::runtime_error(
"Group key not found in get_group: " + group_key);
255 const auto group_keys = group_it->second;
257 std::vector<std::shared_ptr<T>> out;
258 out.reserve(group_keys.size());
260 for (
const auto & group_key : group_keys) {
263 }
catch (
const std::runtime_error & e) {
264 std::cerr <<
"Error retrieving key '" << group_key <<
"' from group '" << group_key <<
265 "': " << e.what() << std::endl;
283 std::lock_guard<std::mutex> lock(state_mutex_);
284 std::vector<std::shared_ptr<T>> out;
285 const size_t target_hash =
typeid(T).hash_code();
286 for (
const auto & kv : values_) {
287 if (types_.at(kv.first) == target_hash) {
288 out.push_back(std::static_pointer_cast<T>(kv.second));
305 std::vector<std::shared_ptr<T>>
get_to_vector(
const std::string & key)
const
307 std::vector<std::shared_ptr<T>> out;
308 std::lock_guard<std::mutex> lock(state_mutex_);
309 auto it = values_.find(key);
310 if (it == values_.end()) {
313 if (types_.at(key) !=
typeid(T).hash_code()) {
316 out.push_back(std::static_pointer_cast<T>(it->second));
333 std::unordered_set<std::string> grouped_keys;
335 std::lock_guard<std::mutex> glock(group_mutex_);
336 for (
const auto & g : groups_) {
337 for (
const auto & k : g.second) {
338 grouped_keys.insert(k);
344 std::lock_guard<std::mutex> slock(state_mutex_);
345 std::vector<std::shared_ptr<T>> out;
346 const size_t target_hash =
typeid(T).hash_code();
347 for (
const auto & kv : values_) {
348 if (types_.at(kv.first) == target_hash &&
349 grouped_keys.find(kv.first) == grouped_keys.end())
351 out.push_back(std::static_pointer_cast<T>(kv.second));
360 bool has(
const std::string & key)
const
362 return values_.find(key) != values_.end();
370 return groups_.find(key) != groups_.end();
377 using AnyPrinter = std::function<std::string(std::shared_ptr<void>)>;
386 auto wrapper = [printer](std::shared_ptr<void> base_ptr) -> std::string {
387 auto typed_ptr = std::static_pointer_cast<T>(base_ptr);
388 return printer(*typed_ptr);
390 type_printers_[
typeid(T).hash_code()] = wrapper;
400 std::stringstream ss;
401 for (
const auto & kv : values_) {
402 ss << kv.first <<
" = ";
403 auto ptr = kv.second;
405 auto type_it = types_.find(kv.first);
406 if (type_it != types_.end()) {
407 auto printer_it = type_printers_.find(type_it->second);
408 if (printer_it != type_printers_.end()) {
409 ss <<
"[" << ptr.get() <<
"] : " << printer_it->second(ptr);
411 ss <<
"[" << ptr.get() <<
"] : " << type_it->second <<
"]";
414 ss <<
"[" << ptr.get() <<
"] : unknown]";
429 int size = backtrace(array, 50);
430 char **strings = backtrace_symbols(array, size);
431 std::cerr <<
"\nStack trace:\n";
432 for (
int i = 0; i < size; ++i) {
433 std::cerr << strings[i] << std::endl;
435 std::cerr << std::endl;
451 [](
const std::vector<std::string> & v) {
452 std::ostringstream oss;
453 oss <<
" " << v.size() <<
" [";
454 for (std::size_t i = 0; i < v.size(); ++i) {
455 if (i > 0) {oss <<
", ";}
464 mutable std::mutex state_mutex_;
465 mutable std::mutex group_mutex_;
468 mutable std::unordered_map<std::string, std::shared_ptr<void>> values_;
471 mutable std::unordered_map<std::string, std::vector<std::string>> groups_;
474 mutable std::unordered_map<std::string, size_t> types_;
477 mutable std::unordered_map<std::string, std::string> type_names_;
480 static inline std::unordered_map<size_t, AnyPrinter> type_printers_;
std::vector< std::shared_ptr< T > > get_no_group() const
Retrieves all stored values of type T that are NOT a member of any group.
Definition NavState.hpp:330
void set_group(const std::string &key, const std::vector< std::string > &group_keys)
Sets a new group of values as a list of strings.
Definition NavState.hpp:169
const T & get(const std::string &key) const
Retrieves a const reference to the stored value of type T for key.
Definition NavState.hpp:187
std::vector< std::shared_ptr< T > > get_to_vector(const std::string &key) const
Wraps a single stored value of type T in a one-element vector.
Definition NavState.hpp:305
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:217
std::function< std::string(std::shared_ptr< void >)> AnyPrinter
Type alias for a generic printer functor used by debug_string().
Definition NavState.hpp:377
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:138
static void print_stacktrace()
Prints the current C++ stack trace to std::cerr.
Definition NavState.hpp:426
static void register_basic_printers()
Registers default printers for common scalar types.
Definition NavState.hpp:442
void set(const std::string &key, const T &value)
Stores a value of type T associated with key (by copy).
Definition NavState.hpp:104
bool has_group(const std::string &key) const
Checks whether key exists in the state.
Definition NavState.hpp:368
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:384
std::vector< std::shared_ptr< T > > get_by_type() const
Retrieves all stored values of type T, regardless of their key.
Definition NavState.hpp:281
NavState()
Constructs an empty NavState and registers basic type printers.
Definition NavState.hpp:86
virtual ~NavState()=default
Destructor.
bool has(const std::string &key) const
Checks whether key exists in the state.
Definition NavState.hpp:360
std::string debug_string() const
Generates a human-readable dump of all stored keys and values.
Definition NavState.hpp:398
const std::vector< std::shared_ptr< T > > get_group(const std::string &group_key) const
Retrieves a vector of values (pointers) from a group by the group key.
Definition NavState.hpp:246
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:59
std::string demangle(const char *name)
Demangles a C++ RTTI type name if possible.
Definition NavState.hpp:46