Mercury Currency Engine
base_channel.hpp
Go to the documentation of this file.
1 //SPDX-License-Identifier: Apache-2.0
2 //Author: Blayne Dennis
7 #ifndef __MERCURY_COROUTINE_ENGINE_BASE_CHANNEL__
8 #define __MERCURY_COROUTINE_ENGINE_BASE_CHANNEL__
9 
10 #include <typeinfo>
11 #include <iterator>
12 #include <exception>
13 #include <memory>
14 
15 // Code in this header is shared by all Channels
16 
17 namespace mce {
18 
22 enum result
23 {
24  // ensure closed is convertable to `false`, allowing while(try_...()) operation loops
25  closed = 0,
27  failure
28 };
29 
47 template <typename T>
48 struct base_channel
49 {
51  typedef T value_type;
52 
54  base_channel(const base_channel<T>* rhs_bc) : bc(rhs_bc) { }
55 
56  virtual ~base_channel(){}
57 
58  /*
59  derived channels should implement the following constructors:
60 
61  derived_channel();
62  derived_channel(const derived_channel<T>& rhs);
63  derived_channel(derived_channel<T>&& rhs);
64  */
65 
66  // operations
67 
69  virtual void construct() const = 0;
70 
72  virtual void* context() const = 0;
73 
75  virtual const std::type_info& type_info() const = 0;
76 
78  virtual void close() const = 0;
79 
81  virtual bool closed() const = 0;
82 
84  virtual bool send(const T& s) const = 0;
85 
87  virtual bool send(T&& s) const = 0;
88 
90  virtual bool recv(T& r) const = 0;
91 
93  virtual result try_send(const T& s) const = 0;
94 
96  virtual result try_send(T&& s) const = 0;
97 
99  virtual result try_recv(T& r) const = 0;
100 
101  /*
102  Derived channels should implement the following operators. They should
103  typically be implemented by directly calling the above pure virtual
104  operations:
105 
106  bool operator=(const derived_channel<T>& rhs) const;
107  bool operator=(derived_channel<T>&& rhs) const;
108  bool operator==(const derived_channel<T>& rhs) const;
109  bool operator==(derived_channel<T>&& rhs) const;
110  bool operator!=(const derived_channel<T>& rhs) const;
111  bool operator!=(derived_channel<T>&& rhs) const;
112  const derived_channel<T>& operator<<(const T& s) const;
113  const derived_channel<T>& operator<<(T&& s) const;
114  T& operator>>(T& r) const;
115  */
116 
117  //TODO: There is potentially room to turn this into a virtual interface for
118  //large and small channel iterators. IE, rather than use a T for all values,
119  //can use a uptr<T> for large values and T for trivially small
120  //(wordsize?) values and convert this class to a pure virtual interface to
121  //the large & small iterator classes.
122  class iterator : public std::input_iterator_tag
123  {
124  private:
125  struct iterator_context
126  {
127  iterator_context() : bc(NULL), good(false) { }
128  iterator_context(const base_channel<T>* rhs_bc) : bc(rhs_bc), good(true) { }
129 
130  inline T& dereference() const { return t; }
131  inline T* arrow() const { return &t; }
132 
133  inline bool increment() const
134  {
135  if(good && !bc->recv(t)) { good=false; }
136  return good;
137  }
138 
139  const base_channel<T>* bc;
140  mutable T t;
141  mutable bool good;
142  };
143 
144  inline void make(const base_channel<T>* bc)
145  {
146  ctx = std::make_shared<iterator::iterator_context>(bc);
147  }
148 
149  mutable std::shared_ptr<iterator_context> ctx;
150  friend struct base_channel<T>;
151 
152  public:
153  typedef T value_type; //< iterator templated value type
154 
155  iterator(){ } //< default constructor
156  iterator(const iterator& rhs) : ctx(rhs.ctx){ } //< copy constructor
157  iterator(iterator&& rhs) noexcept : ctx(std::move(rhs.ctx)){ } //< move constructor
158 
160  inline const iterator& operator=(const iterator& rhs) const
161  {
162  ctx = rhs.ctx;
163  return *this;
164  }
165 
167  inline const iterator& operator=(iterator&& rhs) const
168  {
169  ctx = std::move(rhs.ctx);
170  return *this;
171  }
172 
174  inline bool operator==(const iterator& rhs) const
175  {
176  return ctx == rhs.ctx;
177  }
178 
180  inline bool operator==(iterator&& rhs) const { return *this == rhs; }
181 
183  inline bool operator!=(const iterator& rhs) const { return !(*this == rhs); }
184 
186  inline bool operator!=(iterator&& rhs) const { return *this != rhs; }
187 
189  inline T& operator*() const { return ctx->dereference(); }
190 
192  inline T* operator->() const { return ctx->arrow(); }
193 
195  inline const iterator& operator++() const
196  {
197  if(!ctx->increment()){ ctx.reset(); }
198  return *this;
199  }
200 
202  inline const iterator operator++(int) const
203  {
204  if(!ctx->increment()){ ctx.reset(); }
205  return *this;
206  }
207  };
208 
210  inline iterator begin() const
211  {
212  iterator it;
213  it.make(bc);
214  ++it; // get an initial value
215  return it;
216  }
217 
219  inline iterator end() const { return iterator(); }
220 
221 private:
222  const base_channel<T>* bc; // used for iterator
223 };
224 
225 // CRTP (Curiously Recurring Template Pattern) for implementing shared channel
226 // operator overloads
227 template <typename T, typename CHANNEL>
229 {
231  channel_operators(CHANNEL* rhs_ch) : ch(rhs_ch) { }
232 
233  virtual ~channel_operators(){}
234 
235  virtual void assign(const CHANNEL& rhs) const = 0;
236  virtual void assign(CHANNEL&& rhs) const = 0;
237 
238  template <typename... As>
239  static CHANNEL make(As&&... as)
240  {
241  CHANNEL ch;
242  ch.construct(std::forward<As>(as)...);
243  return ch;
244  }
245 
247  inline explicit operator bool() const
248  {
249  return ch->context() ? true : false;
250  }
251 
252  // operators
254  inline const CHANNEL& operator=(const CHANNEL& rhs) const
255  {
256  ch->assign(rhs);
257  return *ch;
258  }
259 
261  inline const CHANNEL& operator=(CHANNEL&& rhs) const
262  {
263  ch->assign(std::move(rhs));
264  return *ch;
265  }
266 
268  inline bool operator==(const CHANNEL& rhs) const
269  {
270  return ch->context() == rhs.context();
271  }
272 
274  inline bool operator==(CHANNEL&& rhs) const
275  {
276  return *ch == rhs;
277  }
278 
280  inline bool operator!=(const CHANNEL& rhs) const
281  {
282  return !(*ch == rhs);
283  }
284 
286  inline bool operator!=(CHANNEL&& rhs) const
287  {
288  return *ch != rhs;
289  }
290 
291  inline bool operator<(const CHANNEL& rhs) const
292  {
293  return ch->context() < rhs.context();
294  }
295 
296  inline bool operator<(CHANNEL&& rhs) const
297  {
298  return ch->context() < rhs.context();
299  }
300 
301  inline bool operator<=(const CHANNEL& rhs) const
302  {
303  return ch->context() < rhs.context();
304  }
305 
306  inline bool operator<=(CHANNEL&& rhs) const
307  {
308  return ch->context() <= rhs.context();
309  }
310 
311  inline bool operator>(const CHANNEL& rhs) const
312  {
313  return ch->context() > rhs.context();
314  }
315 
316  inline bool operator>(CHANNEL&& rhs) const
317  {
318  return ch->context() > rhs.context();
319  }
320 
321  inline bool operator>=(const CHANNEL& rhs) const
322  {
323  return ch->context() > rhs.context();
324  }
325 
326  inline bool operator>=(CHANNEL&& rhs) const
327  {
328  return ch->context() >= rhs.context();
329  }
330 
331 private:
332  CHANNEL* ch;
333 };
334 
335 }
336 
337 #endif
result
enum for channel operation results
Definition: base_channel.hpp:23
@ success
channel is closed, operation failed
Definition: base_channel.hpp:26
@ failure
blocking/nonblocking operation succeeded
Definition: base_channel.hpp:27
Definition: base_channel.hpp:123
T & operator*() const
retrieve reference to cached value T
Definition: base_channel.hpp:189
const iterator & operator=(iterator &&rhs) const
rvalue iterator assignment
Definition: base_channel.hpp:167
bool operator==(iterator &&rhs) const
rvalue iterator comparison
Definition: base_channel.hpp:180
const iterator & operator=(const iterator &rhs) const
lvalue iterator assignment
Definition: base_channel.hpp:160
bool operator!=(const iterator &rhs) const
lvalue iterator not comparison
Definition: base_channel.hpp:183
bool operator!=(iterator &&rhs) const
rvalue iterator not comparison
Definition: base_channel.hpp:186
T * operator->() const
retrieve pointer to cached value T
Definition: base_channel.hpp:192
const iterator & operator++() const
retrieve data from the channel iterator
Definition: base_channel.hpp:195
const iterator operator++(int) const
retrieve data from the channel iterator
Definition: base_channel.hpp:202
bool operator==(const iterator &rhs) const
lvalue iterator comparison
Definition: base_channel.hpp:174
Definition: base_channel.hpp:49
virtual bool recv(T &r) const =0
retrieve data from channel
iterator end() const
default iterator == end()
Definition: base_channel.hpp:219
virtual bool send(const T &s) const =0
send a copy of data through channel
virtual void * context() const =0
retrieve internal context pointer
base_channel(const base_channel< T > *rhs_bc)
iterator context constructor
Definition: base_channel.hpp:54
virtual bool send(T &&s) const =0
move data through channel
virtual bool closed() const =0
report if channel is closed
virtual result try_send(T &&s) const =0
attempt to move data through channel
virtual result try_recv(T &r) const =0
attempt to retrieve data from channel
virtual void construct() const =0
construct channel context
iterator begin() const
iterator to the current beginning of the channel
Definition: base_channel.hpp:210
virtual const std::type_info & type_info() const =0
retrieve type_info
virtual result try_send(const T &s) const =0
attempt to send a copy of data through channel
virtual void close() const =0
close channel
T value_type
template type for channel
Definition: base_channel.hpp:51
Definition: base_channel.hpp:229
bool operator==(const CHANNEL &rhs) const
lvalue channel context comparison
Definition: base_channel.hpp:268
const CHANNEL & operator=(const CHANNEL &rhs) const
lvalue assign channel context
Definition: base_channel.hpp:254
const CHANNEL & operator=(CHANNEL &&rhs) const
rvalue assign channel context
Definition: base_channel.hpp:261
bool operator==(CHANNEL &&rhs) const
rvalue channel context comparison
Definition: base_channel.hpp:274
bool operator!=(const CHANNEL &rhs) const
lvalue channel context not comparison
Definition: base_channel.hpp:280
channel_operators(CHANNEL *rhs_ch)
context constructor
Definition: base_channel.hpp:231
bool operator!=(CHANNEL &&rhs) const
rvalue channel context not comparison
Definition: base_channel.hpp:286