Lumiera  0.pre.03
»edit your freedom«
tree-mutator-attribute-binding.hpp
Go to the documentation of this file.
1 /*
2  TREE-MUTATOR-ATTRIBUTE-BINDING.hpp - diff::TreeMutator implementation building block
3 
4  Copyright (C) Lumiera.org
5  2016, 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 
104 #ifndef LIB_DIFF_TREE_MUTATOR_ATTRIBUTE_BINDING_H
105 #define LIB_DIFF_TREE_MUTATOR_ATTRIBUTE_BINDING_H
106 
107 
108 #include "lib/error.hpp"
109 #include "lib/symbol.hpp"
110 #include "lib/diff/gen-node.hpp"
111 #include "lib/diff/tree-mutator.hpp"
112 #include "lib/format-string.hpp"
113 #include "lib/idi/entry-id.hpp"
114 
115 #include <utility>
116 
117 
118 namespace lib {
119 namespace diff{
120 
121  namespace { // Mutator-Builder decorator components...
122 
123 
133  template<class PAR>
135  : public PAR
136  {
137 
138  BareEntryID attribID_;
139 
140  protected:
141  AttributeBindingBase (BareEntryID attribID, PAR&& chain)
142  : PAR(std::forward<PAR>(chain))
143  , attribID_(attribID)
144  { }
145 
153  bool
154  isApplicable (GenNode const& spec)
155  {
156  return spec.isNamed()
157  and attribID_ == spec.idi;
158  }
159 
160  void
161  __ifApplicable_refuse_to(Literal oper, GenNode const& spec)
162  {
163  if (this->isApplicable(spec))
164  throw error::Logic (_Fmt{"attempt to %s attribute '%s', "
165  "but this binding for '%s' is linked to a data field and "
166  "thus does not support any notion of 'order' or 'position', "
167  "inserting or deletion."}
168  % oper % spec.idi % this->attribID_);
169  }
170 
171 
172  /* ==== re-Implementation of the operation API ==== */
173  public:
179  virtual bool
180  matchSrc (GenNode const& spec) override
181  {
182  return isApplicable (spec)
183  or PAR::matchSrc (spec);
184  }
185 
186 
187  // note: hasSrc() not overridden here --> delegate to parent layer
188 
189 
191  virtual bool
192  acceptSrc (GenNode const& spec) override
193  {
194  return isApplicable (spec)
195  or PAR::acceptSrc (spec);
196  }
197 
204  virtual void
205  skipSrc (GenNode const& refSpec) override
206  {
207  __ifApplicable_refuse_to ("skip or drop", refSpec);
208  PAR::skipSrc (refSpec);
209  }
210 
211  virtual bool
212  findSrc (GenNode const& refSpec) override
213  {
214  __ifApplicable_refuse_to ("re-order", refSpec);
215  return PAR::findSrc (refSpec);
216  }
217 
227  virtual bool
228  accept_until (GenNode const& spec) override
229  {
230  if (Ref::END == spec or Ref::ATTRIBS == spec)
231  return PAR::accept_until(spec);
232  else
233  {
234  __ifApplicable_refuse_to ("navigate to a position behind", spec);
235  return PAR::accept_until(spec);
236  }
237  }
238  };
239 
240 
241 
242 
243  template<class PAR, class CLO>
245  : public AttributeBindingBase<PAR>
246  {
247  using CloArgs = typename lib::meta::_Fun<CLO>::Args;
248  using ValueType = typename lib::meta::Pick<CloArgs, 0>::Type;
249  using ID = idi::EntryID<ValueType>;
250 
251 
252  CLO setter_;
253 
254  public:
255  ChangeOperation (Symbol attribKey, CLO clo, PAR&& chain)
256  : AttributeBindingBase<PAR>(ID{attribKey}, std::forward<PAR>(chain))
257  , setter_(clo)
258  { }
259 
260 
261  /* ==== Implementation of value assignment operation ==== */
262 
270  virtual bool
271  injectNew (GenNode const& spec) override
272  {
273  if (not this->isApplicable(spec))
274  return PAR::injectNew(spec);
275 
276  setter_(spec.data.get<ValueType>());
277  return true;
278  }
279 
281  virtual bool
282  assignElm (GenNode const& spec) override
283  {
284  if (not this->isApplicable(spec))
285  return PAR::assignElm(spec);
286 
287  setter_(spec.data.get<ValueType>());
288  return true;
289  }
290  };
291 
292 
293 
294  template<class PAR, class MUT>
296  : public AttributeBindingBase<PAR>
297  {
298 
300 
301  MUT mutatorBuilder_;
302 
303 
304  public:
305  MutationOperation (BareEntryID const& attribID, MUT clo, PAR&& chain)
306  : AttributeBindingBase<PAR>(attribID, std::forward<PAR>(chain))
307  , mutatorBuilder_(clo)
308  { }
309 
310 
314  virtual bool
315  mutateChild (GenNode const& spec, TreeMutator::Handle targetBuff) override
316  {
317  if (not this->isApplicable(spec))
318  return PAR::mutateChild(spec, targetBuff);
319 
320  mutatorBuilder_(targetBuff);
321  return true;
322  }
323 
324 
340  virtual bool
341  injectNew (GenNode const& spec) override
342  {
343  return this->isApplicable(spec)
344  or PAR::injectNew(spec);
345  }
346  };
347 
348 
349 
351  template<class PAR>
352  template<typename CLO>
353  inline auto
354  Builder<PAR>::change (Symbol attributeID, CLO setterClosure)
355  {
356  return chainedBuilder<ChangeOperation<PAR,CLO>> (attributeID, setterClosure);
357  }
358 
359 
361  template<class PAR>
362  template<typename CLO>
363  inline auto
364  Builder<PAR>::mutateAttrib (Symbol attributeID, CLO mutatorBuilderClosure)
365  {
366  idi::EntryID<Rec> key{attributeID};
367  return chainedBuilder<MutationOperation<PAR,CLO>> (key, mutatorBuilderClosure);
368  }
369 
371  template<class PAR>
372  template<typename CLO>
373  inline auto
374  Builder<PAR>::mutateAttrib (idi::BareEntryID const& rawID, CLO mutatorBuilderClosure)
375  {
376  return chainedBuilder<MutationOperation<PAR,CLO>> (rawID, mutatorBuilderClosure);
377  }
378 
379 
380 
381  }//(END)Mutator-Builder decorator components...
382 
383 }} // namespace lib::diff
384 #endif /*LIB_DIFF_TREE_MUTATOR_ATTRIBUTE_BINDING_H*/
type erased baseclass for building a combined hash and symbolic ID.
Definition: entry-id.hpp:142
#define ASSERT_VALID_SIGNATURE(_FUN_, _SIG_)
Macro for a compile-time check to verify the given generic functors or lambdas expose some expected s...
Definition: function.hpp:256
virtual bool matchSrc(GenNode const &spec) override
ensure the given spec is deemed appropriate at that point.
inline string literal This is a marker type to indicate that
Definition: symbol.hpp:85
Front-end for printf-style string template interpolation.
typed symbolic and hash ID for asset-like position accounting.
Definition: entry-id.hpp:135
virtual bool acceptSrc(GenNode const &spec) override
accept status quo, after verifying the spec from the diff verb
Helper for uniform access to function signature types.
Definition: function.hpp:108
A front-end for using printf-style formatting.
Implementation namespace for support and library code.
Derived specific exceptions within Lumiera&#39;s exception hierarchy.
Definition: error.hpp:199
Token or Atom with distinct identity.
Definition: symbol.hpp:126
A handle to allow for safe »remote implantation« of an unknown subclass into a given opaque InPlaceBu...
Definition: record.hpp:113
static const Ref END
symbolic ID ref "_END_"
Definition: gen-node.hpp:871
virtual bool mutateChild(GenNode const &spec, TreeMutator::Handle targetBuff) override
if this binding layer is in charge, then invoke the closure, which is assumed to construct a nested T...
Marker types to indicate a literal string and a Symbol.
bool isApplicable(GenNode const &spec)
hard wired "selector predicate" for this binding layer.
virtual bool assignElm(GenNode const &spec) override
invoke the setter lambda, when this binding layer is in charge
virtual bool accept_until(GenNode const &spec) override
there is no real support for navigating to a &#39;position&#39;, since attribute / data field binding has no ...
virtual void skipSrc(GenNode const &refSpec) override
any reordering or deletion of object fields is prohibited
Generic building block for tree shaped (meta)data structures.
virtual bool injectNew(GenNode const &spec) override
while, strictly speaking, one can not "insert" fields into a given class definition, this binding can tolerate an INS verb whenever this means to touch a field which is actually known and present in the class definition underlying this binding.
Lumiera error handling (C++ interface).
static const Ref ATTRIBS
symbolic ID ref "_ATTRIBS_"
Definition: gen-node.hpp:874
Customisable intermediary to abstract generic tree mutation operations.
Bare symbolic and hash ID used for accounting of asset like entries.
virtual bool injectNew(GenNode const &spec) override
default setup: silently absorb insert.
generic data element node within a tree
Definition: gen-node.hpp:231