hmbdc
simplify-high-performance-messaging-programming
TypeTagSet.hpp
1 #include "hmbdc/Copyright.hpp"
2 #pragma once
3 #include "hmbdc/app/Message.hpp"
4 #include "hmbdc/Exception.hpp"
5 #include <atomic>
6 #include <mutex>
7 #include <unordered_map>
8 
9 namespace hmbdc { namespace tips {
10 
11 namespace typetagset_detail {
12 template <typename T, MessageTupleC MessageTuple>
13 struct adder {
14  T& t;
15  void operator()(uint16_t mod, uint16_t res) {}
16 };
17 
18 template <typename T, MessageC Message, MessageC ...Messages>
19 struct adder<T, std::tuple<Message, Messages...>> {
20  T& t;
21  void operator()(uint16_t mod, uint16_t res) {
22  if constexpr (!Message::hasRange) {
23  if (Message::typeTag % mod == res) {
24  t.add(Message::typeTag);
25  }
26  } else {
27  for (uint16_t i = 0; i < Message::typeTagRange; ++i) {
28  auto tag = Message::typeTagStart + i;
29  if (tag % mod == res) {
30  t.add(tag);
31  }
32  }
33  }
34  adder<T, std::tuple<Messages...>>{t}(mod, res);
35  }
36 };
37 
38 // template <typename T, MessageTupleC MessageTuple>
39 // struct eraser {
40 // T& t;
41 // bool operator()() { return true; }
42 // };
43 
44 // template <typename T, MessageC Message, MessageC ...Messages>
45 // struct eraser<T, std::tuple<Message, Messages...>> {
46 // T& t;
47 // bool operator()() {
48 // if constexpr (!Message::hasRange) {
49 // return t.erase(Message::typeTag) != 0xff &&
50 // eraser<T, std::tuple<Messages...>>{t}();
51 // } else {
52 // return eraser<T, std::tuple<Messages...>>{t}();
53 // }
54 // }
55 // };
56 
57 template <MessageTupleC MessageTuple, typename CcNode, typename TypeTagSet>
58 struct subscribe_for {
59  void operator()(CcNode const&, TypeTagSet&, std::function<void(uint16_t)>
60  , uint16_t mod, uint16_t res){}
61 };
62 
63 template <MessageC Message, MessageC ...Messages, typename CcNode, typename TypeTagSet >
64 struct subscribe_for<std::tuple<Message, Messages...>, CcNode, TypeTagSet>{
65  void operator()(CcNode const& node, TypeTagSet& tts
66  , std::function<void(uint16_t)> afterAddTag, uint16_t mod, uint16_t res) {
67  if constexpr (Message::hasRange) {
68  node.addTypeTagRangeSubsFor((Message*)nullptr
69  , [&tts, mod, res, &afterAddTag](uint16_t offsetInRange) {
70  if (offsetInRange >= Message::typeTagRange) {
71  HMBDC_THROW(std::out_of_range, offsetInRange << " as offset is out of the range of "
72  << Message::typeTagStart << "_" << Message::typeTagRange);
73  }
74  auto tag = Message::typeTagStart + offsetInRange;
75  if (tag % mod == res) {
76  if (!tts.check(tag)) {
77  tts.add(tag);
78  afterAddTag(tag);
79  }
80  }
81  }
82  );
83  } else if constexpr (std::is_same<app::JustBytes, Message>::value) {
84  node.addJustBytesSubsFor(
85  [&tts, mod, res, &afterAddTag](uint16_t tag) {
86  if (tag % mod == res) {
87  if (!tts.check(tag)) {
88  tts.add(tag);
89  afterAddTag(tag);
90  }
91  }
92  });
93  } else if (Message::typeTag % mod == res) {
94  auto tag = Message::typeTag;
95  if (!tts.check(tag)) {
96  tts.add(tag);
97  afterAddTag(tag);
98  }
99  }
100  using next = subscribe_for<std::tuple<Messages...>, CcNode, TypeTagSet>;
101  next{}(node, tts, afterAddTag, mod, res);
102  }
103 };
104 
105 template <MessageTupleC MessageTuple, typename CcNode, typename TypeTagSet>
107  void operator()(CcNode const&, TypeTagSet&, uint16_t mod, uint16_t res){}
108 };
109 
110 template <MessageC Message, MessageC ...Messages, typename CcNode, typename TypeTagSet >
111 struct advertise_for<std::tuple<Message, Messages...>, CcNode, TypeTagSet>{
112  void operator()(CcNode const& node, TypeTagSet& tts, uint16_t mod, uint16_t res) {
113  if constexpr (Message::hasRange) {
114  node.addTypeTagRangePubsFor((Message*)nullptr
115  , [&tts, mod, res](uint16_t offsetInRange) {
116  if (offsetInRange >= Message::typeTagRange) {
117  HMBDC_THROW(std::out_of_range, offsetInRange << " as offset is out of the range of "
118  << Message::typeTagStart << "_" << Message::typeTagRange);
119  }
120  if ((Message::typeTagStart + offsetInRange) % mod == res) {
121  tts.add(Message::typeTagStart + offsetInRange);
122  }
123  }
124  );
125  } else if constexpr (std::is_same<app::JustBytes, Message>::value) {
126  node.addJustBytesPubsFor(
127  [&tts, mod, res](uint16_t tag) {
128  if (tag % mod == res) {
129  tts.add(tag);
130  }
131  });
132  } else if (Message::typeTag % mod == res) {
133  tts.add(Message::typeTag);
134  }
135  using next = advertise_for<std::tuple<Messages...>, CcNode, TypeTagSet>;
136  next{}(node, tts, mod, res);
137  }
138 };
139 } //typetagset_detail
140 
141 struct TypeTagSet {
142  using TagType = uint16_t;
143  enum {
144  capacity = 1u << (sizeof(TagType) * 8),
145  };
146 
147  template <MessageTupleC MessageTuple, typename CcNode>
148  void addSubsFor(CcNode const& node, uint16_t mod, uint16_t res
149  , std::function<void(uint16_t)> afterAddTag = [](uint16_t){}) {
151  adder(node, *this, afterAddTag, mod, res);
152  }
153 
154  template <MessageTupleC MessageTuple>
155  void addAll(uint16_t mod = 1, uint16_t res = 0) {
157  }
158 
159  uint8_t add(TagType tag) {
160  return ++subCounts_[tag];
161  }
162 
163  bool set(TagType tag) {
164  if (subCounts_[tag]) return false;
165  return (subCounts_[tag] = 1);
166  }
167 
168  bool unset(TagType tag) {
169  if (!subCounts_[tag]) return false;
170  subCounts_[tag] = 0;
171  return true;
172  }
173 
174  // template <MessageTupleC MessageTuple>
175  // bool erase() {
176  // return typetagset_detail::eraser<TypeTagSet, MessageTuple>{*this}();
177  // }
178 
179  uint8_t erase(TagType tag) {
180  return --subCounts_[tag];
181  }
182 
183  uint8_t check(TagType tag) const {
184  return subCounts_[tag];
185  }
186 
187  template <typename TagRecver>
188  void exportTo(TagRecver&& r) const {
189  for (uint32_t i = 0; i < capacity; i++) {
190  auto c = (uint8_t)subCounts_[i];
191  if (c) {
192  r((uint16_t)i, c);
193  }
194  }
195  }
196 
197  private:
198  std::atomic<TagType> subCounts_[capacity] = {0};
199 };
200 
201 struct TypeTagSetST {
202  using TagType = uint16_t;
203  enum {
204  capacity = 1u << (sizeof(TagType) * 8),
205  };
206 
207  template <MessageTupleC MessageTuple, typename CcNode>
208  void addSubsFor(CcNode const& node, uint16_t mod, uint16_t res) {
210  adder(node, *this, mod, res);
211  }
212 
213  template <MessageTupleC MessageTuple, typename CcNode>
214  void addPubsFor(CcNode const& node, uint16_t mod, uint16_t res) {
216  adder(node, *this, mod, res);
217  }
218 
219  template <MessageTupleC MessageTuple>
220  void addAll(uint16_t mod = 1, uint16_t res = 0) {
222  }
223 
224  uint8_t add(TagType tag) {
225  auto res = ++subCounts_[tag];
226  if (res == 0xffu) {
227  HMBDC_THROW(std::out_of_range, "too many subscriptions - abort");
228  }
229  return res;
230  }
231 
232  bool set(TagType tag) {
233  auto it = subCounts_.find(tag);
234  if (it == subCounts_.end()) return false;
235  return ++it->second;
236  }
237 
238  bool unset(TagType tag) {
239  auto it = subCounts_.find(tag);
240  if (it == subCounts_.end()) return false;
241  it->second = 0;
242  return true;
243  }
244 
245  // template <MessageTupleC MessageTuple>
246  // bool erase() {
247  // return typetagset_detail::eraser<TypeTagSetST, MessageTuple>{*this}();
248  // }
249 
250  // uint8_t erase(TagType tag) {
251  // return --subCounts_[tag];
252  // }
253 
254  uint8_t check(TagType tag) const {
255  auto it = subCounts_.find(tag);
256  if (it == subCounts_.end()) return false;
257  return it->second;
258  }
259 
260  template <typename TagRecver>
261  void exportTo(TagRecver&& r) const {
262  for (auto const& t : subCounts_) {
263  if (t.second) {
264  r(t.first, t.second);
265  }
266  }
267  }
268 
269  std::mutex lock;
270  private:
271  std::unordered_map<TagType, uint8_t> subCounts_;
272 };
273 }}
Definition: TypeTagSet.hpp:106
Definition: TypedString.hpp:84
Definition: TypeTagSet.hpp:13
Definition: TypeTagSet.hpp:141
Definition: TypeTagSet.hpp:201
Definition: Base.hpp:12