GKD.RoboCtrl
RoboMaster Linux 电控:异步 IO、设备驱动与机器人控制
载入中...
搜索中...
未找到
multiton.hpp
浏览该文件的文档.
1
17#pragma once
18
19#include <concepts>
20#include <initializer_list>
21#include <stdexcept>
22#include <string>
23#include <unordered_map>
24#include <memory>
25#include <mutex>
26#include <span>
27#include <format>
28#include <functional>
29#include <unordered_set>
30#include <utility>
31#include <vector>
32
33#include "utils/concepts.hpp"
34#include "utils/singleton.hpp"
35
36namespace roboctrl{
37
50namespace multiton{
55template <typename T>
56concept descable = requires (const T& t) {
57 { t.desc() } -> std::same_as<std::string>;
58};
59
65template<typename T>
66concept multiton_info = requires(T info){
67 typename T::key_type;
68 typename T::owner_type;
69 {info.key()} -> std::convertible_to<typename T::key_type>;
70};
71
75template<typename T>
77
86template<typename T>
87concept owner = requires(T owner){
88 typename T::info_type;
89 {T(std::declval<typename T::info_type>())};
90};
91
93template<multiton_info T>
94using key_type_t = typename T::key_type;
95
96
98template<multiton_info T>
99using owner_type_t = typename T::owner_type;
100
102namespace details{
103
104template <typename owner_type>
105struct multiton_impl final :
108
109 using key_type = typename owner_type::info_type::key_type;
110
111 static std::mutex mutex_;
112 static std::unordered_map<key_type, std::unique_ptr<owner_type>> instances;
113
114 using info_type = typename owner_type::info_type;
115
116 static auto init(const info_type& info) -> owner_type& {
117 std::lock_guard<std::mutex> lock{mutex_};
118
119 const auto key = info.key();
120 if (instances.contains(key)) {
121 throw std::runtime_error(std::format("duplicate multiton key {}", key));
122 }
123
124 auto instance = std::make_unique<owner_type>(info);
125 auto [it, inserted] = instances.emplace(key, std::move(instance));
126 if (!inserted) {
127 throw std::runtime_error(std::format("failed to register multiton key {}", key));
128 }
129 return *it->second;
130 }
131
132 static void init(std::initializer_list<info_type> infos) {
133 init(std::span{infos.begin(), infos.size()});
134 }
135
136 static void init(std::span<const info_type> infos) {
137 std::lock_guard<std::mutex> lock{mutex_};
138
139 std::unordered_set<key_type> pending_keys;
140 for (const auto& info : infos) {
141 const auto key = info.key();
142 if (instances.contains(key) || !pending_keys.emplace(key).second) {
143 throw std::runtime_error(std::format("duplicate multiton key {}", key));
144 }
145 }
146
147 std::vector<std::pair<key_type, std::unique_ptr<owner_type>>> pending;
148 pending.reserve(infos.size());
149 for (const auto& info : infos) {
150 pending.emplace_back(info.key(), std::make_unique<owner_type>(info));
151 }
152
153 for (auto& [key, instance] : pending) {
154 instances.emplace(std::move(key), std::move(instance));
155 }
156 }
157
158 [[nodiscard]]
159 static bool contains(const key_type& key){
160 std::lock_guard<std::mutex> lock{mutex_};
161 return instances.contains(key);
162 }
163
164 template<typename Fn>
165 static void for_each(Fn&& fn) {
166 std::lock_guard<std::mutex> lock{mutex_};
167 for (auto& [key, instance] : instances) {
168 std::invoke(fn, *instance);
169 }
170 }
171
172 [[nodiscard]]
173 static auto get(const key_type& key) -> owner_type& {
174 std::lock_guard<std::mutex> lock { mutex_ };
175 auto it = instances.find(key);
176 if (it != instances.end()) {
177 return *it->second;
178 }
179
180 throw std::runtime_error(std::format("uninitialized multiton {}",key)); //TODO:add detailed desc.
181 };
182};
183
184template<multiton_info info_type>
186
187template <typename owner_type>
189
190template <typename owner_type>
191std::unordered_map<
192 typename multiton_impl<owner_type>::key_type,
193 std::unique_ptr<owner_type>
194> multiton_impl<owner_type>::instances {};
195}
196
210template<owner owner_type>
211[[nodiscard]]
212inline auto get(const typename details::multiton_impl<owner_type>::key_type& key) -> owner_type&{
214}
215
228template<typename T>
229 requires(!owner<T> && utils::singleton<T>)
230inline auto get() -> T&{
231 return T::instance();
232}
233
251template<info info_type>
252inline auto init(const info_type& info) -> bool{
253 if constexpr (multiton_info<info_type>){
255 return true;
256 }
257 else return get<typename info_type::owner_type>().init(info);
258}
259
260template<info info_type>
261inline auto init(std::initializer_list<info_type> infos) -> bool{
262 if constexpr (multiton_info<info_type>) {
264 } else {
265 for (const auto& info : infos) {
266 if (!init(info)) {
267 return false;
268 }
269 }
270 }
271 return true;
272}
273
277template<multiton_info info_type>
278inline auto init(std::span<const info_type> infos) -> bool{
280 return true;
281}
282
290template<info... info_types>
291inline auto init(const info auto& info,const info_types&... infos) -> bool{
292 if(init(info))
293 return init(infos...);
294 return false;
295}
296
304template<multiton_info info_type>
305[[nodiscard]]
306inline auto get(const info_type& info) -> owner_type_t<info_type>&{
307 using owner_type = owner_type_t<info_type>;
308 auto key = info.key();
311
313}
314
322[[nodiscard]]
323inline auto desc(const descable auto& owner) -> std::string{
324 return owner.desc();
325}
326
327template<owner owner_type, typename Fn>
328void for_each_instance(Fn&& fn){
330}
331
332template<typename T>
333concept startable = requires(T& instance) {
334 { instance.start() } -> std::same_as<void>;
335};
336
337template<owner owner_type>
338 requires startable<owner_type>
339void start_all(){
340 for_each_instance<owner_type>([](owner_type& instance) {
341 instance.start();
342 });
343}
344
345template<typename T>
346concept connectable = requires(T& instance) {
347 { instance.connect() } -> std::same_as<void>;
348};
349
350template<owner owner_type>
352void connect_all(){
353 for_each_instance<owner_type>([](owner_type& instance) {
354 instance.connect();
355 });
356}
357
358}
359
360
361
362template<typename T>
364 static_assert(multiton::owner<T>, "T must be a multiton owner.");
365
366 using key_type = typename T::info_type::key_type;
367
368 key_type key;
369
370 explicit instance_ref(key_type key_) : key(std::move(key_)) {}
371
372 T& operator *() const {
373 return roboctrl::multiton::get<T>(key);
374 }
375
376 T* operator ->() const {
377 return &roboctrl::multiton::get<T>(key);
378 }
379};
380
381using namespace multiton;
382}
拥有描述信息的类。
Definition multiton.hpp:56
通用的info concept,主要用于统一单例和多例的info概念。这个concept的主要目的是让单例和多例都可以被roboctrl::get获取。
Definition multiton.hpp:76
多例类的info_type concept
Definition multiton.hpp:66
描述多例类的concept
Definition multiton.hpp:87
公共Concept与元类型工具。
auto get() -> T &
获取单例实例
Definition multiton.hpp:230
auto desc(const descable auto &owner) -> std::string
获取一个可描述对象的描述信息
Definition multiton.hpp:323
auto init(const info_type &info) -> bool
初始化多例实例或单例实例
Definition multiton.hpp:252
快速继承获得“不可移动”约束的基类。
Definition concepts.hpp:59
快速继承获得“不可复制”约束的基类。
Definition concepts.hpp:68