object_manager.h 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. #ifndef DEPTHGUIDE_OBJECT_MANAGER_H
  2. #define DEPTHGUIDE_OBJECT_MANAGER_H
  3. #include "core/meta_helper.hpp"
  4. #include "core/utility.hpp"
  5. #include <boost/asio/post.hpp>
  6. #include <boost/asio/io_context.hpp>
  7. #include <boost/signals2.hpp>
  8. #include <cassert>
  9. #include <cstdint>
  10. #include <functional>
  11. #include <memory>
  12. #include <optional>
  13. #include <typeindex>
  14. #include <typeinfo>
  15. class object_manager {
  16. public:
  17. using name_type = uint16_t;
  18. using io_context = boost::asio::io_context;
  19. struct create_config {
  20. io_context *ctx = nullptr;
  21. };
  22. explicit object_manager(create_config conf);
  23. ~object_manager();
  24. // thread-safe
  25. template<typename T>
  26. void save(name_type obj_name, T &&val) {
  27. using RT = std::remove_cvref_t<T>;
  28. if (auto ctx = switch_ctx(); ctx != nullptr) [[unlikely]] {
  29. using boost::asio::post;
  30. static_assert(std::is_copy_constructible_v<RT>);
  31. // TODO: figure out why some works are not called when the main thread is blocked.
  32. post(*ctx, [=, rt_val = RT(val), this] { save(obj_name, rt_val); });
  33. return;
  34. }
  35. auto pl_ptr = query_placeholder(obj_name, typeid(RT));
  36. if (pl_ptr == nullptr) [[unlikely]] {
  37. static_assert(std::is_default_constructible_v<RT>);
  38. create_placeholder(obj_name, typeid(RT),
  39. new RT{}, [](void *ptr) { delete (RT *) ptr; });
  40. pl_ptr = query_placeholder(obj_name, typeid(RT));
  41. }
  42. assert(pl_ptr != nullptr);
  43. static_assert(std::is_copy_assignable_v<RT>);
  44. *(RT *) pl_ptr = val;
  45. merge_meta<RT>(obj_name, pl_ptr);
  46. notify_signal(obj_name);
  47. }
  48. template<typename T>
  49. T query(name_type obj_name) {
  50. auto pl_ptr = query_placeholder(obj_name, typeid(T));
  51. assert(pl_ptr != nullptr);
  52. static_assert(std::is_copy_constructible_v<T>);
  53. return *(T *) pl_ptr;
  54. }
  55. std::type_index query_type(name_type obj_name) {
  56. auto info_o = query_info(obj_name);
  57. assert(info_o.has_value());
  58. return info_o->type;
  59. }
  60. timestamp_type query_save_ts(name_type obj_name) {
  61. auto info_o = query_info(obj_name);
  62. assert(info_o.has_value());
  63. return info_o->last_save_ts;
  64. }
  65. using obj_sig_type = boost::signals2::signal<void(name_type)>;
  66. obj_sig_type *query_signal(name_type obj_name) {
  67. auto info_o = query_info(obj_name);
  68. assert(info_o.has_value());
  69. return info_o->sig;
  70. }
  71. struct obj_stats {
  72. float save_interval = 0.0f; // in ms
  73. float save_frequency = 0.0f; // in Hz
  74. };
  75. obj_stats query_obj_stats(name_type obj_name);
  76. template<typename T>
  77. void pin_meta(name_type obj_name, meta_key_type key, T &&val) {
  78. auto meta = query_meta_obj(obj_name);
  79. meta->set_meta_any(key, std::forward<T>(val));
  80. }
  81. void unpin_meta(name_type obj_name, meta_key_type key) {
  82. auto meta = query_meta_obj(obj_name);
  83. meta->remove_meta(key);
  84. }
  85. void merge_meta(name_type obj_name, meta_base *meta) {
  86. if (meta == nullptr) return;
  87. meta->merge_from(query_meta_obj(obj_name));
  88. }
  89. private:
  90. using del_func_type = void (*)(void *);
  91. struct obj_info {
  92. std::type_index type = typeid(void);
  93. void *pl_ptr = nullptr;
  94. meta_obj *meta = nullptr;
  95. obj_sig_type *sig = nullptr;
  96. timestamp_type last_save_ts = 0;
  97. };
  98. std::optional<obj_info> query_info(name_type obj_name);
  99. void *query_placeholder(name_type obj_name, std::type_index obj_type) {
  100. auto info_o = query_info(obj_name);
  101. if (!info_o.has_value()) [[unlikely]] return nullptr;
  102. assert(info_o->type == obj_type);
  103. // if (info_o->type != obj_type) return nullptr;
  104. return info_o->pl_ptr;
  105. }
  106. void create_placeholder(name_type obj_name, std::type_index obj_type,
  107. void *ptr, del_func_type del_func);
  108. void notify_signal(name_type obj_name);
  109. // return target context or nullptr
  110. io_context *switch_ctx();
  111. meta_obj *query_meta_obj(name_type obj_name) {
  112. auto info_o = query_info(obj_name);
  113. assert(info_o.has_value());
  114. return info_o->meta;
  115. }
  116. template<typename RT>
  117. void merge_meta(name_type obj_name, void *pl_ptr) {}
  118. template<PointerContainsMeta RT>
  119. void merge_meta(name_type obj_name, void *pl_ptr) {
  120. auto rt_ptr = *(RT *) pl_ptr;
  121. if (rt_ptr == nullptr) return;
  122. auto meta_ptr =
  123. dynamic_cast<meta_base *>(&(*rt_ptr));
  124. assert(meta_ptr != nullptr);
  125. auto meta_obj = query_meta_obj(obj_name);
  126. meta_ptr->merge_from(meta_obj);
  127. }
  128. struct impl;
  129. std::unique_ptr<impl> pimpl;
  130. };
  131. using obj_name_type = object_manager::name_type;
  132. using obj_conn_type = boost::signals2::connection;
  133. using io_ctx_type = object_manager::io_context;
  134. static constexpr obj_name_type invalid_obj_name = -1;
  135. extern object_manager *main_ob;
  136. #define OBJ_QUERY(type, name) \
  137. main_ob->query<type>(name)
  138. #define OBJ_TYPE(name) \
  139. main_ob->query_type(name)
  140. #define OBJ_TS(name) \
  141. main_ob->query_save_ts(name)
  142. #define OBJ_STATS(name) \
  143. main_ob->query_obj_stats(name)
  144. #define OBJ_SAVE(name, val) \
  145. main_ob->save(name, val)
  146. #define OBJ_SIG(name) \
  147. main_ob->query_signal(name)
  148. #define OBJ_PIN_META(name, key, val) \
  149. main_ob->pin_meta(name, key, val)
  150. #define OBJ_MERGE_META(name, meta) \
  151. main_ob->merge_meta(name, meta)
  152. #endif //DEPTHGUIDE_OBJECT_MANAGER_H