| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- #ifndef DEPTHGUIDE_OBJECT_MANAGER_H
- #define DEPTHGUIDE_OBJECT_MANAGER_H
- #include "core/meta_helper.hpp"
- #include "core/utility.hpp"
- #include <boost/asio/post.hpp>
- #include <boost/asio/io_context.hpp>
- #include <boost/signals2.hpp>
- #include <cassert>
- #include <cstdint>
- #include <functional>
- #include <memory>
- #include <optional>
- #include <typeindex>
- #include <typeinfo>
- 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<typename T>
- void save(name_type obj_name, T &&val) {
- using RT = std::remove_cvref_t<T>;
- if (auto ctx = switch_ctx(); ctx != nullptr) [[unlikely]] {
- using boost::asio::post;
- static_assert(std::is_copy_constructible_v<RT>);
- // TODO: figure out why some works are not called when the main thread is blocked.
- 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<RT>);
- 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>);
- *(RT *) pl_ptr = val;
- merge_meta<RT>(obj_name, pl_ptr);
- notify_signal(obj_name);
- }
- template<typename T>
- 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<T>);
- 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<void(name_type)>;
- 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);
- template<typename T>
- void pin_meta(name_type obj_name, meta_key_type key, T &&val) {
- auto meta = query_meta_obj(obj_name);
- meta->set_meta_any(key, std::forward<T>(val));
- }
- void unpin_meta(name_type obj_name, meta_key_type key) {
- auto meta = query_meta_obj(obj_name);
- meta->remove_meta(key);
- }
- void merge_meta(name_type obj_name, meta_base *meta) {
- if (meta == nullptr) return;
- meta->merge_from(query_meta_obj(obj_name));
- }
- private:
- using del_func_type = void (*)(void *);
- struct obj_info {
- std::type_index type = typeid(void);
- void *pl_ptr = nullptr;
- meta_obj *meta = nullptr;
- obj_sig_type *sig = nullptr;
- timestamp_type last_save_ts = 0;
- };
- std::optional<obj_info> 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;
- assert(info_o->type == obj_type);
- // 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();
- meta_obj *query_meta_obj(name_type obj_name) {
- auto info_o = query_info(obj_name);
- assert(info_o.has_value());
- return info_o->meta;
- }
- template<typename RT>
- void merge_meta(name_type obj_name, void *pl_ptr) {}
- template<PointerContainsMeta RT>
- void merge_meta(name_type obj_name, void *pl_ptr) {
- auto rt_ptr = *(RT *) pl_ptr;
- if (rt_ptr == nullptr) return;
- auto meta_ptr =
- dynamic_cast<meta_base *>(&(*rt_ptr));
- assert(meta_ptr != nullptr);
- auto meta_obj = query_meta_obj(obj_name);
- meta_ptr->merge_from(meta_obj);
- }
- struct impl;
- std::unique_ptr<impl> pimpl;
- };
- using obj_name_type = object_manager::name_type;
- using obj_conn_type = boost::signals2::connection;
- using io_ctx_type = object_manager::io_context;
- static constexpr obj_name_type invalid_obj_name = -1;
- extern object_manager *main_ob;
- #define OBJ_QUERY(type, name) \
- main_ob->query<type>(name)
- #define OBJ_TYPE(name) \
- main_ob->query_type(name)
- #define OBJ_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)
- #define OBJ_PIN_META(name, key, val) \
- main_ob->pin_meta(name, key, val)
- #define OBJ_MERGE_META(name, meta) \
- main_ob->merge_meta(name, meta)
- #endif //DEPTHGUIDE_OBJECT_MANAGER_H
|