Lumiera 0.pre.04
»edit your freedom«
Loading...
Searching...
No Matches
record.hpp
Go to the documentation of this file.
1/*
2 RECORD.hpp - collection to represent object-like data
3
4 Copyright (C)
5 2015, 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
81#ifndef LIB_DIFF_RECORD_H
82#define LIB_DIFF_RECORD_H
83
84
85#include "lib/error.hpp"
86#include "lib/nocopy.hpp"
87#include "lib/iter-adapter.hpp"
89#include "lib/itertools.hpp"
90#include "lib/format-util.hpp"
91#include "lib/util.hpp"
92
93
94#include <algorithm>
95#include <utility>
96#include <vector>
97#include <string>
98
99
100
101namespace lib {
102
103 template<class BA, class DEFAULT>
104 class PlantingHandle;
105
106namespace idi {
107 class BareEntryID;
108}
109namespace diff{
110
111 namespace error = lumiera::error;
112
113 using util::isnil;
114 using std::string;
115
116 class TreeMutator;
117
118 template<typename VAL>
120
121
140 template<typename VAL>
141 class Record
142 {
146
147
148 string type_;
151
152 public:
153 static const string TYPE_NIL;
154 static const Symbol TYPE_NIL_SYM;
155
157 : type_(TYPE_NIL)
158 { }
159
160 template<typename A, typename C>
161 Record(Symbol typeID, A&& att, C&& chi)
162 : type_(isnil(typeID)? TYPE_NIL:string(typeID))
163 , attribs_(std::forward<A> (att))
164 , children_(std::forward<C> (chi))
165 { }
166
167 template<typename A, typename C>
168 Record(Symbol typeID, std::initializer_list<A> const&& att
169 , std::initializer_list<C> const&& chi)
170 : type_(isnil(typeID)? TYPE_NIL:string(typeID))
171 , attribs_(att)
172 , children_(chi)
173 { }
174
175 template<typename SEQ>
176 explicit
177 Record (SEQ const& con)
178 : type_(TYPE_NIL)
179 {
180 auto p = std::begin(con);
181 auto e = std::end(con);
182 for ( ; p!=e and isAttribute(*p); ++p)
183 if (isTypeID (*p))
184 type_ = extractTypeID(*p);
185 else
186 attribs_.push_back (*p);
187 for ( ; p!=e; ++p)
188 children_.push_back (*p);
189 }
190
191 Record (std::initializer_list<VAL> const&& ili)
192 : Record(ili)
193 { }
194
195 // all default copy operations acceptable
196 Record (Record &&) = default;
197 Record (Record const&) = default;
198 Record& operator= (Record &&) = default;
199 Record& operator= (Record const&) = default;
200
201
203 operator std::string() const;
204
205
206 size_t
208 {
209 return attribs_.size();
210 }
211
212 size_t
213 childSize() const
214 {
215 return children_.size();
216 }
217
218 bool
219 empty() const
220 {
221 return attribs_.empty()
222 and children_.empty();
223 }
224
225
226 string
227 getType() const
228 {
229 return type_;
230 }
231
232 bool
233 hasAttribute (string key) const
234 {
235 return attribs_.end() != findKey(key);
236 }
237
238 bool
239 contains (VAL const& val) const
240 {
241 return util::contains (children_, val);
242 }
243
244 Access
245 get (string key) const
246 {
247 ElmIter found = findKey (key);
248 if (attribs_.end() == found)
249 throw error::Invalid ("Record has no attribute \""+key+"\"");
250 else
251 return extractVal (*found);
252 }
253
254 Access
255 child (size_t idx) const
256 {
257 if (children_.size() <= idx)
258 throw error::Invalid ("Child index " +util::toString(idx)
259 +" out of bounds [0.."+util::toString(children_.size())
260 +"["
261 ,error::LUMIERA_ERROR_INDEX_BOUNDS);
262 return children_[idx];
263 }
264
265
276 class Mutator;
277
278
279
293 Record (Mutator const& mut)
294 : Record(static_cast<Record const&> (mut))
295 { }
296 explicit
298 : Record{}
299 {
300 mut.swap(*this);
301 }
302
303 friend class Mutator;
304
305
306
307 /* ==== Exposing scope and contents for iteration ====== */
308
310 using scopeIter = iter_stl::_SeqT<const Storage>::Range;
313
315 iterator begin () const { return iterator(this, attribs_.empty()? children_.begin() : attribs_.begin()); }
316 iterator end () const { return iterator(); }
317
320
323
324 protected: /* ==== API for the IterAdapter ==== */
325
327 friend void
328 iterNext (const Record*, ElmIter& pos)
329 {
330 ++pos;
331 }
332
338 friend bool
339 checkPoint (const Record* src, ElmIter& pos)
340 {
341 REQUIRE (src);
342 static const ElmIter END;
343 if (pos != END and pos == src->attribs_.end() and not src->children_.empty())
344 {
345 pos = src->children_.begin();
346 return true;
347 }
348 else
349 if (pos != END and (pos != src->children_.end()))
350 return true;
351 else
352 {
353 pos = END;
354 return false;
355 } }
356
357 private:
358 /* === abstract attribute handling : needs specialisation === */
359 static bool isAttribute (VAL const& v);
360 static bool isTypeID (VAL const& v);
361 static string extractTypeID (VAL const& v);
362 static string renderAttribute (VAL const& a);
363 static string extractKey (VAL const& v);
364 static Access extractVal (VAL const& v);
365 template<typename X>
366 static VAL buildAttribute (string const& key, X&& payload);
367
368
369 ElmIter
370 findKey (string key) const
371 {
372 return std::find_if (attribs_.begin()
373 ,attribs_.end()
374 ,[=](VAL const& elm)
375 {
376 return key == extractKey(elm);
377 });
378 }
379
380
381 friend bool
382 operator== (Record const& r1, Record const& r2)
383 {
384 return r1.type_ == r2.type_
385 and r1.attribs_ == r2.attribs_
386 and r1.children_ == r2.children_;
387 }
388
389 friend bool
390 operator!= (Record const& r1, Record const& r2)
391 {
392 return not (r1 == r2);
393 }
394 };
395
396 template<typename VAL>
397 const Symbol Record<VAL>::TYPE_NIL_SYM = "NIL";
398
399 template<typename VAL>
400 const string Record<VAL>::TYPE_NIL = string(TYPE_NIL_SYM);
401
402
403
404 template<typename VAL>
405 class Record<VAL>::Mutator
407 {
409
411
412 public:
414 : record_()
415 { }
416
417 explicit
418 Mutator (Rec const& startingPoint)
419 : record_(startingPoint)
420 { }
421
422 explicit
423 Mutator (Rec && startingPoint)
424 : record_(std::move (startingPoint))
425 { }
426
428 operator Rec & () { return record_; }
429 operator Rec const&() const { return record_; }
430
431 void
432 swap (Rec& existingInstance) noexcept
433 {
434 using std::swap;
435 swap (existingInstance, record_);
436 }
437
438 bool
439 empty() const
440 {
441 return record_.empty();
442 }
443
444
445 /* === functions to alter contents === */
446
447 void
448 setType (string const& newTypeID)
449 {
450 record_.type_ = newTypeID;
451 }
452
453 Mutator&&
454 type (string const& typeID)
455 {
456 setType (typeID);
457 return move(*this);
458 }
459
460 template<typename X>
461 Mutator&&
462 set (string const& key, X&& content)
463 {
464 VAL attribute(Rec::buildAttribute (key, std::forward<X>(content)));
465 return set (std::move (attribute));
466 }
467
468 Mutator&&
469 set (VAL&& attribute)
470 {
471 string key = Rec::extractKey(attribute);
472 if (isnil (key))
473 throw error::Invalid ("Attempt to set an attribute with empty key");
474
475 Rec::Storage& as =record_.attribs_;
476 auto found = std::find_if (as.begin(),as.end()
477 ,[=](VAL const& elm)
478 {
479 return key == extractKey(elm);
480 });
481 if (as.end() == found)
482 as.push_back (std::forward<VAL> (attribute));
483 else
484 (*found) = (std::forward<VAL> (attribute));
485 return move(*this);
486 }
487
488 Mutator&&
489 appendAttrib (VAL const& newAttrib)
490 {
491 REQUIRE (Rec::isAttribute(newAttrib));
492 record_.attribs_.push_back (newAttrib);
493 return move(*this);
494 }
495
496 Mutator&&
497 appendChild (VAL const& newChild)
498 {
499 record_.children_.push_back (newChild);
500 return move(*this);
501 }
502
503 Mutator&&
504 prependChild (VAL const& newChild)
505 {
506 record_.children_.insert (record_.children_.begin(), newChild);
507 return move(*this);
508 }
509
510 /* === low-level access (for diff application) === */
511
513
529
530 auto
532 {
533 return std::tie (record_.attribs_, record_.children_);
534 }
535
536
543 VAL const&
545 {
546 if (record_.empty())
547 throw error::State("Record is empty, unable to access (last) element.");
548
549 if (record_.children_.empty())
550 return record_.attribs_.back();
551 else
552 return record_.children_.back();
553 }
554
555
556 /* === extension point for building specific value types === */
557 /*
558 * the following builder functions need to be specialised
559 * to create a Record holding specific value types,
560 * especially for building a tree like structure
561 * with GenNode holding a Record<GenNode>
562 */
563
564 VAL genNode();
565 VAL genNode(idi::BareEntryID rawID);
566 VAL genNode(string const& symbolicID);
567
568 template<typename X, typename...ARGS>
569 Mutator&& attrib (string const& key, X&& initialiser, ARGS&& ...args)
570 {
571 set (key, std::forward<X>(initialiser));
572 return attrib (std::forward<ARGS>(args)...);
573 }
574 Mutator&& attrib () { return move(*this); } // argument recursion end
575
576
577 template<typename X, typename...ARGS>
578 Mutator&& scope (X const& initialiser, ARGS&& ...args)
579 {
580 appendChild (VAL(initialiser));
581 return scope (std::forward<ARGS>(args)...);
582 }
583 Mutator&& scope () { return move(*this); }
584
585 };
586
587
597 template<typename VAL>
599 mutateInPlace (Record<VAL>& record_to_mutate)
600 {
601 return reinterpret_cast<Record<VAL>::Mutator &> (record_to_mutate);
602 }
603
604
616 template<typename VAL>
618 {
620
622
623 public:
626 RecordRef() noexcept
627 : record_(nullptr)
628 { }
629
632 RecordRef(Target& o) noexcept
633 : record_(&o)
634 { }
635
637 RecordRef(Target&&) = delete;
638
639 RecordRef(RecordRef const&) = default;
640 RecordRef(RecordRef &&) = default;
641
643 RecordRef& operator= (RecordRef const&) = delete;
645
647 RecordRef&
649 {
650 std::swap (record_, o.record_);
651 return *this;
652 }
653
654
655 explicit
656 operator bool() const
657 {
658 return bool(record_);
659 }
660
661 bool
662 empty() const
663 {
664 return not record_;
665 }
666
670 operator Target&() const
671 {
672 if (!record_)
673 throw error::Logic("attempt to dereference an unbound record reference"
674 ,error::LUMIERA_ERROR_BOTTOM_VALUE);
675 return *record_;
676 }
677
678 Target*
679 get() const noexcept
680 {
681 return record_;
682 }
683
684 operator string() const
685 {
686 return "Ref->" + (empty()? util::BOTTOM_INDICATOR
687 : string(*record_));
688 }
689
691 friend bool
692 operator== (RecordRef const& r1, RecordRef const& r2)
693 {
694 return r1.record_ == r2.record_;
695 }
696 friend bool
697 operator!= (RecordRef const& r1, RecordRef const& r2)
698 {
699 return r1.record_ != r2.record_;
700 }
701 };
702
703
704
705
706 /* === Extension point: Specialisations for attribute handling === */
707
712 template<>
713 struct RecordSetup<string>
714 {
715 using Storage = std::vector<string>;
716 using ElmIter = Storage::const_iterator;
717 using Access = string;
718 };
719
720
721
722
723 /* default handling defined for Record<string> */
724
725 template<>
726 inline string
728 {
729 size_t pos = v.find('=');
730 if (string::npos == pos)
731 return "";
732 else
733 return util::trim (v.substr (0,pos));
734 }
735
736 template<>
737 inline string
739 {
740 size_t pos = v.find('=');
741 if (string::npos == pos)
742 return v;
743 else
744 return util::trim (v.substr (pos+1, v.length() - pos));
745 }
746
747 template<>
748 inline bool
750 {
751 return string::npos != v.find('=');
752 }
753
754 template<>
755 inline bool
756 Record<string>::isTypeID (string const& v)
757 {
758 return isAttribute(v)
759 and "type" == extractKey(v);
760 }
761
762 template<>
763 inline string
765 {
766 return extractVal(v);
767 }
768
769 template<>
770 inline string
771 Record<string>::renderAttribute (string const& attrib)
772 {
773 return extractKey(attrib) + " = " + extractVal(attrib);
774 }
775
776 template<>
777 template<typename X>
778 inline string
779 Record<string>::buildAttribute (string const& key, X&& payload)
780 {
781 return string(key + " = " + extractVal(payload));
782 }
783
784
785
786
787
788
789 /* === Diagnostics === */
790
791 template<typename VAL>
792 Record<VAL>::operator std::string() const
793 {
794 using util::join;
796
797 return "Rec("
798 + (TYPE_NIL==type_? "" : type_)
799 + (isnil(this->attribs())? "" : "| "+join (transformIterator (this->attribs(), renderAttribute))+" ")
800 + (isnil(this->scope())? "" : "|{"+join (this->scope())+"}")
801 + ")"
802 ;
803 }
804
805
806
807}} // namespace lib::diff
808#endif /*LIB_DIFF_GEN_NODE_H*/
Adapter for building an implementation of the »Lumiera Forward Iterator« concept.
A handle to allow for safe »remote implantation« of an unknown subclass into a given opaque InPlaceBu...
Token or Atom with distinct identity.
Definition symbol.hpp:120
Iterator tool treating pulled data by a custom transformation (function)
wrapped record reference.
Definition record.hpp:618
friend bool operator!=(RecordRef const &r1, RecordRef const &r2)
Definition record.hpp:697
Record< VAL > Target
Definition record.hpp:619
RecordRef(RecordRef &&)=default
RecordRef() noexcept
by default create an invalid ("bottom") reference
Definition record.hpp:626
RecordRef(Target &o) noexcept
create a reference bound to the given target; can not be rebound
Definition record.hpp:632
RecordRef & operator=(RecordRef const &)=delete
references can not be reassigned
bool empty() const
Definition record.hpp:662
RecordRef(RecordRef const &)=default
RecordRef(Target &&)=delete
prevent moving into black hole
Target * get() const noexcept
Definition record.hpp:679
friend bool operator==(RecordRef const &r1, RecordRef const &r2)
Definition record.hpp:692
Mutator && set(string const &key, X &&content)
Definition record.hpp:462
Mutator && set(VAL &&attribute)
Definition record.hpp:469
Mutator && scope(X const &initialiser, ARGS &&...args)
Definition record.hpp:578
Mutator && prependChild(VAL const &newChild)
Definition record.hpp:504
void swap(Rec &existingInstance) noexcept
Definition record.hpp:432
Mutator(Rec const &startingPoint)
Definition record.hpp:418
VAL const & accessLast()
get the tail element.
Definition record.hpp:544
Mutator && appendAttrib(VAL const &newAttrib)
Definition record.hpp:489
void buildMutator(BufferHandle)
attachment point to receive and apply tree-diff changes.
Mutator && appendChild(VAL const &newChild)
Definition record.hpp:497
Mutator && attrib(string const &key, X &&initialiser, ARGS &&...args)
Definition record.hpp:569
Mutator(Rec &&startingPoint)
Definition record.hpp:423
Mutator && type(string const &typeID)
Definition record.hpp:454
void setType(string const &newTypeID)
Definition record.hpp:448
object-like record of data.
Definition record.hpp:142
static const string TYPE_NIL
Definition record.hpp:153
iterator begin() const
default iteration exposes all data within this "object", starting with the attributes
Definition record.hpp:315
static const Symbol TYPE_NIL_SYM
Definition record.hpp:154
Record(SEQ const &con)
Definition record.hpp:177
operator std::string() const
for diagnostic purpose
Definition record.hpp:792
ElmIter findKey(string key) const
Definition record.hpp:370
Record(std::initializer_list< VAL > const &&ili)
Definition record.hpp:191
valIter vals() const
Definition record.hpp:322
static bool isAttribute(VAL const &v)
Access get(string key) const
Definition record.hpp:245
static string extractTypeID(VAL const &v)
scopeIter attribs() const
Definition record.hpp:318
bool hasAttribute(string key) const
Definition record.hpp:233
size_t attribSize() const
Definition record.hpp:207
size_t childSize() const
Definition record.hpp:213
scopeIter scope() const
Definition record.hpp:319
TransformIter< scopeIter, Access > valIter
Definition record.hpp:312
bool empty() const
Definition record.hpp:219
keyIter keys() const
Definition record.hpp:321
iterator end() const
Definition record.hpp:316
string getType() const
Definition record.hpp:227
static VAL buildAttribute(string const &key, X &&payload)
Record(Symbol typeID, A &&att, C &&chi)
Definition record.hpp:161
IterAdapter< ElmIter, const Record * > iterator
Definition record.hpp:309
RecordSetup< VAL >::ElmIter ElmIter
Definition record.hpp:144
friend void iterNext(const Record *, ElmIter &pos)
Implementation of Iteration-logic: pull next element.
Definition record.hpp:328
RecordSetup< VAL >::Access Access
Definition record.hpp:145
friend bool checkPoint(const Record *src, ElmIter &pos)
Implementation of Iteration-logic: detect iteration end.
Definition record.hpp:339
bool contains(VAL const &val) const
Definition record.hpp:239
Record(Record &&)=default
RecordSetup< VAL >::Storage Storage
Definition record.hpp:143
static string renderAttribute(VAL const &a)
Record(Record const &)=default
static Access extractVal(VAL const &v)
Access child(size_t idx) const
Definition record.hpp:255
friend bool operator==(Record const &r1, Record const &r2)
Definition record.hpp:382
Record & operator=(Record &&)=default
Record(Symbol typeID, std::initializer_list< A > const &&att, std::initializer_list< C > const &&chi)
Definition record.hpp:168
iter_stl::_SeqT< const Storage >::Range scopeIter
Definition record.hpp:310
static bool isTypeID(VAL const &v)
Storage children_
Definition record.hpp:150
Record(Mutator const &mut)
copy-initialise (or convert) from the given Mutator instance.
Definition record.hpp:293
Record(Mutator &&mut)
Definition record.hpp:297
friend bool operator!=(Record const &r1, Record const &r2)
Definition record.hpp:390
static string extractKey(VAL const &v)
TransformIter< scopeIter, string > keyIter
Definition record.hpp:311
type erased baseclass for building a combined hash and symbolic ID.
Definition entry-id.hpp:134
Types marked with this mix-in may be moved but not copied.
Definition nocopy.hpp:50
Lumiera error handling (C++ interface).
Collection of small helpers and convenience shortcuts for diagnostics & formatting.
Preconfigured adapters for some STL container standard usage situations.
Helper template(s) for creating Lumiera Forward Iterators.
Helpers for working with iterators based on the pipeline model.
Storage::const_iterator ElmIter
Definition record.hpp:716
std::vector< string > Storage
Definition record.hpp:715
Record< VAL >::Mutator & mutateInPlace(Record< VAL > &record_to_mutate)
open an existing record for modification in-place.
Definition record.hpp:599
string Access
data access by value copy
Definition record.hpp:717
_SeqT< CON >::Range eachElm(CON &coll)
Implementation namespace for support and library code.
auto transformIterator(IT const &src, FUN processingFunc)
Build a TransformIter: convenience free function shortcut, picking up the involved types automaticall...
LumieraError< LERR_(STATE)> State
Definition error.hpp:209
LumieraError< LERR_(LOGIC)> Logic
Definition error.hpp:207
LumieraError< LERR_(INVALID)> Invalid
Definition error.hpp:211
STL namespace.
bool contains(MAP &map, typename MAP::key_type const &key)
shortcut for containment test on a map
Definition util.hpp:230
std::string toString(TY const &val) noexcept
get some string representation of any object, reliably.
string join(COLL &&coll, string const &delim=", ")
enumerate a collection's contents, separated by delimiter.
string trim(string const &org)
remove leading and trailing whitespace
Definition util.cpp:85
bool isnil(lib::time::Duration const &dur)
Mix-Ins to allow or prohibit various degrees of copying and cloning.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...