Lumiera 0.pre.04~rc.1
»edit your freedom«
Loading...
Searching...
No Matches
tree-mutator-collection-binding.hpp
Go to the documentation of this file.
1/*
2 TREE-MUTATOR-COLLECTION-BINDING.hpp - diff::TreeMutator implementation building block
3
4 Copyright (C)
5 2016, 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
72#ifndef LIB_DIFF_TREE_MUTATOR_COLLECTION_BINDING_H
73#define LIB_DIFF_TREE_MUTATOR_COLLECTION_BINDING_H
74
75
76#include "lib/error.hpp"
77#include "lib/nocopy.hpp"
78#include "lib/meta/trait.hpp"
79#include "lib/diff/gen-node.hpp"
82
83#include <utility>
84#include <vector>
85#include <map>
86
87
88namespace lib {
89namespace diff{
90
91 namespace { // Mutator-Builder decorator components...
92
93
94 using std::forward;
95 using lib::meta::Strip;
98
99
100 /* === Technicalities of container access === */
101
102 template<class C>
103 using _AsVector = std::vector<typename C::value_type>;
104 template<class C>
105 using _AsMap = std::map<typename C::key_type, typename C::mapped_type>;
106
107 template<class C>
109 template<class C>
111
112
114 template<class C, typename SEL =void>
116 {
117 static_assert (not sizeof(C), "unable to determine any supported container type for C");
118 };
119
120 template<typename V>
122 {
124 using Elm = Vec::value_type;
125 using Itr = Vec::iterator;
126
127 static Itr
129 {
130 return Itr{&vec.back()};
131 }
132
133 static void
134 append (Vec& vec, Elm&& elm)
135 {
136 vec.emplace_back (forward<Elm> (elm));
137 }
138 };
139
140 template<typename M>
142 {
143 using Map = _AsMap<M>;
144 using Key = Map::key_type;
145 using Val = Map::mapped_type;
146 using Elm = std::pair<const Key, Val>;
147
153 static auto
155 {
156 auto& recentPos = ++map.rend();
157 return map.find (recentPos->first);
158 }
159
160 static void
161 append (Map& map, Elm&& elm)
162 {
163 map.emplace (forward<Elm> (elm));
164 }
165 };
166
167
168
187 template<class COLL, class MAT, class CTR, class SEL, class ASS, class MUT>
190 {
192 using Elm = Coll::value_type;
194
195 using iterator = lib::iter_stl::_SeqT<Coll>::Range;
196 using const_iterator = lib::iter_stl::_SeqT<const Coll>::Range;
197
198
199 ASSERT_VALID_SIGNATURE (MAT, bool(GenNode const& spec, Elm const& elm))
200 ASSERT_VALID_SIGNATURE (CTR, Elm (GenNode const&))
201 ASSERT_VALID_SIGNATURE (SEL, bool(GenNode const&))
202 ASSERT_VALID_SIGNATURE (ASS, bool(Elm&, GenNode const&))
204
205
206 Coll& collection;
207
208 MAT matches;
209 CTR construct;
210 SEL isApplicable;
211 ASS assign;
212 MUT openSub;
213
214 CollectionBinding(Coll& coll, MAT m, CTR c, SEL s, ASS a, MUT u)
215 : collection(coll)
216 , matches(m)
217 , construct(c)
218 , isApplicable(s)
219 , assign(a)
220 , openSub(u)
221 { }
222
223 // only move construction allowed,
224 // to enable use of unique_ptr in collections
225
226
227
228 /* === content manipulation API === */
229
231
234 {
235 contentBuffer.clear();
236 swap (collection, contentBuffer);
237 return eachElm (contentBuffer);
238 }
239
240 void
241 inject (Elm&& elm)
242 {
243 Trait::append (collection, forward<Elm>(elm));
244 }
245
246 iterator
247 search (GenNode const& targetSpec, iterator pos)
248 {
249 while (pos and not matches(targetSpec, *pos))
250 ++pos;
251 return pos;
252 }
253
256 iterator
257 locate (GenNode const& targetSpec)
258 {
259 if (not collection.empty()
260 and matches (targetSpec, recentElm()))
261 return recentElmIter();
262 else
263 return search (targetSpec, eachElm(collection));
264 }
265
266
267 private: /* === Technicalities of container access === */
268
274 iterator
276 {
277 return iterator{Trait::recentElmRawIter (collection), std::end (collection)};
278 }
279
280 Elm&
282 {
283 return *Trait::recentElmRawIter (collection);
284 }
285 };
286
287
288
305 template<class PAR, class BIN>
307 : public PAR
308 {
309 using Iter = BIN::iterator;
310
313
314
315 public:
316 ChildCollectionMutator(BIN&& wiringClosures, PAR&& chain)
317 : PAR(std::forward<PAR>(chain))
318 , binding_(forward<BIN>(wiringClosures))
319 , pos_()
320 { }
321
322
323
324
325 /* ==== Implementation of TreeNode operation API ==== */
326
327 virtual void
328 init() override
329 {
330 pos_ = binding_.initMutation();
331 PAR::init();
332 }
333
339 virtual bool
340 injectNew (GenNode const& n) override
341 {
342 if (binding_.isApplicable(n))
343 {
344 binding_.inject (std::move (binding_.construct(n)));
345 return true;
346 }
347 else
348 return PAR::injectNew (n);
349 }
350
351 virtual bool
352 hasSrc () override
353 {
354 return bool(pos_) or PAR::hasSrc();
355 }
356
359 virtual bool
360 matchSrc (GenNode const& spec) override
361 {
362 if (binding_.isApplicable(spec))
363 return pos_ and binding_.matches (spec, *pos_);
364 else
365 return PAR::matchSrc (spec);
366 }
367
372 virtual void
373 skipSrc (GenNode const& n) override
374 {
375 if (binding_.isApplicable(n))
376 {
377 if (pos_)
378 ++pos_;
379 }
380 else
381 PAR::skipSrc (n);
382 }
383
385 virtual bool
386 acceptSrc (GenNode const& n) override
387 {
388 if (binding_.isApplicable(n))
389 {
390 bool isSrcMatch = pos_ and binding_.matches (n, *pos_);
391 if (isSrcMatch) //NOTE: crucial to perform only our own match check here
392 {
393 binding_.inject (move(*pos_));
394 ++pos_;
395 }
396 return isSrcMatch;
397 }
398 else
399 return PAR::acceptSrc (n);
400 }
401
403 virtual bool
404 findSrc (GenNode const& refSpec) override
405 {
406 if (binding_.isApplicable(refSpec))
407 {
408 Iter found = binding_.search (refSpec, pos_);
409 if (found)
410 {
411 binding_.inject (move(*found));
412 }
413 return bool(found);
414 }
415 else
416 return PAR::findSrc (refSpec);
417 }
418
420 virtual bool
421 accept_until (GenNode const& spec) override
422 {
423 if (spec.matches (Ref::END)
424 or
425 (spec.matches (Ref::ATTRIBS)
426 and binding_.isApplicable (Ref::ATTRIBS)))
427 {
428 for ( ; pos_; ++pos_)
429 binding_.inject (move(*pos_));
430 return PAR::accept_until (spec);
431 }
432 else
433 if (binding_.isApplicable(spec))
434 {
435 bool foundTarget = false;
436 while (pos_ and not binding_.matches (spec, *pos_))
437 {
438 binding_.inject (move(*pos_));
439 ++pos_;
440 }
441 if (pos_ and binding_.matches (spec, *pos_))
442 {
443 binding_.inject (move(*pos_));
444 ++pos_;
445 foundTarget = true;
446 }
447 return foundTarget;
448 }
449 else
450 return PAR::accept_until (spec);
451 }
452
455 virtual bool
456 assignElm (GenNode const& spec) override
457 {
458 if (binding_.isApplicable(spec))
459 {
460 Iter target_found = binding_.locate (spec);
461 return target_found and binding_.assign (*target_found, spec);
462 }
463 else
464 return PAR::assignElm (spec);
465 }
466
479 virtual bool
480 mutateChild (GenNode const& spec, TreeMutator::Handle targetBuff) override
481 {
482 if (binding_.isApplicable(spec))
483 {
484 Iter target_found = binding_.locate (spec);
485 return target_found and binding_.openSub (*target_found, spec.idi, targetBuff);
486 }
487 else
488 return PAR::mutateChild (spec, targetBuff);
489 }
490
493 virtual bool
494 completeScope() override
495 {
496 return PAR::completeScope()
497 and isnil(this->pos_);
498 }
499 };
500
501
502
503
507 template<class COLL, class MAT, class CTR, class SEL, class ASS, class MUT>
509 : CollectionBinding<COLL,MAT,CTR,SEL,ASS,MUT>
510 {
511 using CollectionBinding<COLL,MAT,CTR,SEL,ASS,MUT>::CollectionBinding;
512
513 template<class FUN>
515 matchElement (FUN matcher)
516 {
517 return { this->collection
518 , matcher
519 , this->construct
520 , this->isApplicable
521 , this->assign
522 , this->openSub
523 };
524 }
525
526 template<class FUN>
528 constructFrom (FUN constructor)
529 {
530 return { this->collection
531 , this->matches
532 , constructor
533 , this->isApplicable
534 , this->assign
535 , this->openSub
536 };
537 }
538
539 template<class FUN>
541 isApplicableIf (FUN selector)
542 {
543 return { this->collection
544 , this->matches
545 , this->construct
546 , selector
547 , this->assign
548 , this->openSub
549 };
550 }
551
552 template<class FUN>
554 assignElement (FUN setter)
555 {
556 return { this->collection
557 , this->matches
558 , this->construct
559 , this->isApplicable
560 , setter
561 , this->openSub
562 };
563 }
564
565 template<class FUN>
567 buildChildMutator (FUN childMutationBuilder)
568 {
569 return { this->collection
570 , this->matches
571 , this->construct
572 , this->isApplicable
573 , this->assign
574 , childMutationBuilder
575 };
576 }
577 };
578
579
581 template<class COLL, class MAT, class CTR, class SEL, class ASS, class MUT>
582 inline auto
583 createCollectionBindingBuilder (COLL& coll, MAT m, CTR c, SEL s, ASS a, MUT u)
584 {
585 using Coll = Strip<COLL>::TypeReferred;
586
588 }
589
590
591
592 template<class ELM>
594 {
595 static bool
596 __ERROR_missing_matcher (GenNode const&, ELM const&)
597 {
598 throw error::Logic ("unable to build a sensible default matching predicate");
599 }
600
601 static ELM
603 {
604 throw error::Logic ("unable to build a sensible default for creating new elements");
605 }
606
607 static bool
609 {
610 return spec != Ref::ATTRIBS;
611 // by default apply diff unconditionally,
612 // but don't respond to after(ATTRIBS)
613 }
614
615 static bool
617 {
618 return false;
619 }
620
621 static bool
623 {
624 return false;
625 }
626
627
628 template<class COLL>
629 static auto
630 attachTo (COLL& coll)
631 {
633 ,__ERROR_missing_matcher
634 ,__ERROR_missing_constructor
635 ,ignore_selector
636 ,disable_assignment
637 ,disable_childMutation
638 );
639 }
640 };
641
642
643
646
660 template<class ELM, typename SEL =void>
662 : _EmptyBinding<ELM>
663 { };
664
665 template<class ELM>
666 struct _DefaultBinding<ELM, enable_if<can_wrap_in_GenNode<ELM>>>
667 {
668 template<class COLL>
669 static auto
670 attachTo (COLL& coll)
671 {
673 .matchElement([](GenNode const& spec, ELM const& elm)
674 {
675 return spec.matches(elm);
676 })
677 .constructFrom([](GenNode const& spec) -> ELM
678 {
679 return spec.data.get<ELM>();
680 });
681 }
682 };
683
684
687 template<>
689 {
690 template<class COLL>
691 static auto
692 attachTo (COLL& coll)
693 {
695 .matchElement([](GenNode const& spec, GenNode const& elm)
696 {
697 return spec.matches(elm);
698 })
699 .constructFrom([](GenNode const& spec) -> GenNode
700 {
701 return GenNode{spec};
702 })
703 .assignElement ([](GenNode& target, GenNode const& spec) -> bool
704 {
705 target.data = spec.data;
706 return true;
707 })
708 .buildChildMutator ([](GenNode& target, GenNode::ID const& subID, TreeMutator::Handle buff) -> bool
709 {
710 if (target.idi == subID // require match on already existing child object
711 and target.data.isNested())
712 {
713 mutateInPlace (target.data.get<Rec>())
714 .buildMutator(buff);
715 buff.get()->init();
716 return true;
717 }
718 else
719 return false;
720 });
721 }
722 };
723
724
725
726
727
737 template<class COLL>
738 inline auto
739 collection (COLL& coll)
740 {
741 using Elm = COLL::value_type;
742
744 }
745
746
747
749 template<class PAR>
750 template<class BIN>
751 inline auto
752 Builder<PAR>::attach (BIN&& collectionBindingSetup)
753 {
754 return chainedBuilder<ChildCollectionMutator<PAR,BIN>> (forward<BIN>(collectionBindingSetup));
755 }
756
757
758 }//(END)Mutator-Builder decorator components...
759
760}} // namespace lib::diff
761#endif /*LIB_DIFF_TREE_MUTATOR_COLLECTION_BINDING_H*/
A handle to allow for safe »remote implantation« of an unknown subclass into a given opaque InPlaceBu...
bool isNested() const
determine if payload constitutes a nested scope ("object")
Definition gen-node.hpp:769
virtual bool acceptSrc(GenNode const &n) override
accept existing element, when matching the given spec
virtual bool accept_until(GenNode const &spec) override
repeatedly accept, until after the designated location
virtual bool matchSrc(GenNode const &spec) override
ensure the next recorded source element matches on a formal level with given spec
virtual bool findSrc(GenNode const &refSpec) override
locate designated element and accept it at current position
virtual bool mutateChild(GenNode const &spec, TreeMutator::Handle targetBuff) override
locate the designated target element and build a suitable sub-mutator for this element into the provi...
virtual bool assignElm(GenNode const &spec) override
locate element already accepted into the target sequence and assign the designated payload value to i...
virtual bool completeScope() override
verify all our pending (old) source elements where mentioned.
virtual void skipSrc(GenNode const &n) override
skip next pending src element, causing this element to be discarded
virtual bool injectNew(GenNode const &n) override
fabricate a new element, based on the given specification (GenNode), and insert it at current positio...
Types marked with this mix-in may be moved but not copied.
Definition nocopy.hpp:50
Lumiera error handling (C++ interface).
#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:316
Generic building block for tree shaped (meta)data structures.
Preconfigured adapters for some STL container standard usage situations.
auto collection(COLL &coll)
Entry point to a nested DSL for setup and configuration of a collection binding.
lib::meta::enable_if< std::is_base_of< _AsVector< C >, C > > IF_is_vector
lib::meta::enable_if< std::is_base_of< _AsMap< C >, C > > IF_is_map
auto createCollectionBindingBuilder(COLL &coll, MAT m, CTR c, SEL s, ASS a, MUT u)
builder function to synthesise builder type from given functors
_SeqT< CON >::Range eachElm(CON &coll)
remove_reference_t< TypeUnconst > TypeReferred
Definition trait.hpp:257
enable_if_c< Cond::value, T >::type enable_if
SFINAE helper to control the visibility of specialisations and overloads.
Definition meta/util.hpp:87
Helper for type analysis: tries to strip all kinds of type adornments.
Definition trait.hpp:251
Implementation namespace for support and library code.
LumieraError< LERR_(LOGIC)> Logic
Definition error.hpp:207
STL namespace.
Mix-Ins to allow or prohibit various degrees of copying and cloning.
generic data element node within a tree
Definition gen-node.hpp:224
bool matches(GenNode const &o) const
Definition gen-node.hpp:352
CollectionBindingBuilder< COLL, MAT, CTR, SEL, ASS, FUN > buildChildMutator(FUN childMutationBuilder)
CollectionBindingBuilder< COLL, MAT, FUN, SEL, ASS, MUT > constructFrom(FUN constructor)
iterator locate(GenNode const &targetSpec)
locate element for assignment or mutation, with special shortcut to the recently inserted element
Builder-DSL to create and configure a concrete TreeMutator.
metafunction to detect types able to be wrapped into a GenNode.
Definition gen-node.hpp:515
Helpers for type detection, type rewriting and metaprogramming.
Customisable intermediary to abstract generic tree mutation operations.