#ifndef DEPTHGUIDE_OBJECT_MANAGER_H #define DEPTHGUIDE_OBJECT_MANAGER_H #include "core/utility.hpp" #include #include #include #include #include #include #include #include #include #include class object_manager { public: using name_type = uint16_t; using io_context = boost::asio::io_context; struct create_config { io_context *ctx = nullptr; }; explicit object_manager(create_config conf); ~object_manager(); // thread-safe template void save(name_type obj_name, T &&val) { using RT = std::remove_cvref_t; if (auto ctx = switch_ctx(); ctx != nullptr) [[unlikely]] { using boost::asio::post; static_assert(std::is_copy_constructible_v); post(*ctx, [=, rt_val = RT(val), this] { save(obj_name, rt_val); }); return; } auto pl_ptr = query_placeholder(obj_name, typeid(RT)); if (pl_ptr == nullptr) [[unlikely]] { static_assert(std::is_default_constructible_v); create_placeholder(obj_name, typeid(RT), new RT{}, [](void *ptr) { delete (RT *) ptr; }); pl_ptr = query_placeholder(obj_name, typeid(RT)); } assert(pl_ptr != nullptr); static_assert(std::is_copy_assignable_v); *(RT *) pl_ptr = val; notify_signal(obj_name); } template T query(name_type obj_name) { auto pl_ptr = query_placeholder(obj_name, typeid(T)); assert(pl_ptr != nullptr); static_assert(std::is_copy_constructible_v); return *(T *) pl_ptr; } std::type_index query_type(name_type obj_name) { auto info_o = query_info(obj_name); assert(info_o.has_value()); return info_o->type; } timestamp_type query_save_ts(name_type obj_name) { auto info_o = query_info(obj_name); assert(info_o.has_value()); return info_o->last_save_ts; } using obj_sig_type = boost::signals2::signal; obj_sig_type *query_signal(name_type obj_name) { auto info_o = query_info(obj_name); assert(info_o.has_value()); return info_o->sig; } struct obj_stats { float save_interval = 0.0f; // in ms float save_frequency = 0.0f; // in Hz }; obj_stats query_obj_stats(name_type obj_name); private: using del_func_type = void (*)(void *); struct obj_info { std::type_index type = typeid(void); void *pl_ptr = nullptr; obj_sig_type *sig = nullptr; timestamp_type last_save_ts = 0; }; std::optional query_info(name_type obj_name); void *query_placeholder(name_type obj_name, std::type_index obj_type) { auto info_o = query_info(obj_name); if (!info_o.has_value()) [[unlikely]] return nullptr; if (info_o->type != obj_type) return nullptr; return info_o->pl_ptr; } void create_placeholder(name_type obj_name, std::type_index obj_type, void *ptr, del_func_type del_func); void notify_signal(name_type obj_name); // return target context or nullptr io_context *switch_ctx(); struct impl; std::unique_ptr pimpl; }; using obj_name_type = object_manager::name_type; static constexpr obj_name_type invalid_obj_name = -1; extern object_manager *main_ob; #define OBJ_QUERY(type, name) \ main_ob->query(name) #define OBJ_TYPE(name) \ main_ob->query_type(name) #define OBJ_SAVE_TS(name) \ main_ob->query_save_ts(name) #define OBJ_STATS(name) \ main_ob->query_obj_stats(name) #define OBJ_SAVE(name, val) \ main_ob->save(name, val) #define OBJ_SIG(name) \ main_ob->query_signal(name) #endif //DEPTHGUIDE_OBJECT_MANAGER_H