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) Lumiera.org
5  2019, Hermann Vosseler <Ichthyostega@web.de>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 */
22 
23 
85 #ifndef LIB_VERB_VISITOR_H
86 #define LIB_VERB_VISITOR_H
87 
88 
91 #include "lib/verb-token.hpp"
92 #include "lib/symbol.hpp"
93 #include "lib/util.hpp"
94 
95 #include <utility>
96 #include <string>
97 #include <tuple>
98 
99 
100 namespace lib {
101 
102  namespace {
103  using JustSomeIrrelvantType = struct{};
104  const size_t VERB_TOKEN_SIZE = sizeof(VerbToken<JustSomeIrrelvantType, void(void)>);
105 
106  constexpr size_t
107  storageOverhead(size_t argStorage)
108  {
109  return argStorage + VERB_TOKEN_SIZE;
110  }
111  }
112 
113 
115  template<class REC, class RET>
116  struct VerbInvoker
117  : polyvalue::CloneValueSupport<polyvalue::EmptyBase> // mark and mix-in virtual copy construction support
118  {
119  virtual ~VerbInvoker() { }
120 
121  virtual RET applyTo (REC&) =0;
122  virtual Literal getID() const =0;
123 
124  bool operator== (VerbInvoker const& o) const { return getID() == o.getID(); }
125  bool operator!= (VerbInvoker const& o) const { return getID() != o.getID(); }
126  };
127 
128 
129  template<class REC, class SIG>
130  struct VerbHolder;
131 
136  template<class REC, class RET, typename... ARGS>
137  struct VerbHolder<REC, RET(ARGS...)>
138  : VerbInvoker<REC,RET>
139  , VerbToken<REC,RET(ARGS...)>
140  {
141  using Verb = VerbToken<REC,RET(ARGS...)>;
142  using Args = std::tuple<ARGS...>;
143 
145  using SequenceIterator = typename meta::BuildIdxIter<ARGS...>::Ascending;
146 
148  Args args_;
149 
150  template<typename...PARS>
151  VerbHolder (typename Verb::Handler handlerRef, Literal verbID, PARS&&... args)
152  : Verb{handlerRef, verbID}
153  , args_{std::forward<PARS> (args)...}
154  { }
155 
156  Literal
157  getID() const override
158  {
159  return Verb::getID();
160  }
161 
162  RET
163  applyTo (REC& receiver) override
164  {
165  return invokeVerb (receiver, SequenceIterator());
166  }
167 
168  private:
170  template<size_t...idx>
171  RET
173  {
174  return (receiver.*Verb::handler_) (std::get<idx> (args_)...);
175  }
176  };
177 
178 
179 
180  /******************************************************************************************/
195  template<class REC, class RET, size_t arg_storage>
196  class VerbPack
197  : public PolymorphicValue<VerbInvoker<REC,RET>, storageOverhead(arg_storage)>
198  {
199  using Dispatcher = VerbInvoker<REC,RET>; // the interface to talk to our payload
201 
202  template<typename FUN>
204  {
205  static_assert (!sizeof(FUN), "handler must be a function member pointer for the given receiver");
206  };
207  template<typename...ARGS>
208  struct HandlerTypeDetector<RET (REC::*) (ARGS...)>
209  {
210  using Verb = VerbToken<REC, RET(ARGS...)>;
211  using Payload = VerbHolder<REC, RET(ARGS...)>;
212  };
213 
214  template<typename FUN>
215  using PayloadType = typename HandlerTypeDetector<FUN>::Payload *;
216 
217 
218  public:
226  template<typename FUN, typename...ARGS>
227  VerbPack (FUN handler, Literal verbID, ARGS&&... args)
228  : PolyHolder(PayloadType<FUN>(), handler, verbID, std::forward<ARGS>(args)...)
229  { }
230 
236  RET
237  applyTo (REC& receiver)
238  {
239  return PolyHolder::getPayload().applyTo (receiver);
240  }
241 
242  operator string() const
243  {
244  return "VerbPack("
245  + string{util::unConst(this)->getPayload().getID()}
246  + ")";
247  }
248 
250  template<typename ARG>
251  ARG&
253  {
254  using EmbeddedPayload = lib::VerbHolder<REC, RET(ARG)>;
255  REQUIRE (INSTANCEOF (EmbeddedPayload, &this->getPayload()));
256  EmbeddedPayload& embedded = static_cast<EmbeddedPayload&>(this->getPayload());
257  return std::get<0> (embedded.args_);
258  }
259  };
260 
261 
262 
263 } // namespace lib
264 #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:78
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:492
inline string literal This is a marker type to indicate that
Definition: symbol.hpp:85
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.