object_manager.h 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. #ifndef DEPTHGUIDE_OBJECT_MANAGER_H
  2. #define DEPTHGUIDE_OBJECT_MANAGER_H
  3. #include "core/utility.hpp"
  4. #include <boost/asio/post.hpp>
  5. #include <boost/asio/io_context.hpp>
  6. #include <boost/signals2.hpp>
  7. #include <cassert>
  8. #include <cstdint>
  9. #include <functional>
  10. #include <memory>
  11. #include <optional>
  12. #include <typeindex>
  13. #include <typeinfo>
  14. class object_manager {
  15. public:
  16. using name_type = uint16_t;
  17. using io_context = boost::asio::io_context;
  18. struct create_config {
  19. io_context *ctx = nullptr;
  20. };
  21. explicit object_manager(create_config conf);
  22. ~object_manager();
  23. // thread-safe
  24. template<typename T>
  25. void save(name_type obj_name, T &&val) {
  26. using RT = std::remove_cvref_t<T>;
  27. if (auto ctx = switch_ctx(); ctx != nullptr) [[unlikely]] {
  28. using boost::asio::post;
  29. static_assert(std::is_copy_constructible_v<RT>);
  30. post(*ctx, [=, rt_val = RT(val), this] { save(obj_name, rt_val); });
  31. return;
  32. }
  33. auto pl_ptr = query_placeholder(obj_name, typeid(RT));
  34. if (pl_ptr == nullptr) [[unlikely]] {
  35. static_assert(std::is_default_constructible_v<RT>);
  36. create_placeholder(obj_name, typeid(RT),
  37. new RT{}, [](void *ptr) { delete (RT *) ptr; });
  38. pl_ptr = query_placeholder(obj_name, typeid(RT));
  39. }
  40. assert(pl_ptr != nullptr);
  41. static_assert(std::is_copy_assignable_v<RT>);
  42. *(RT *) pl_ptr = val;
  43. notify_signal(obj_name);
  44. }
  45. template<typename T>
  46. T query(name_type obj_name) {
  47. auto pl_ptr = query_placeholder(obj_name, typeid(T));
  48. assert(pl_ptr != nullptr);
  49. static_assert(std::is_copy_constructible_v<T>);
  50. return *(T *) pl_ptr;
  51. }
  52. std::type_index query_type(name_type obj_name) {
  53. auto info_o = query_info(obj_name);
  54. assert(info_o.has_value());
  55. return info_o->type;
  56. }
  57. timestamp_type query_save_ts(name_type obj_name) {
  58. auto info_o = query_info(obj_name);
  59. assert(info_o.has_value());
  60. return info_o->last_save_ts;
  61. }
  62. using obj_sig_type = boost::signals2::signal<void(name_type)>;
  63. obj_sig_type *query_signal(name_type obj_name) {
  64. auto info_o = query_info(obj_name);
  65. assert(info_o.has_value());
  66. return info_o->sig;
  67. }
  68. struct obj_stats {
  69. float save_interval = 0.0f; // in ms
  70. float save_frequency = 0.0f; // in Hz
  71. };
  72. obj_stats query_obj_stats(name_type obj_name);
  73. private:
  74. using del_func_type = void (*)(void *);
  75. struct obj_info {
  76. std::type_index type = typeid(void);
  77. void *pl_ptr = nullptr;
  78. obj_sig_type *sig = nullptr;
  79. timestamp_type last_save_ts = 0;
  80. };
  81. std::optional<obj_info> query_info(name_type obj_name);
  82. void *query_placeholder(name_type obj_name, std::type_index obj_type) {
  83. auto info_o = query_info(obj_name);
  84. if (!info_o.has_value()) [[unlikely]] return nullptr;
  85. if (info_o->type != obj_type) return nullptr;
  86. return info_o->pl_ptr;
  87. }
  88. void create_placeholder(name_type obj_name, std::type_index obj_type,
  89. void *ptr, del_func_type del_func);
  90. void notify_signal(name_type obj_name);
  91. // return target context or nullptr
  92. io_context *switch_ctx();
  93. struct impl;
  94. std::unique_ptr<impl> pimpl;
  95. };
  96. using obj_name_type = object_manager::name_type;
  97. static constexpr obj_name_type invalid_obj_name = -1;
  98. extern object_manager *main_ob;
  99. #define OBJ_QUERY(type, name) \
  100. main_ob->query<type>(name)
  101. #define OBJ_TYPE(name) \
  102. main_ob->query_type(name)
  103. #define OBJ_SAVE_TS(name) \
  104. main_ob->query_save_ts(name)
  105. #define OBJ_STATS(name) \
  106. main_ob->query_obj_stats(name)
  107. #define OBJ_SAVE(name, val) \
  108. main_ob->save(name, val)
  109. #define OBJ_SIG(name) \
  110. main_ob->query_signal(name)
  111. #endif //DEPTHGUIDE_OBJECT_MANAGER_H