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.set(tag)) {
77  afterAddTag(tag);
78  }
79  }
80  }
81  );
82  } else if constexpr (std::is_same<app::JustBytes, Message>::value) {
83  node.addJustBytesSubsFor(
84  [&tts, mod, res, &afterAddTag](uint16_t tag) {
85  if (tag % mod == res) {
86  if (tts.set(tag)) {
87  afterAddTag(tag);
88  }
89  }
90  });
91  } else if (Message::typeTag % mod == res) {
92  auto tag = Message::typeTag;
93  if (tts.set(tag)) {
94  afterAddTag(tag);
95  }
96  }
97  using next = subscribe_for<std::tuple<Messages...>, CcNode, TypeTagSet>;
98  next{}(node, tts, afterAddTag, mod, res);
99  }
100 };
101 
102 template <MessageTupleC MessageTuple, typename CcNode, typename TypeTagSet>
104  void operator()(CcNode const&, TypeTagSet&, uint16_t mod, uint16_t res){}
105 };
106 
107 template <MessageC Message, MessageC ...Messages, typename CcNode, typename TypeTagSet >
108 struct advertise_for<std::tuple<Message, Messages...>, CcNode, TypeTagSet>{
109  void operator()(CcNode const& node, TypeTagSet& tts, uint16_t mod, uint16_t res) {
110  if constexpr (Message::hasRange) {
111  node.addTypeTagRangePubsFor((Message*)nullptr
112  , [&tts, mod, res](uint16_t offsetInRange) {
113  if (offsetInRange >= Message::typeTagRange) {
114  HMBDC_THROW(std::out_of_range, offsetInRange << " as offset is out of the range of "
115  << Message::typeTagStart << "_" << Message::typeTagRange);
116  }
117  if ((Message::typeTagStart + offsetInRange) % mod == res) {
118  tts.set(Message::typeTagStart + offsetInRange);
119  }
120  }
121  );
122  } else if constexpr (std::is_same<app::JustBytes, Message>::value) {
123  node.addJustBytesPubsFor(
124  [&tts, mod, res](uint16_t tag) {
125  if (tag % mod == res) {
126  tts.set(tag);
127  }
128  });
129  } else if (Message::typeTag % mod == res) {
130  tts.set(Message::typeTag);
131  }
132  using next = advertise_for<std::tuple<Messages...>, CcNode, TypeTagSet>;
133  next{}(node, tts, mod, res);
134  }
135 };
136 } //typetagset_detail
137 
138 struct TypeTagSet {
139  using TagType = uint16_t;
140  enum {
141  capacity = 1u << (sizeof(TagType) * 8),
142  };
143 
144  template <MessageTupleC MessageTuple, typename CcNode>
145  void markSubsFor(CcNode const& node, uint16_t mod, uint16_t res
146  , std::function<void(uint16_t)> afterAddTag = [](uint16_t){}) {
148  marker(node, *this, afterAddTag, mod, res);
149  }
150 
151  template <MessageTupleC MessageTuple>
152  void addAll(uint16_t mod = 1, uint16_t res = 0) {
154  }
155 
156  uint8_t add(TagType tag) {
157  return ++subCounts_[tag];
158  }
159 
160  bool set(TagType tag) {
161  if (subCounts_[tag]) return false;
162  return (subCounts_[tag] = 1);
163  }
164 
165  bool unset(TagType tag) {
166  if (!subCounts_[tag]) return false;
167  subCounts_[tag] = 0;
168  return true;
169  }
170 
171  // template <MessageTupleC MessageTuple>
172  // bool erase() {
173  // return typetagset_detail::eraser<TypeTagSet, MessageTuple>{*this}();
174  // }
175 
176  uint8_t sub(TagType tag) {
177  return --subCounts_[tag];
178  }
179 
180  uint8_t check(TagType tag) const {
181  return subCounts_[tag];
182  }
183 
184  template <typename TagRecver>
185  void exportTo(TagRecver&& r) const {
186  for (uint32_t i = 0; i < capacity; i++) {
187  auto c = (uint8_t)subCounts_[i];
188  if (c) {
189  r((uint16_t)i, c);
190  }
191  }
192  }
193 
194  private:
195  std::atomic<TagType> subCounts_[capacity] = {0};
196 };
197 
198 struct TypeTagSetST {
199  using TagType = uint16_t;
200  enum {
201  capacity = 1u << (sizeof(TagType) * 8),
202  };
203 
204  template <MessageTupleC MessageTuple, typename CcNode>
205  void markSubsFor(CcNode const& node, uint16_t mod, uint16_t res) {
207  marker(node, *this, mod, res);
208  }
209 
210  template <MessageTupleC MessageTuple, typename CcNode>
211  void markPubsFor(CcNode const& node, uint16_t mod, uint16_t res) {
213  marker(node, *this, mod, res);
214  }
215 
216  template <MessageTupleC MessageTuple>
217  void addAll(uint16_t mod = 1, uint16_t res = 0) {
219  }
220 
221  uint8_t add(TagType tag) {
222  auto res = ++subCounts_[tag];
223  if (res == 0xffu) {
224  HMBDC_THROW(std::out_of_range, "too many subscriptions - abort");
225  }
226  return res;
227  }
228 
229  bool set(TagType tag) {
230  auto it = subCounts_.find(tag);
231  if (it != subCounts_.end() && it->second) return false;
232  return (subCounts_[tag] = 1);
233  }
234 
235  bool unset(TagType tag) {
236  return subCounts_.erase(tag) == 1;
237  }
238 
239  // template <MessageTupleC MessageTuple>
240  // bool erase() {
241  // return typetagset_detail::eraser<TypeTagSetST, MessageTuple>{*this}();
242  // }
243 
244  uint8_t sub(TagType tag) {
245  return --subCounts_[tag];
246  }
247 
248  uint8_t check(TagType tag) const {
249  auto it = subCounts_.find(tag);
250  if (it == subCounts_.end()) return false;
251  return it->second;
252  }
253 
254  template <typename TagRecver>
255  void exportTo(TagRecver&& r) const {
256  for (auto const& t : subCounts_) {
257  if (t.second) {
258  r(t.first, t.second);
259  }
260  }
261  }
262 
263  std::mutex lock;
264  private:
265  std::unordered_map<TagType, uint8_t> subCounts_;
266 };
267 }}
Definition: TypeTagSet.hpp:103
Definition: TypedString.hpp:84
Definition: TypeTagSet.hpp:13
Definition: TypeTagSet.hpp:138
Definition: TypeTagSet.hpp:198
Definition: Base.hpp:12