8#ifndef HPP_ALIB_MONOMEM_STRINGTREE
9#define HPP_ALIB_MONOMEM_STRINGTREE 1
11#if !defined (HPP_ALIB_MONOMEM_MONOMEM)
17#include "alib/monomem/detail/stringtreebase.inl"
19namespace alib {
namespace monomem {
111template<
typename TChar=
character,
integer TLocalCapacity= 32>
120 strings::TString <TChar> );
138 template<
typename TTree>
145 if constexpr (TLocalCapacity <= 0)
148 node.name.key.CopyTo( buffer );
155 node.name.storage.DbgDisableBufferReplacementWarning();
156 ALIB_DBG(
const TChar* internalBuffer= node.name.storage.Buffer(); )
157 node.name.storage.Append(key);
159 if( internalBuffer != node.name.storage.Buffer() )
179 template<
typename TTree>
181 void FreeNode( TTree& tree,
typename TTree::Node& node )
184 if constexpr (TLocalCapacity <= 0)
185 delete[] node.name.key.Buffer();
187 node.name.storage.~TLocalString();
218template<
typename TChar=
character>
245 template<
typename TTree>
271 template<
typename TTree>
273 void FreeNode( TTree& tree,
typename TTree::Node& node )
311template<
typename TChar=
character>
340 template<
typename TTree>
344 node.name.storage= tree.nodeTable.GetAllocator()->EmplaceString( node.name.key );
365 template<
typename TTree>
367 void FreeNode( TTree& tree,
typename TTree::baseNode& node )
619 #if !defined(ALIB_DOX)
625 friend TNodeMaintainer;
628 using baseNodeKey =
typename basetree::NodeKey;
629 using baseNodeBase =
typename basetree::NodeBase;
630 using baseNode =
typename basetree::Node;
631 using baseCursor =
typename basetree::CursorBase;
632 using baseConstCursor =
typename basetree::ConstCursorBase;
684 template<
bool TConst>
687 #if !defined(ALIB_DOX)
737 :
TCursor{ src.tree, src.node }
743 :
TCursor{ src.tree, src.node }
771 return cmCursor::node == other.node
772 && cmCursor::tree == other.tree;
781 return !((*this) == other);
810 return cmCursor::node !=
nullptr;
831 return TCursor(cmCursor::tree, cmCursor::node);
846 cmCursor::node = &cmCursor::tree->root.root;
863 "Invalid StringTree::Cursor.")
864 return TCursor(cmCursor::tree, cmCursor::node->parent);
876 "Invalid StringTree::Cursor.")
877 cmCursor::node = cmCursor::node->parent;
908 cmCursor::node = cmCursor::node->next();
911 cmCursor::node =
nullptr;
941 cmCursor::node= cmCursor::node->prev();
944 cmCursor::node=
nullptr;
972 cmCursor::node= cmCursor::node->children.first();
975 cmCursor::node=
nullptr;
1004 cmCursor::node= cmCursor::node->children.last();
1007 cmCursor::node=
nullptr;
1029 return TCursor(cmCursor::tree, cmCursor::node->findChild(cmCursor::tree, name));
1051 cmNode* child= cmCursor::node->findChild( cmCursor::tree, name );
1054 cmCursor::node= child;
1078 template<
typename... TArgs>
1085 return std::make_pair(
TCursor(cmCursor::tree,
nullptr),
true );
1087 auto result= cmCursor::node->findOrCreateChild( cmCursor::tree, name,
1088 std::forward<TArgs>(args)... );
1090 return std::make_pair(
TCursor( cmCursor::tree, result.first ), result.second );
1109 template<
typename... TArgs>
1116 cmCursor::node=
nullptr;
1120 auto result= cmCursor::node->findOrCreateChild( cmCursor::tree, name,
1121 std::forward<TArgs>(args)... );
1123 cmCursor::node= result.first;
1124 return result.second;
1169 cmNode* grandChild= cmCursor::followPath( remainingPath );
1170 return std::make_pair(
TCursor(cmCursor::tree, grandChild), remainingPath );
1184 cmCursor::node= cmCursor::followPath( remainingPath );
1185 return remainingPath;
1204 template<
typename... TArgs>
1209 "MONOMEM/STRINGTREE",
1210 "Invalid StringTree::Cursor given with relative path addressing." )
1212 auto result= cmCursor::followPathCreate( path, std::forward<TArgs>(args)... );
1214 return std::make_pair(
TCursor(cmCursor::tree, result.first), result.second );
1232 template<
typename... TArgs>
1237 "MONOMEM/STRINGTREE",
1238 "Invalid StringTree::Cursor given with relative path addressing." )
1240 auto result= cmCursor::followPathCreate( path, std::forward<TArgs>(args)... );
1241 cmCursor::node= result.first;
1242 return result.second;
1256 return cmCursor::node->name.key;
1267 "StringTree::Cursor is not initialized." )
1268 return *
static_cast<StringTree*
>(cmCursor::tree);
1279 "StringTree::Cursor is not initialized." )
1280 return *
static_cast<const StringTree*
>(cmCursor::tree);
1283 #if defined(ALIB_DOX)
1290 template<
bool TEnableIf= !TConst>
1295 "Root node has no value. Either this operation is unwanted or root node's value\n"
1296 "has to be explicitly set using SetRootNode(...)" )
1297 return static_cast<baseNode*>(
cmCursor::node)->data;
1307 "Root node has no value. Either this operation is unwanted or root node's value\n"
1308 "has to be explicitly set using SetRootNode(...)" )
1309 return static_cast<const baseNode*
>(cmCursor::node)->data;
1320 return cmCursor::node->isRoot();
1331 return cmCursor::node->depth();
1341 return cmCursor::node->qtyChildren != 0;
1352 return cmCursor::node->qtyChildren;
1364 && !cmCursor::node->parent->children.isLast( cmCursor::node );
1376 && !cmCursor::node->parent->children.isFirst( cmCursor::node );
1406 targetString.
Reset();
1408 return cmCursor::node->assemblePath( targetString, cmCursor::node,
nullptr,
1436 targetString.
Reset();
1438 return cmCursor::node->assemblePath( targetString, cmCursor::node, parent.node,
1439 cmCursor::tree->separator );
1471 template<
bool TCheck =
true,
typename... TArgs>
1475 if constexpr (TCheck)
1480 ALIB_WARNING(
"STRINGTREE",
"Illegal child name {!Q}", childName )
1481 return Cursor( baseCursor::tree,
nullptr );
1485 if( baseCursor::node->qtyChildren > 0
1486 && baseCursor::tree->
nodeTable.Contains( baseNodeKey( baseCursor::node, childName) ))
1487 return Cursor( baseCursor::tree,
nullptr );
1490 baseNode* child= &baseCursor::tree->nodeTable.EmplaceUnique( baseCursor::node, childName,
1491 std::forward<TArgs>(args)... )
1493 TNodeMaintainer::InitializeNode( *baseCursor::tree, *child );
1495 baseCursor::node->children.pushEnd( child );
1496 ++baseCursor::node->qtyChildren;
1498 return TCursor( baseCursor::tree, child );
1517 if( baseCursor::node->qtyChildren == 0 )
1520 auto handle= baseCursor::tree->nodeTable.Extract( baseNodeKey( baseCursor::node, childName) );
1521 if( handle.IsEmpty() )
1524 handle.Value().deleteChildren( baseCursor::tree );
1526 TNodeMaintainer::FreeNode( *baseCursor::tree, handle.Value() );
1527 handle.Value().remove();
1529 --baseCursor::node->qtyChildren;
1554 "Invalid StringTree::Cursor." )
1556 "Invalid StringTree::Cursor given for parameter 'child'." )
1557 cmNode* nodeToDelete= child.node;
1559 baseCursor::node->deleteChild( baseCursor::tree, nodeToDelete );
1571 return baseCursor::node->deleteChildren( baseCursor::tree );
1595 if( baseCursor::node->isRoot() )
1596 return baseCursor::node->deleteChildren( baseCursor::tree );
1598 cmNode * child= baseCursor::node;
1599 baseCursor::node= baseCursor::node->parent;
1600 return baseCursor::node->deleteChild( baseCursor::tree, child );
1663 template<
bool TConst>
1704 #if defined(ALIB_DOX)
1781 size_t actDepth =
size_t(-1);
1788 unsigned int recursionDepth =(std::numeric_limits<
unsigned int>::max)();
1794 bool nextIsSorting = false;
1797 bool nextSortingIsDescending = false;
1800 bool nextSortingIsCaseSensitive = false;
1839 void SetPathGeneration( lang::Switch pathGeneration )
1858 unsigned int depth= (std::numeric_limits<unsigned int>::max)() )
1860 initialize( &pTree, &pTree.root.root, depth );
1881 unsigned int depth= (std::numeric_limits<unsigned int>::max)() )
1883 initialize(
static_cast<cmTree*
>( cursor.tree ),
1884 cursor.IsValid() ? cursor.node : &cursor.tree->root.root,
1902 unsigned int depth= (std::numeric_limits<unsigned int>::max)() )
1904 initialize( other.
tree, other.
node, depth );
1914 actDepth= size_t(-1);
1928 return actDepth != size_t(-1);
1958 if( sorting == lang::Switch::Off )
1959 nextIsSorting=
false;
1961 SetSorting(lang::SortOrder::Ascending, lang::Case::Ignore );
1978 lang::Case sensitivity = lang::Case::Ignore )
1980 nextIsSorting =
true;
1981 nextCustomSorter =
nullptr;
1982 nextSortingIsDescending = ( order == lang::SortOrder::Descending );
1983 nextSortingIsCaseSensitive= ( sensitivity == lang:: Case::Sensitive );
1998 nextIsSorting =
true;
1999 nextCustomSorter = customSorterFunction;
2058 "Path generation not activated" )
2079 "Path generation not activated" )
2081 if( targetData == lang::CurrentData::Clear )
2084 if( actPath.IsNotEmpty() )
2085 target << actPath << tree->separator;
2087 return target << node->name.key;
2102 return int(recursionDepth);
2117 "RecursiveIterator not initialized or exceeded (invalid)." )
2118 return int(actDepth);
2137 "RecursiveIterator not initialized or exceeded (invalid)." )
2163 "RecursiveIterator not initialized or exceeded (invalid)." )
2164 auto& nodeToDelete= *node;
2166 return nodeToDelete.parent->deleteChild( tree, &nodeToDelete );
2181 if( actPath.IsNotNull() )
2184 if( newnode->isRoot() )
2185 actPath << tree->separator;
2189 if( newnode->qtyChildren )
2191 recursionDepth= depth;
2192 actDepth= size_t(-1);
2196 actDepth= size_t( -1 );
2207 if( stack.size() == actDepth )
2208 stack.emplace_back();
2210 auto& rd= stack[actDepth];
2211 rd.customSorter = nextCustomSorter;
2212 rd.isSorting = nextIsSorting;
2213 rd.sortingIsDescending = nextSortingIsDescending;
2214 rd.sortingIsCaseSensitive= nextSortingIsCaseSensitive;
2219 rd.childrenUnsorted= &node->children;
2220 node= (rd.actChild.unsorted= rd.childrenUnsorted->first());
2225 rd.childrenSorted.clear();
2226 rd.childrenSorted.reserve(
size_t( node->qtyChildren ) );
2227 auto* copyIt= node->children.first();
2228 while( copyIt != &node->children.hook )
2230 rd.childrenSorted.emplace_back( copyIt );
2231 copyIt= copyIt->next();
2235 if( rd.customSorter )
2237 std::sort( rd.childrenSorted.begin(), rd.childrenSorted.end(),
2241 return rd.customSorter( cmCursor(tree, lhs),
2242 cmCursor(tree, rhs) );
2248 std::sort( rd.childrenSorted.begin(), rd.childrenSorted.end(),
2251 int compResult= rd.sortingIsCaseSensitive
2252 ? lhs->name.key. template CompareTo<true, lang::Case::Sensitive>(rhs->name.key)
2253 : lhs->name.key. template CompareTo<true, lang::Case::Ignore >(rhs->name.key);
2254 return rd.sortingIsDescending ? compResult > 0
2261 rd.actChild.sorted= 0;
2262 node= rd.childrenSorted[0];
2280 "Invalid iterator" )
2284 &&
static_cast<unsigned int>( actDepth ) < recursionDepth
2285 && node->qtyChildren )
2287 if( actPath.IsNotNull() )
2289 if( actPath.IsNotEmpty()
2290 && (actPath.Length() != 1 || actPath.CharAtStart() != tree->separator ) )
2291 actPath << tree->separator;
2293 actPath << node->name.key;
2297 if( stack.size() == actDepth + 1 )
2298 stack.emplace_back();
2310 bool foundNextChild;
2328 if( foundNextChild )
2339 if( actPath.IsNotEmpty() )
2344 lastChar= actPath.CharAtEnd<
false>();
2345 actPath.DeleteEnd<
false>( 1 );
2347 while( lastChar != tree->separator && actPath.IsNotEmpty() );
2352 actDepth= size_t(-1);
2354 || (actPath.Length() == 1 && actPath.CharAtStart() == tree->separator) )
2359 return actDepth != size_t(-1);
2381 : basetree( allocator, pathSeparator )
2391 : basetree( allocator, pRecycler, pathSeparator )
2401 for(
auto&
node : basetree::nodeTable )
2402 TNodeMaintainer::FreeNode( *
this, *
static_cast<baseNode*
>(&
node) );
2405 "The root node's value object was set but not deleted before destruction of this StringTree.\n"
2406 "Possible memory leak! To suppress this warning call DeleteRootValue() prior to destruction.\n"
2407 "In case this is not necessary (because the value type does not leak if not destructed),\n"
2408 " emplace it in macro ALIB_DBG() to remove the call in release compilations." )
2420 basetree::nodeTable.SetAllocatorPostConstruction( pAllocator );
2430 return basetree::nodeTable.GetAllocator();
2448 template<
typename... TArgs>
2453 "Root node value is set without prior deletion. Possible memory leak (depending on allocation \n"
2454 "of template type T). This warning is only printed on the first overwrite." )
2455 ++basetree::dbgRootDataSet;
2458 new (&basetree::root.root.data) T( std::forward<TArgs>(args)... );
2470 "Deletion of root node data without prior setting (our double deletion)." )
2471 --basetree::dbgRootDataSet;
2473 basetree::root.root.data.~T();
2488 for(
auto&
node : basetree::nodeTable )
2489 TNodeMaintainer::FreeNode( *
this, *
static_cast<baseNode*
>(&
node) );
2491 basetree::nodeTable.Clear();
2494 basetree::root.root.children.reset();
2495 basetree::root.root.qtyChildren= 0;
2512 for(
auto&
node : basetree::nodeTable )
2513 TNodeMaintainer::FreeNode( *
this, *
static_cast<baseNode*
>(&
node) );
2515 basetree::nodeTable.Reset();
2518 basetree::root.root.children.reset();
2519 basetree::root.root.qtyChildren= 0;
2536 return basetree::nodeTable.RecyclablesCount();
2549 return basetree::nodeTable.Size();
2559 return basetree::nodeTable.Size() == 0;
2576 basetree::nodeTable.ReserveRecyclables( expected, reference );
2588 return basetree::nodeTable;
2600 return basetree::nodeTable;
2609 return Cursor(
this, &(basetree::root.
root) );
2627template<
typename TChar,
integer TLocalCapacity= 32>
2631template<
typename TChar>
2635template<
typename TChar>
TCursor CreateChild(const NameType &childName, TArgs &&... args) const
TCursor() noexcept=default
ATMP_IF_T_F(!TConst, baseNodeBase, const baseNodeBase) cmNode
const StringTree & Tree() const
TCursor(const TCursor &src) noexcept
TCursor & operator=(TCursor &&) noexcept=default
bool DeleteChild(const NameType &childName) const
std::pair< TCursor, bool > CreateChildIfNotExistent(const NameType &name, TArgs &&... args)
AString & AssemblePath(AString &targetString, const TCursor &parent, lang::CurrentData targetData=lang::CurrentData::Clear) const
const NameType & Name() const
AString & AssemblePath(AString &targetString, lang::CurrentData targetData=lang::CurrentData::Clear) const
ATMP_IF_T_F(!TConst, StringTree, const StringTree) TStringTree
bool operator!=(const TCursor &other) const
bool GoToCreateChildIfNotExistent(const NameType &name, TArgs &&... args)
uinteger DeleteChildren() const
bool HasNextSibling() const
ATMP_IF_T_F(!TConst, basetree, const basetree) cmTree
TCursor LastChild() const
uinteger CountChildren() const
TCursor NextSibling() const
TCursor FirstChild() const
TCursor & operator=(const TCursor &) noexcept=default
TCursor(cmTree *pTree, cmNode *pNode) noexcept
TCursor Child(const NameType &name) const
bool HasPreviousSibling() const
std::pair< TCursor, integer > CreatePathIfNotExistent(const NameType &path, TArgs &&... args)
bool operator==(const TCursor &other) const
integer GoToCreatedPathIfNotExistent(const NameType &path, TArgs &&... args)
TCursor PreviousSibling() const
SubstringType GoToTraversedPath(const NameType &path)
bool GoToChild(const NameType &name)
std::pair< TCursor, SubstringType > TraversePath(const NameType &path) const
TCursor(TCursor &&src) noexcept
void DeleteChild(TCursor &child) const
ATMP_IF_T_F(!TConst, baseCursor, baseConstCursor) cmCursor
bool GoToPreviousSibling()
const NameType & CurrentPath() const
void Initialize(cmCursor cursor, unsigned int depth=(std::numeric_limits< unsigned int >::max)())
ATMP_IF_T_F(!TConst, baseNodeBase, const baseNodeBase) cmNode
ATMP_IF_T_F(!TConst, Cursor, ConstCursor) cmCursor
void SetSorting(lang::SortOrder order=lang::SortOrder::Ascending, lang::Case sensitivity=lang::Case::Ignore)
AString & FullPath(AString &target, lang::CurrentData targetData=lang::CurrentData::Clear) const
void initialize(cmTree *pTree, cmNode *newnode, unsigned int depth)
void SetSorting(lang::Switch sorting)
void Initialize(cmTree &pTree, unsigned int depth=(std::numeric_limits< unsigned int >::max)())
ATMP_IF_T_F(!TConst, StringTree, const StringTree) cmTree
void Initialize(const TRecursiveIterator &other, unsigned int depth=(std::numeric_limits< unsigned int >::max)())
int RequestedDepth() const
void SetSorting(bool(*customSorterFunction)(const Cursor &, const Cursor &))
const auto & NodeTable() const
MonoAllocator * GetAllocator()
integer RecyclablesCount() const
StringTree(MonoAllocator *allocator, CharacterType pathSeparator, TSharedRecycler &pRecycler)
typename TNodeMaintainer::CharacterType CharacterType
void ConstructRootValue(TArgs &&... args)
const ConstCursor Root() const
void SetAllocatorPostConstruction(MonoAllocator *pAllocator)
StringTree(MonoAllocator *allocator, CharacterType pathSeparator)
TCursor< true > ConstCursor
typename strings::TSubstring< CharacterType > SubstringType
typename strings::TString< CharacterType > NameType
void ReserveRecyclables(integer expected, lang::ValueReference reference)
typename basetree::TSharedRecycler TSharedRecycler
#define ATMP_IF_T_F( Cond, T, F)
#define ALIB_WARNING(...)
#define ALIB_ASSERT_MODULE(modulename)
#define ALIB_ASSERT_ERROR(cond,...)
#define ALIB_ASSERT_WARNING(cond,...)
#define ALIB_ASSERT(cond)
#define ATMP_T_IF(T, Cond)
@ Clear
Chooses to clear existing data.
ALIB_API uinteger DbgStatsStringTreeNameOverflows
ALIB_API uinteger DbgStatsStringTreeNames
lang::uinteger uinteger
Type alias in namespace alib.
constexpr CString EmptyString()
constexpr String NullString()
characters::character character
Type alias in namespace alib.
lang::integer integer
Type alias in namespace alib.
static void InitializeNode(TTree &tree, typename TTree::Node &node)
ATMP_IF_T_F((TLocalCapacity > 0), strings::TLocalString< TChar ALIB_COMMA TLocalCapacity >, strings::TString< TChar >) NameStringType
static void FreeNode(TTree &tree, typename TTree::Node &node)
static void InitializeNode(TTree &tree, typename TTree::Node &node)
static void FreeNode(TTree &tree, typename TTree::baseNode &node)
static void InitializeNode(TTree &tree, typename TTree::Node &node)
static void FreeNode(TTree &tree, typename TTree::Node &node)
std::vector< cmNode * > childrenSorted
RecursionData() noexcept=default
union alib::monomem::StringTree::TRecursiveIterator::RecursionData::@5 actChild
lang::BidiListHelper< baseNodeBase > * childrenUnsorted
bool sortingIsCaseSensitive
bool checkChildName(const NameType &name) const
monomem::HashTable< Node, Node, NodeKey, void, typename NodeKey::Hash, typename NodeKey::EqualTo, typename NodeKey::Access, lang::Caching::Enabled, TRecycling > nodeTable
Node root
Full version of the root node, without initialization of member T.