Lumiera  0.pre.03
»edit your freedom«
verb-visitor.hpp
Go to the documentation of this file.
1 /*
2  VERB-VISITOR.hpp - double dispatch to arbitrary functions on a common interface
3 
4  Copyright (C)
5  2019, Hermann Vosseler <Ichthyostega@web.de>
6 
7   **Lumiera** is free software; you can redistribute it and/or modify it
8   under the terms of the GNU General Public License as published by the
9   Free Software Foundation; either version 2 of the License, or (at your
10   option) any later version. See the file COPYING for further details.
11 
12 */
13 
14 
76 #ifndef LIB_VERB_VISITOR_H
77 #define LIB_VERB_VISITOR_H
78 
79 
82 #include "lib/verb-token.hpp"
83 #include "lib/symbol.hpp"
84 #include "lib/util.hpp"
85 
86 #include <utility>
87 #include <string>
88 #include <tuple>
89 
90 
91 namespace lib {
92 
93  namespace {
94  using JustSomeIrrelvantType = struct{};
95  const size_t VERB_TOKEN_SIZE = sizeof(VerbToken<JustSomeIrrelvantType, void(void)>);
96 
97  constexpr size_t
98  storageOverhead(size_t argStorage)
99  {
100  return argStorage + VERB_TOKEN_SIZE;
101  }
102  }
103 
104 
106  template<class REC, class RET>
107  struct VerbInvoker
108  : polyvalue::CloneValueSupport<polyvalue::EmptyBase> // mark and mix-in virtual copy construction support
109  {
110  virtual ~VerbInvoker() { }
111 
112  virtual RET applyTo (REC&) =0;
113  virtual Literal getID() const =0;
114 
115  bool operator== (VerbInvoker const& o) const { return getID() == o.getID(); }
116  bool operator!= (VerbInvoker const& o) const { return getID() != o.getID(); }
117  };
118 
119 
120  template<class REC, class SIG>
121  struct VerbHolder;
122 
127  template<class REC, class RET, typename... ARGS>
128  struct VerbHolder<REC, RET(ARGS...)>
129  : VerbInvoker<REC,RET>
130  , VerbToken<REC,RET(ARGS...)>
131  {
132  using Verb = VerbToken<REC,RET(ARGS...)>;
133  using Args = std::tuple<ARGS...>;
134 
136  using SequenceIterator = typename meta::BuildIdxIter<ARGS...>::Ascending;
137 
139  Args args_;
140 
141  template<typename...PARS>
142  VerbHolder (typename Verb::Handler handlerRef, Literal verbID, PARS&&... args)
143  : Verb{handlerRef, verbID}
144  , args_{std::forward<PARS> (args)...}
145  { }
146 
147  Literal
148  getID() const override
149  {
150  return Verb::getID();
151  }
152 
153  RET
154  applyTo (REC& receiver) override
155  {
156  return invokeVerb (receiver, SequenceIterator());
157  }
158 
159  private:
161  template<size_t...idx>
162  RET
164  {
165  return (receiver.*Verb::handler_) (std::get<idx> (args_)...);
166  }
167  };
168 
169 
170 
171  /******************************************************************************************/
186  template<class REC, class RET, size_t arg_storage>
187  class VerbPack
188  : public PolymorphicValue<VerbInvoker<REC,RET>, storageOverhead(arg_storage)>
189  {
190  using Dispatcher = VerbInvoker<REC,RET>; // the interface to talk to our payload
192 
193  template<typename FUN>
195  {
196  static_assert (!sizeof(FUN), "handler must be a function member pointer for the given receiver");
197  };
198  template<typename...ARGS>
199  struct HandlerTypeDetector<RET (REC::*) (ARGS...)>
200  {
201  using Verb = VerbToken<REC, RET(ARGS...)>;
202  using Payload = VerbHolder<REC, RET(ARGS...)>;
203  };
204 
205  template<typename FUN>
206  using PayloadType = typename HandlerTypeDetector<FUN>::Payload *;
207 
208 
209  public:
217  template<typename FUN, typename...ARGS>
218  VerbPack (FUN handler, Literal verbID, ARGS&&... args)
219  : PolyHolder(PayloadType<FUN>(), handler, verbID, std::forward<ARGS>(args)...)
220  { }
221 
227  RET
228  applyTo (REC& receiver)
229  {
230  return PolyHolder::getPayload().applyTo (receiver);
231  }
232 
233  operator string() const
234  {
235  return "VerbPack("
236  + string{util::unConst(this)->getPayload().getID()}
237  + ")";
238  }
239 
241  template<typename ARG>
242  ARG&
244  {
245  using EmbeddedPayload = lib::VerbHolder<REC, RET(ARG)>;
246  REQUIRE (INSTANCEOF (EmbeddedPayload, &this->getPayload()));
247  EmbeddedPayload& embedded = static_cast<EmbeddedPayload&>(this->getPayload());
248  return std::get<0> (embedded.args_);
249  }
250  };
251 
252 
253 
254 } // namespace lib
255 #endif /*LIB_VERB_VISITOR_H*/
Action token implemented by double dispatch to a handler function, as defined in the "receiver" inter...
Definition: verb-token.hpp:69
Hold a sequence of index numbers as template parameters.
build a sequence of index numbers based on a type sequence
Building block: actual storage for a "verb" (function pointer), together with the pre-bound invocatio...
ARG & accessArg()
unsafe downcast and access to an embedded payload argument value
Building block: the Interface to cause the invocation.
Building blocks for a simple DSL using double dispatch to a handler function.
A self-contained token to embody a specific yet abstracted operation, together with a concrete set of...
#define INSTANCEOF(CLASS, EXPR)
shortcut for subclass test, intended for assertions only.
Definition: util.hpp:514
inline string literal This is a marker type to indicate that
Definition: symbol.hpp:76
A variation for limited copy support.
STL namespace.
A mechanism to allow for opaque polymorphic value objects.
Implementation namespace for support and library code.
Marker types to indicate a literal string and a Symbol.
Template to build polymorphic value objects.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
RET invokeVerb(REC &receiver, meta::IndexSeq< idx... >)
RET applyTo(REC &receiver)
Core operation: invoke the operation for this "verb" with the pre-bound parameters.
typename meta::BuildIdxIter< ARGS... >::Ascending SequenceIterator
meta-sequence to pick argument values from the storage tuple
VerbPack(FUN handler, Literal verbID, ARGS &&... args)
setup a VerbPack for a given operation on the interface REC
Args args_
Storage for the argument tuple.
Metaprogramming with type sequences based on variadic template parameters.