23 #ifndef COM_DAFER45_TBTK_INDEXED_DATA_TREE
24 #define COM_DAFER45_TBTK_INDEXED_DATA_TREE
26 #include "TBTK/ElementNotFoundException.h"
38 #ifndef TBTK_DISABLE_NLOHMANN_JSON
39 # include "TBTK/json.hpp"
44 template<
typename Data>
67 void add(
const Data &data,
const Index &index);
77 bool get(Data &data,
const Index &index)
const;
97 const Data&
get(
const Index &index)
const;
119 template<
bool isConstIterator>
124 typedef typename std::conditional<
128 >::type DataReferenceType;
137 bool operator==(
const _Iterator &rhs)
const;
143 const Index& getCurrentIndex()
const;
147 typedef typename std::conditional<
151 >::type IndexedDataTreePointerType;
154 IndexedDataTreePointerType indexedDataTree;
161 _Iterator(IndexedDataTreePointerType indexedDataTree,
bool end =
false);
175 ) : _Iterator<false>(indexedDataTree,
end){};
188 ) : _Iterator<true>(indexedDataTree,
end){};
204 ConstIterator
begin()
const;
210 ConstIterator
cbegin()
const;
220 ConstIterator
end()
const;
225 ConstIterator
cend()
const;
228 std::map<Subindex, IndexedDataTree> children;
244 void add(
const Data &data,
const Index& index,
unsigned int subindex);
248 bool get(Data &data,
const Index& index,
unsigned int subindex)
const;
252 const Data&
get(
const Index& index,
unsigned int subindex)
const;
255 Index getFirstIndex()
const;
259 bool getFirstIndex(
Index &index)
const;
269 const Index ¤tIndex,
276 #ifndef TBTK_DISABLE_NLOHMANN_JSON
278 template<
typename Data>
280 indexIncluded =
false;
281 indexSeparator =
false;
284 template<
typename Data>
286 const std::string &serialization,
290 validate(serialization,
"IndexedDataTree", mode),
291 "IndexedDataTree<bool>::IndexedDataTree()",
292 "Unable to parse string as IndexedDataTree<bool> '"
293 << serialization <<
"'.",
301 nlohmann::json j = nlohmann::json::parse(
304 indexIncluded = j.at(
"indexIncluded").get<
bool>();
305 indexSeparator = j.at(
"indexSeparator").get<
bool>();
306 data = Serializable::deserialize<Data>(
307 j.at(
"data").get<std::string>(),
310 nlohmann::json jsonChildren = j.at(
"children");
312 nlohmann::json::const_iterator iterator
313 = jsonChildren.cbegin();
314 iterator != jsonChildren.cend();
320 Serializable::Mode::JSON
323 iterator.value().dump(),
324 Serializable::Mode::JSON
329 catch(nlohmann::json::exception &e){
331 "IndexedDataTree<bool>::IndexedDataTree()",
332 "Unable to parse string as"
333 <<
" IndexedDataTree<bool> '"
334 << serialization <<
"'.",
343 "IndexedDataTree<Data>::IndexedDataTree()",
344 "Only Serializable::Mode::JSON is supported yet.",
350 template<
typename Data>
354 template<
typename Data>
359 template<
typename Data>
363 unsigned int subindex
365 if(subindex < index.
getSize()){
373 if(children.size() == 0){
374 indexSeparator =
true;
379 "IndexedDataTree:add()",
380 "Invalid index '" << index.
toString()
381 <<
"'. Another Index has already been"
382 <<
" added to the tree that has a"
383 <<
" conflicting index at the index"
384 <<
" separator at subindex '"
386 "Note that a separation point between"
387 <<
" two indices counts as a subindex."
391 indexSeparator =
false;
392 add(data, index, subindex+1);
393 indexSeparator =
true;
399 "IndexedDataTree:add()",
400 "Invalid index '" << index.
toString() <<
"'."
401 <<
" Another Index has already been added to"
402 <<
" the tree that has a conflicting index"
403 <<
" separator at subindex '"
405 "Note that a separation point between two"
406 <<
" indices counts as a subindex."
412 "IndexedDataTree::add()",
413 "Invalid Index. Negative indices not allowed, but the"
414 <<
"index " << index.
toString() <<
" have a negative"
415 <<
" index" <<
" in position " << subindex <<
".",
416 "Compound indices such as {{1, 2, 3}, {4, 5, 6}} are"
417 <<
" separated by IDX_SEPARATOR with the value '"
418 << IDX_SEPARATOR <<
"' and are" <<
" represented as {1"
419 <<
", 2, 3, " << IDX_SEPARATOR <<
", 4, 5, 6}. This is"
420 <<
" the only allowed instance of negative numbers."
431 "IndexedDataTree::add()",
432 "Incompatible indices. The Index " << index.
toString()
433 <<
" cannot be added because an Index of length "
434 << subindex + 1 <<
" which exactly agrees with the "
435 << subindex + 1 <<
" first indices of the current"
436 <<
" Index has already been added.",
440 children[currentIndex].add(data, index, subindex+1);
452 children.size() == 0,
453 "IndexedDataTree::add()",
454 "Incompatible indices. The Index " << index.
toString()
455 <<
" cannot be added because a longer Index which"
456 <<
" exactly agrees with the current Index in the"
457 <<
" common indices has already been added.",
461 indexIncluded =
true;
466 template<
typename Data>
468 return get(data, index, 0);
471 template<
typename Data>
475 unsigned int subindex
477 if(subindex < index.
getSize()){
485 if(children.size() == 0 && !indexIncluded)
493 return get(data, index, subindex+1);
497 "IndexedDataTree::get()",
498 "Invalid Index. Found IDX_SEPARATOR at"
499 <<
" subindex '" << subindex <<
"',"
500 <<
" but the node is not an index"
509 "IndexedDataTree::add()",
510 "Invalid Index. Negative indices not allowed, but the"
511 <<
" index " << index.
toString() <<
" have a negative"
512 <<
" index in position " << subindex <<
".",
517 return children.at(currentIndex).get(data, index, subindex+1);
519 catch(std::out_of_range &e){
538 template<
typename Data>
545 return const_cast<Data&
>(
550 template<
typename Data>
552 return get(index, 0);
555 template<
typename Data>
558 unsigned int subindex
560 if(subindex < index.
getSize()){
569 if(children.size() == 0 && !indexIncluded){
573 "Tried to get element with Index '"
574 + index.
toString() +
"', but no such element"
581 Subindex currentIndex = index.
at(subindex);
583 if(currentIndex.isIndexSeparator()){
585 return get(index, subindex+1);
589 "IndexedDataTree::get()",
590 "Invalid Index. Found IDX_SEPARATOR at"
591 <<
" subindex '" << subindex <<
"',"
592 <<
" but the node is not an index"
601 "IndexedDataTree::get()",
602 "Invalid Index. Negative indices not allowed, but the"
603 <<
"index " << index.
toString() <<
" have a negative"
604 <<
" index" <<
" in position " << subindex <<
".",
605 "Compound indices such as {{1, 2, 3}, {4, 5, 6}} are"
606 <<
" separated by IDX_SEPARATOR with the value '"
607 << IDX_SEPARATOR <<
"' and are" <<
" represented as {1"
608 <<
", 2, 3, " << IDX_SEPARATOR <<
", 4, 5, 6}. This is"
609 <<
" the only allowed instance of negative numbers."
613 return children.at(currentIndex).get(index, subindex+1);
615 catch(std::out_of_range &e){
616 throw ElementNotFoundException(
619 "Tried to get element with Index '"
620 + index.
toString() +
"', but no such element"
634 throw ElementNotFoundException(
637 "Tried to get element with Index '"
638 + index.
toString() +
"', but no such element"
646 template<
typename Data>
647 Index IndexedDataTree<Data>::getFirstIndex()
const{
649 getFirstIndex(index);
654 template<
typename Data>
655 bool IndexedDataTree<Data>::getFirstIndex(Index &index)
const{
660 index.pushBack(IDX_SEPARATOR);
666 >::const_iterator iterator = children.cbegin();
667 iterator != children.cend();
670 Subindex subindex = iterator->first;
671 index.pushBack(subindex);
672 if(iterator->second.getFirstIndex(index))
684 template<
typename Data>
685 Index IndexedDataTree<Data>::getNextIndex(
const Index &index)
const{
686 if(index.getSize() == 0)
690 getNextIndex(index, nextIndex);
695 template<
typename Data>
696 bool IndexedDataTree<Data>::getNextIndex(
697 const Index ¤tIndex,
701 if(currentIndex.equals(nextIndex))
708 nextIndex.pushBack(IDX_SEPARATOR);
710 bool hasSameIndexStructure =
true;
711 if(currentIndex.getSize() > nextIndex.getSize()){
712 for(
unsigned int n = 0; n < nextIndex.getSize(); n++){
713 if(currentIndex[n] != nextIndex[n]){
714 hasSameIndexStructure =
false;
720 hasSameIndexStructure =
false;
723 typename std::map<Subindex, IndexedDataTree>::const_iterator iterator;
724 if(hasSameIndexStructure)
725 iterator = children.find(currentIndex[nextIndex.getSize()]);
727 iterator = children.cbegin();
728 while(iterator != children.cend()){
729 nextIndex.pushBack(iterator->first);
730 if(iterator->second.getNextIndex(currentIndex, nextIndex))
743 template<
typename Data>
745 indexIncluded =
false;
749 template<
typename Data>
756 >::const_iterator iterator = children.
cbegin();
757 iterator != children.cend();
760 size += iterator->second.getSizeInBytes();
766 template<
typename Data>
772 j[
"id"] =
"IndexedDataTree";
773 j[
"indexIncluded"] = indexIncluded;
774 j[
"indexSeparator"] = indexSeparator;
776 j[
"children"] = nlohmann::json();
781 >::const_iterator iterator = children.
cbegin();
782 iterator != children.cend();
786 iterator->first.serialize(
787 Serializable::Mode::JSON
789 ] = nlohmann::json::parse(
790 iterator->second.serialize(
791 Serializable::Mode::JSON
800 "IndexedDataTree<Data>::serialize()",
801 "Only Serializable::Mode::JSON is supported yet.",
807 template<
typename Data>
809 return Iterator(
this);
812 template<
typename Data>
816 return ConstIterator(
this);
819 template<
typename Data>
820 typename IndexedDataTree<Data>::ConstIterator IndexedDataTree<
823 return ConstIterator(
this);
826 template<
typename Data>
828 return Iterator(
this,
true);
831 template<
typename Data>
833 return ConstIterator(
this,
true);
836 template<
typename Data>
838 return ConstIterator(
this,
true);
841 template<
typename Data>
template<
bool isConstIterator>
843 currentIndex = indexedDataTree->getNextIndex(currentIndex);
846 template<
typename Data>
template<
bool isConstIterator>
847 typename IndexedDataTree<Data>::template _Iterator<
849 >::DataReferenceType IndexedDataTree<Data>::_Iterator<
852 return indexedDataTree->get(currentIndex);
855 template<
typename Data>
template<
bool isConstIterator>
856 bool IndexedDataTree<Data>::_Iterator<isConstIterator>::operator==(
857 const IndexedDataTree<Data>::_Iterator<isConstIterator> &rhs
860 indexedDataTree == rhs.indexedDataTree
861 && currentIndex.equals(rhs.currentIndex)
870 template<
typename Data>
template<
bool isConstIterator>
871 bool IndexedDataTree<Data>::_Iterator<isConstIterator>::operator!=(
872 const IndexedDataTree<Data>::_Iterator<isConstIterator> &rhs
875 indexedDataTree != rhs.indexedDataTree
876 || !currentIndex.equals(rhs.currentIndex)
885 template<
typename Data>
template<
bool isConstIterator>
886 const Index& IndexedDataTree<Data>::_Iterator<
893 template<
typename Data>
template<
bool isConstIterator>
894 IndexedDataTree<Data>::_Iterator<isConstIterator>::_Iterator(
895 IndexedDataTreePointerType indexedDataTree,
898 this->indexedDataTree = indexedDataTree;
900 currentIndex = Index();
902 currentIndex = indexedDataTree->getFirstIndex();