97template<
typename TChar=
character,
integer TLocalCapacity= 32>
106 strings::TString <TChar> >;
122 template<
typename TTree>
128 if constexpr (TLocalCapacity <= 0) {
130 node.name.key.CopyTo( buffer );
136 node.name.storage.DbgDisableBufferReplacementWarning();
137 ALIB_DBG(
const TChar* internalBuffer= node.name.storage.Buffer(); )
138 node.name.storage.Append(key);
140 if( internalBuffer != node.name.storage.Buffer() )
157 template<
typename TTree>
159 void FreeNode(
typename TTree::Node& node, TTree& tree ) {
161 if constexpr (TLocalCapacity <= 0)
162 delete[] node.name.key.Buffer();
164 node.name.storage.~TLocalString();
193template<
typename TChar=
character>
218 template<
typename TTree>
220 void InitializeNode(
typename TTree::Node& node, TTree& tree ) { (void) node; (void) tree; }
238 template<
typename TTree>
240 void FreeNode( TTree::Node& node, TTree& tree ) { (void) node; (void) tree; }
270template<
typename TChar=
character>
297 template<
typename TTree>
300 { node.name.storage.Allocate( tree.nodeTable.GetAllocator(), node.name.key ); }
318 template<
typename TTree>
320 void FreeNode(
typename TTree::baseNode& node, TTree& tree ) { (void) node; (void) tree; }
568template<
typename TAllocator,
571 Recycling TRecycling = Recycling::Private>
581 using baseNodeKey =
typename basetree::NodeKey;
582 using baseNodeBase =
typename basetree::NodeBase;
583 using baseNode =
typename basetree::Node;
584 using baseCursor =
typename basetree::CursorBase;
585 using baseConstCursor =
typename basetree::ConstCursorBase;
667 {
return value==other.value; }
704 template<
bool TConst>
712 #if ALIB_DEBUG_CRITICAL_SECTIONS
713 #define DCS ALIB_DCS_WITH(cmCursor::tree->nodeTable.dcs)
714 #define DCSSHRD ALIB_DCS_SHARED_WITH(cmCursor::tree->nodeTable.dcs)
724 using cmTree = std::conditional_t<!TConst, basetree, const basetree>;
728 using cmNode = std::conditional_t<!TConst, baseNode, const baseNode>;
732 using cmCursor = std::conditional_t<!TConst, baseCursor, baseConstCursor>;
745 "Invalid StringTree::Cursor: No binding with a StringTree. "
746 "(Probably default-constructed.)")
754 "Invalid StringTree::Cursor not representing a node of the assigned tree." )
761 using TStringTree = std::conditional_t<!TConst, StringTree, const StringTree>;
772 :
TCursor{ src.node, src.tree } {}
777 :
TCursor{ src.node, src.tree } {}
801 return cmCursor::node == other.node
802 && cmCursor::tree == other.tree;
842 bool IsValid()
const {
return cmCursor::node !=
nullptr; }
856 return TCursor(cmCursor::tree, &cmCursor::tree->
root.root);
863 cmCursor::node = &cmCursor::tree->root.root;
877 return TCursor(
static_cast<cmNode*
>(cmCursor::node->parent), cmCursor::tree);
886 cmCursor::node =
static_cast<cmNode*
>(cmCursor::node->parent);
911 cmCursor::node =
static_cast<cmNode*
>(cmCursor::node->next());
914 cmCursor::node =
nullptr;
938 cmCursor::node=
static_cast<cmNode*
>(cmCursor::node->prev());
941 cmCursor::node=
nullptr;
963 cmCursor::node=
static_cast<cmNode*
>(cmCursor::node->children.first());
966 cmCursor::node=
nullptr;
989 cmCursor::node=
static_cast<cmNode*
>(cmCursor::node->children.last());
992 cmCursor::node=
nullptr;
1010 return TCursor(
static_cast<cmNode*
>(cmCursor::node->findChild(cmCursor::tree, name)),
1030 cmNode* child=
static_cast<cmNode*
>(cmCursor::node->findChild( cmCursor::tree, name ));
1032 cmCursor::node= child;
1054 template<
typename... TArgs>
1056 TArgs&&... args ) {DCS
1059 return std::make_pair(
TCursor(cmCursor::tree,
nullptr),
true );
1061 auto result= cmCursor::node->findOrCreateChild( cmCursor::tree, name,
1062 std::forward<TArgs>(args)... );
1064 return std::make_pair(
TCursor( cmCursor::tree, result.first ), result.second );
1081 template<
typename... TArgs>
1085 cmCursor::node=
nullptr;
1089 auto result= cmCursor::node->findOrCreateChild( cmCursor::tree, name,
1090 std::forward<TArgs>(args)... );
1092 cmCursor::node=
static_cast<cmNode*
>(result.first);
1093 return result.second;
1136 cmNode* grandChild= cmCursor::followPath( remainingPath );
1137 return std::make_pair(
TCursor(grandChild, cmCursor::tree), remainingPath );
1148 cmCursor::node= cmCursor::followPath( remainingPath );
1149 return remainingPath;
1165 template<
typename... TArgs>
1167 TArgs&&... args ) {DCS
1170 "STRINGTREE",
"Invalid StringTree::Cursor given with relative path addressing." )
1172 auto result= cmCursor::followPathCreate( path, std::forward<TArgs>(args)... );
1174 return std::make_pair(
TCursor(
static_cast<cmNode*
>(result.first), cmCursor::tree),
1191 template<
typename... TArgs>
1193 TArgs&&... args ) {DCS
1196 "STRINGTREE",
"Invalid StringTree::Cursor given with relative path addressing." )
1198 auto result= cmCursor::followPathCreate( path, std::forward<TArgs>(args)... );
1199 cmCursor::node=
static_cast<cmNode*
>(result.first);
1200 return result.second;
1216 template<
typename TParent= StringTree>
1217 requires std::derived_from<TParent, StringTree>
1227 template<
bool TRequires= !TConst>
1232 "Root node has no value. Either this operation is unwanted or root node's value\n"
1233 "has to be explicitly set using ConstructRootValue(...)" )
1234 return static_cast<baseNode*
>(cmCursor::node)->data;
1244 "Root node has no value. Either this operation is unwanted or root node's value\n"
1245 "has to be explicitly set using ConstructRootValue(...)" )
1246 return static_cast<const baseNode*
>(cmCursor::node)->data;
1255 template<
bool TRequires= !TConst>
1260 "Root node has no value. Either this operation is unwanted or root node's value\n"
1261 "has to be explicitly set using ConstructRootValue(...)" )
1262 return &
static_cast<baseNode*
>(cmCursor::node)->data;
1271 "Root node has no value. Either this operation is unwanted or root node's value\n"
1272 "has to be explicitly set using ConstructRootValue(...)" )
1273 return &
static_cast<const baseNode*
>(cmCursor::node)->data;
1282 template<
bool TRequires= !TConst>
1287 "Root node has no value. Either this operation is unwanted or root node's value\n"
1288 "has to be explicitly set using ConstructRootValue(...)" )
1289 return static_cast<baseNode*
>(cmCursor::node)->data;
1299 "Root node has no value. Either this operation is unwanted or root node's value\n"
1300 "has to be explicitly set using ConstructRootValue(...)" )
1301 return static_cast<const baseNode*
>(cmCursor::node)->data;
1315 return cmCursor::node->depth();
1334 "Given node belongs to a different StringTree." )
1335 return cmCursor::node->distance( other.node );
1343 return cmCursor::node->qtyChildren != 0;
1352 return cmCursor::node->qtyChildren;
1362 && !cmCursor::node->parent->children.isLast( cmCursor::node );
1372 && !cmCursor::node->parent->children.isFirst( cmCursor::node );
1402 targetString.
Reset();
1404 return cmCursor::node->assemblePath( targetString, cmCursor::node,
nullptr,
1432 targetString.
Reset();
1433 return cmCursor::node->assemblePath( targetString, cmCursor::node, parent.node,
1434 cmCursor::tree->separator );
1464 template<
typename TCheck =
CHK,
typename... TArgs>
1467 if constexpr ( TCheck::value ) {
1470 ALIB_WARNING(
"STRINGTREE",
"Illegal child name \"{}\"", childName )
1471 return Cursor(
nullptr, baseCursor::tree );
1475 if( baseCursor::node->qtyChildren > 0
1476 && baseCursor::tree->
nodeTable.Contains( baseNodeKey( baseCursor::node, childName) ))
1477 return Cursor(
nullptr, baseCursor::tree );
1480 baseNode* child= &baseCursor::tree->nodeTable.EmplaceUnique( baseCursor::node, childName,
1481 std::forward<TArgs>(args)... )
1483 TNodeHandler::InitializeNode( *child, *baseCursor::tree );
1485 baseCursor::node->children.pushEnd( child );
1486 ++baseCursor::node->qtyChildren;
1487 return TCursor( child, baseCursor::tree );
1503 if( baseCursor::node->qtyChildren == 0 )
1506 auto handle= baseCursor::tree->nodeTable.Extract( baseNodeKey( baseCursor::node, childName) );
1507 if( handle.IsEmpty() )
1509 handle.Value().deleteChildren( baseCursor::tree );
1510 TNodeHandler::FreeNode( handle.Value(), *baseCursor::tree );
1511 handle.Value().remove();
1513 --baseCursor::node->qtyChildren;
1534 cmNode* nodeToDelete= child.node;
1536 return baseCursor::node->deleteChild( baseCursor::tree, nodeToDelete );
1546 return baseCursor::node->deleteChildren( baseCursor::tree );
1568 if( baseCursor::node->isRoot() )
1569 return baseCursor::node->deleteChildren( baseCursor::tree );
1571 cmNode * child= baseCursor::node;
1572 baseCursor::node=
static_cast<cmNode*
>(baseCursor::node->parent);
1573 return baseCursor::node->deleteChild( baseCursor::tree, child );
1595 #if ALIB_DEBUG_CRITICAL_SECTIONS
1598 #define DCS ALIB_DCS_WITH(basetree::nodeTable.dcs)
1599 #define DCSSHRD ALIB_DCS_SHARED_WITH(basetree::nodeTable.dcs)
1607 : basetree( allocator, pathSeparator ) {
1608 #if ALIB_DEBUG_CRITICAL_SECTIONS
1609 basetree::nodeTable.dcs.DCSName=
"StringTree";
1616 template<
typename TSharedRecycler= SharedRecyclerType>
1617 requires(!std::same_as<TSharedRecycler, void>)
1619 : basetree( pRecycler, pathSeparator ) {
1620 #if ALIB_DEBUG_CRITICAL_SECTIONS
1621 basetree::nodeTable.dcs.DCSName=
"StringTree";
1628 for(
auto& node : basetree::nodeTable )
1629 TNodeHandler::FreeNode( *
static_cast<baseNode*
>(&node), *
this );
1632 "Possible memory leak! The root node's value object was set but not deleted before\n"
1633 "destruction of this StringTree. To suppress this warning call DestructRootValue()\n"
1634 "before destruction. In case this is not necessary (because the stored type does not\n"
1635 "leak if not destructed), emplace it in macro ALIB_DBG() to remove the call in\n"
1645 #if ALIB_DEBUG_CRITICAL_SECTIONS
1659 #if ALIB_DEBUG_CRITICAL_SECTIONS
1663 void DbgSetDCSName(
const char* name)
const { basetree::nodeTable.dcs.DCSName= name; }
1679 template<
typename... TArgs>
1683 "Root node value is set without prior deletion. Possible memory leak (depending on\n "
1684 "allocation of template type T). This warning is only printed on the first overwrite.")
1685 ++basetree::dbgRootDataSet;
1688 new (&basetree::root.root.data) T( std::forward<TArgs>(args)... );
1698 "Deletion of root node data without prior setting (or double deletion)." )
1699 --basetree::dbgRootDataSet;
1701 basetree::root.root.data.~T();
1714 for(
auto& node : basetree::nodeTable )
1715 TNodeHandler::FreeNode( *
static_cast<baseNode*
>(&node), *
this );
1716 basetree::nodeTable.Clear();
1719 basetree::root.root.children.reset();
1720 basetree::root.root.qtyChildren= 0;
1737 for(
auto& node : basetree::nodeTable )
1738 TNodeHandler::FreeNode( *
static_cast<baseNode*
>(&node), *
this );
1741 basetree::nodeTable.Reset();
1742 basetree::root.root.children.reset();
1743 basetree::root.root.qtyChildren= 0;
1770 bool IsEmpty()
const {
return basetree::nodeTable.Size() == 0; }
1782 { basetree::nodeTable.ReserveRecyclables( qty, reference ); }
1796 const auto&
NodeTable()
const {
return basetree::nodeTable; }
1810 {
return Cursor(
reinterpret_cast<typename basetree::Node*
>(handle.value),
this ); }
1816 {
return ConstCursor(
reinterpret_cast<typename basetree::Node*
>(handle.value),
this ); }
1819 #if ALIB_DEBUG_CRITICAL_SECTIONS
1830template<
typename TChar,
integer TLocalCapacity= 32>
1834template<
typename TChar>
1838template<
typename TChar>
1842template<
typename TAllocator,
1845 Recycling TRecycling = Recycling::Private >
#define ALIB_WARNING(domain,...)
#define ALIB_ASSERT_WARNING(cond, domain,...)
#define ALIB_ASSERT_ERROR(cond, domain,...)
TCursor() noexcept=default
SubstringType GoTo(const NameType &path)
int Distance(const TCursor< true > &other) const
TCursor NextSibling() const
TCursor(cmNode *pNode, cmTree *pTree) noexcept
bool operator!=(const TCursor &other) const
std::pair< TCursor, SubstringType > operator()(const NameType &path) const
TCursor & operator=(const TCursor &) noexcept=default
int GoToCreatedPathIfNotExistent(const NameType &path, TArgs &&... args)
const T * operator->() const
void dbgCheckTree() const
TCursor CreateChild(const NameType &childName, TArgs &&... args) const
std::conditional_t<!TConst, StringTree, const StringTree > TStringTree
strings::TAString< typename cmTree::CharacterType, lang::HeapAllocator > & AssemblePath(strings::TAString< typename cmTree::CharacterType > &targetString, const TCursor< true > &parent, lang::CurrentData targetData=lang::CurrentData::Clear) const
const T & operator*() const
uinteger DeleteChild(TCursor &child) const
TCursor FirstChild() const
std::conditional_t<!TConst, basetree, const basetree > cmTree
TCursor PreviousSibling() const
bool HasNextSibling() const
TCursor(TCursor &&src) noexcept
bool GoToPreviousSibling()
ConstCursorHandle Export() const
std::conditional_t<!TConst, baseNode, const baseNode > cmNode
const NameType & Name() const
TCursor LastChild() const
TCursor Child(const NameType &name) const
bool GoToCreateChildIfNotExistent(const NameType &name, TArgs &&... args)
bool HasPreviousSibling() const
bool GoToChild(const NameType &name)
std::pair< TCursor, integer > CreatePathIfNotExistent(const NameType &path, TArgs &&... args)
uinteger CountChildren() const
std::conditional_t<!TConst, baseCursor, baseConstCursor > cmCursor
void dbgCheckTreeAndNode() const
bool operator==(const TCursor &other) const
std::pair< TCursor, bool > CreateChildIfNotExistent(const NameType &name, TArgs &&... args)
TCursor & operator=(TCursor &&) noexcept=default
bool DeleteChild(const NameType &childName) const
uinteger DeleteChildren() const
strings::TAString< typename cmTree::CharacterType, lang::HeapAllocator > & AssemblePath(strings::TAString< typename cmTree::CharacterType > &targetString, lang::CurrentData targetData=lang::CurrentData::Clear) const
void ReserveRecyclables(integer qty, lang::ValueReference reference)
integer RecyclablesCount() const
lang::DbgCriticalSections & DbgGetDCS() const
constexpr CharacterType Separator() const noexcept
const auto & NodeTable() const
TCursor< true > ConstCursor
The constant version of type TCursor<TConst>.
typename StringTreeNamesAlloc< character >::CharacterType CharacterType
Cursor ImportCursor(CursorHandle handle)
const ConstCursor Root() const
Cursor createCursor(baseNode &node)
typename strings::TSubstring< CharacterType > SubstringType
strings::TString< CharacterType > NameType
void DbgSetDCSName(const char *name) const
AllocatorType & GetAllocator() noexcept
TCursor< false > Cursor
The mutable version of type TCursor<TConst>.
StringTree(AllocatorType &allocator, CharacterType pathSeparator)
StringTreeNamesAlloc< character > HandlerType
StringTree(CharacterType pathSeparator, TSharedRecycler &pRecycler)
MonoAllocator AllocatorType
void ConstructRootValue(TArgs &&... args)
ConstCursor ImportCursor(ConstCursorHandle handle) const
typename basetree::SharedRecyclerType SharedRecyclerType
TChar CharAtStart() const
uinteger DBG_STATS_STRINGTREE_NAMES
uinteger DBG_STATS_STRINGTREE_NAME_OVERFLOWS
@ Clear
Chooses to clear existing data.
ValueReference
Denotes if a value is interpreted as an absolute or relative number.
lang::integer integer
Type alias in namespace alib.
containers::StringTreeNamesStatic< TChar > StringTreeNamesStatic
Type alias in namespace alib.
containers::Recycling Recycling
Type alias in namespace alib.
containers::StringTree< TAllocator, T, TNodeHandler, TRecycling > StringTree
Type alias in namespace alib.
containers::StringTreeNamesAlloc< TChar > StringTreeNamesAlloc
Type alias in namespace alib.
lang::uinteger uinteger
Type alias in namespace alib.
containers::StringTreeNamesDynamic< TChar, TLocalCapacity > StringTreeNamesDynamic
Type alias in namespace alib.
strings::TString< TChar > NameStringType
The string-type of a node's name.
static void FreeNode(typename TTree::baseNode &node, TTree &tree)
static void InitializeNode(typename TTree::Node &node, TTree &tree)
TChar CharacterType
The character type that the StringTree uses for child name and path strings.
std::conditional_t<(TLocalCapacity > 0), strings::TLocalString< TChar, TLocalCapacity >, strings::TString< TChar > > NameStringType
The string-type of a node's name.
TChar CharacterType
The character type that the StringTree uses for child name and path strings.
static void InitializeNode(typename TTree::Node &node, TTree &tree)
static void FreeNode(typename TTree::Node &node, TTree &tree)
static void FreeNode(TTree::Node &node, TTree &tree)
TChar CharacterType
The character type that the StringTree uses for child name and path strings.
static void InitializeNode(typename TTree::Node &node, TTree &tree)
strings::TString< TChar > NameStringType
The string-type of a node's name.
A handle type used with methods #"TCursor::Export" and #"ImportCursor".
bool operator==(const CursorHandle &other) const noexcept
ConstCursorHandle(const CursorHandle &mutableHandle)
ConstCursorHandle()=default
Defaulted default constructor.
bool IsValid() const noexcept
uinteger value
The encapsulated value.
bool operator==(const ConstCursorHandle &other) const noexcept
ConstCursorHandle(uinteger pValue)
uinteger value
The encapsulated value.
bool IsValid() const noexcept
bool operator==(const CursorHandle &other) const noexcept
RootNodeSpacer root
The root node.
HashTable< TAllocator, typename NodeKey::ValueDescriptor, typename NodeKey::Hash, typename NodeKey::EqualTo, lang::Caching::Enabled, TRecycling > nodeTable
bool checkChildName(const NameType &name) const
TAllocator & GetAllocator() const noexcept