VR-Engage  2.2
Loading...
Searching...
No Matches
treeClass.h
Go to the documentation of this file.
1/*******************************************************************************
2** Copyright (c) 2025 MAK Technologies, Inc.
3** All rights reserved.
4*******************************************************************************/
5
6//! \file treeClass.h
7//! \ingroup vreUtil
8//! \brief Provides a generic hierarchical tree structure implementation
9//!
10//! This file defines the DtTreeClass template which provides a robust tree structure
11//! implementation for building parent-child hierarchies in the VREngage system.
12//! It supports owned and unowned children, name-based lookups, and various tree
13//! manipulation operations.
14
15#pragma once
16#include "vreUtil/baseClass.h"
17
18#include "vreUtil/logger.h"
19
20#include <memory>
21#include <functional>
22#include <list>
23#include <map>
24
25namespace makVre
26{
27
28//! \brief Template class implementing a tree structure with parent-child relationships
29//! \tparam SELF_T The derived class type (CRTP pattern)
30//! \tparam SUPER_T The base class type, defaults to DtSpObject
31//!
32//! This class provides a comprehensive implementation of a tree data structure
33//! with smart pointer ownership management, child lookup by name, and various
34//! traversal capabilities. It's designed to be used as a base class for objects
35//! that need to exist in hierarchical relationships.
36template <class SELF_T, class SUPER_T = DtSpObject>
37class DtTreeClass : public DtSpSubClass<SELF_T, SUPER_T>
38{
39public:
40 //! \brief Shared pointer type for this class
41 using Sptr = std::shared_ptr<SELF_T>;
42 //! \brief Function type for child traversal callbacks
43 using ForChildFn = std::function<bool(Sptr child)>;
44 //! \brief Function type for child search predicates
45 using FindChildFn = std::function<bool(Sptr child)>;
46
47 //! \brief Default constructor
48 //!
49 //! Creates a new tree node with ownership of children enabled by default
51 : myOwnsChildren(true)
52 {
53 }
54
55 //! \brief Virtual destructor
56 //!
57 //! Removes all children when the node is destroyed
58 virtual ~DtTreeClass() override { removeAllChildren(); }
59
60 //! \brief Sets whether this node owns its children
61 //! \param owns True if this node should own its children, false otherwise
62 //!
63 //! When a node owns its children, it maintains strong references to them,
64 //! preventing their destruction as long as the parent exists
65 virtual void setOwnsChildren(bool owns) { myOwnsChildren = owns; }
66
67 //! \brief Checks if this node owns its children
68 //! \return True if this node owns its children, false otherwise
69 virtual bool ownsChildren() { return myOwnsChildren; }
70
71 //! \brief Adds a child to this node
72 //! \param child Shared pointer to the child node to add
73 //! \return True if the child was added successfully, false otherwise
74 //!
75 //! This method adds a child to this node if:
76 //! - The child is not null
77 //! - The child is not already a child of this node
78 //! - The child does not already have a parent
79 //!
80 //! The child is added to either the owned or unowned list based on
81 //! the current ownership setting of this node.
82 virtual bool addChild(Sptr child)
83 {
85
86 if (!child)
87 {
88 LOG_WARN("UTIL") << "Cannot add null child ptr." << std::endl;
89 return false;
90 }
91
92 if (isChild(child))
93 {
94 return true;
95 }
96
97 if (child->parent())
98 {
99 return false;
100 }
101
102 if (ownsChildren())
103 {
104 myOwnedChildren.emplace_back(child);
105 }
106 else
107 {
108 myUnownedChildren.emplace_back(child);
109 }
110
111 child->setParent(this->self());
112
113 return true;
114 }
115
116 //! \brief Removes a child from this node
117 //! \param child Shared pointer to the child node to remove
118 //! \return True if the child was removed successfully, false if not found
119 //!
120 //! This method searches for the child in both the owned and unowned
121 //! children lists and removes it if found. It also clears the parent
122 //! reference from the child.
123 virtual bool removeChild(Sptr child)
124 {
125 bool found = false;
126 {
127 auto findIt = myOwnedChildren.begin();
128 for (; findIt != myOwnedChildren.end(); ++findIt)
129 {
130 if (*findIt == child)
131 {
132 myOwnedChildren.erase(findIt);
133 found = true;
134 break;
135 }
136 }
137 }
138 if (!found)
139 {
140 auto findIt = myUnownedChildren.begin();
141 for (; findIt != myUnownedChildren.end(); ++findIt)
142 {
143 if (findIt->lock() == child)
144 {
145 myUnownedChildren.erase(findIt);
146 found = true;
147 break;
148 }
149 }
150 }
151
152 if (found && child->parent() != this->self())
153 {
154 LOG_WARN("UTIL") << "Parent of child did not match this." << std::endl;
155 }
156
157 if (child->parent() == this->self())
158 {
159 child->setParent(Sptr());
160 }
161
163
164 return found;
165 }
166
167 //! \brief Removes all children from this node
168 //!
169 //! This method removes all children from this node, converting owned children
170 //! to unowned first to prevent their destruction during the process. It then
171 //! clears the parent reference from all children and clears internal lists.
172 virtual void removeAllChildren()
173 {
174 // First convert all owned children to unowned to prevent destruction
175 for (auto child : myOwnedChildren)
176 {
177 myUnownedChildren.emplace_back(child);
178 }
179
180 myOwnedChildren.clear();
182
183 // Clear parent reference from all children
184 for (auto child : myUnownedChildren)
185 {
186 child.lock()->setParent(Sptr());
187 }
188
189 myUnownedChildren.clear();
190 myChildrenByName.clear();
191 }
192
193 //! \brief Iterates over all children and applies a function to each
194 //! \param fn Function to apply to each child
195 //! \return True if the function was applied to all children, false if interrupted
196 //!
197 //! This method iterates over all children (both owned and unowned) and applies
198 //! the provided function to each. If the function returns false for any child,
199 //! iteration stops and the method returns false. Otherwise, it returns true.
200 //!
201 //! Note that it creates copies of the child lists before iteration to allow
202 //! safe modification of the lists during iteration.
203 virtual bool forEachChild(ForChildFn fn)
204 {
206 for (auto child : ownedCopy)
207 {
208 if (!fn(child))
209 {
210 return false;
211 }
212 }
213 ownedCopy.clear();
214
216
218 for (auto child : unownedCopy)
219 {
220 if (!fn(child.lock()))
221 {
222 return false;
223 }
224 }
225 unownedCopy.clear();
226
227 return true;
228 }
229
230 //! \brief Finds a child that matches a given predicate
231 //! \param fn Predicate function to test each child
232 //! \return Shared pointer to the first matching child, or null if none found
233 //!
234 //! This method searches through all children (both owned and unowned) and
235 //! returns the first child for which the predicate function returns true.
236 //! If no child matches, it returns a null pointer.
238 {
239 // First check owned children
240 for (auto child : myOwnedChildren)
241 {
242 if (fn(child))
243 {
244 return child;
245 }
246 }
247
249
250 // Then check unowned children
251 for (auto child : myUnownedChildren)
252 {
253 if (fn(child.lock()))
254 {
255 return child.lock();
256 }
257 }
258
259 return Sptr();
260 }
261
262 //! \brief Checks if a given node is a child of this node
263 //! \param child Shared pointer to the node to check
264 //! \return True if the node is a child of this node, false otherwise
265 //!
266 //! This method checks both the owned and unowned children lists to determine
267 //! if the specified node is a direct child of this node.
268 virtual bool isChild(Sptr child)
269 {
270 // Check owned children
271 {
272 auto findIt = myOwnedChildren.begin();
273 for (; findIt != myOwnedChildren.end(); ++findIt)
274 {
275 if (*findIt == child)
276 {
277 return true;
278 }
279 }
280 }
281 // Check unowned children
282 {
283 auto findIt = myUnownedChildren.begin();
284 for (; findIt != myUnownedChildren.end(); ++findIt)
285 {
286 if (findIt->lock() == child)
287 {
288 return true;
289 }
290 }
291 }
292 return false;
293 }
294
295 //! \brief Finds a child by name
296 //! \param name The name of the child to find
297 //! \return Shared pointer to the child with the given name, or null if none found
298 //!
299 //! This method first checks a name-to-child map for fast lookup. If the child
300 //! is not found in the map, it searches all children for one with the given name.
301 //! If found, it adds the child to the name map for faster subsequent lookups.
302 //!
303 //! The method also performs cleanup of expired references in the name map.
304 virtual Sptr findChild(const std::string& name)
305 {
306 // First, check the name map for fast lookup
307 {
308 auto findIt = myChildrenByName.find(name);
309 if (findIt != myChildrenByName.end())
310 {
311 // Check for expired reference
312 if (!findIt->second.expired())
313 {
314 Sptr found = findIt->second.lock();
315 // Check that the name still matches
316 if (found->name() == name)
317 {
318 return findIt->second.lock();
319 }
320 }
321
322 // If we're still here, either the reference expired or
323 // the name changed. Clean up the defunct entry.
324 myChildrenByName.erase(findIt);
325 }
326 }
327
328 // Clean up any expired references in the name map
329 {
330 auto it = myChildrenByName.begin();
331 while (it != myChildrenByName.end())
332 {
333 if (it->second.expired())
334 {
335 it = myChildrenByName.erase(it);
336 }
337 else
338 {
339 ++it;
340 }
341 }
342 }
343
344 // Failed to find in the name map, so search all children
345 Sptr found = findChild(
346 [&](Sptr child)
347 {
348 return child->name() == name;
349 });
350
351 if (found)
352 {
353 // Add the name to the map for faster subsequent lookup
354 myChildrenByName[name] = found;
355 return found;
356 }
357
358 return Sptr();
359 }
360
361 //! \brief Gets the total number of children
362 //! \return The total number of children (both owned and unowned)
363 virtual unsigned int numChildren() { return myOwnedChildren.size() + myUnownedChildren.size(); }
364
365 //! \brief Checks if this node has any children
366 //! \return True if this node has at least one child, false otherwise
367 virtual bool hasChildren() { return numChildren() > 0; }
368
369 //! \brief Gets the parent of this node
370 //! \return Shared pointer to the parent node, or null if no parent
371 virtual Sptr parent() { return myParent.lock(); }
372
373protected:
374 //! \brief Sets the parent of this node
375 //! \param parent Shared pointer to the new parent node
376 //!
377 //! This protected method is called by the addChild and removeChild methods
378 //! to update the parent reference of this node.
379 virtual void setParent(Sptr parent) { myParent = parent; }
380
381 //! \brief Removes expired weak references from the unowned children list
382 //!
383 //! This protected method is called internally to clean up any weak references
384 //! to children that have been destroyed. It iterates through the unowned
385 //! children list and removes any expired references.
386 virtual void pruneChildren()
387 {
388 auto it = myUnownedChildren.begin();
389 while (it != myUnownedChildren.end())
390 {
391 if (it->expired())
392 {
393 it = myUnownedChildren.erase(it);
394 }
395 else
396 {
397 ++it;
398 }
399 }
400 }
401
402protected:
403 //! \brief Weak pointer type for this class
404 using Wptr = std::weak_ptr<SELF_T>;
405 //! \brief Type for the list of owned children
406 using OwnedChildList = std::list<Sptr>;
407 //! \brief Type for the list of unowned children
408 using UnownedChildList = std::list<Wptr>;
409 //! \brief Type for the map of child names to child pointers
410 using ChildNameMap = std::map<std::string, Wptr>;
411
412 //! \brief List of children owned by this node (strong references)
414 //! \brief List of children not owned by this node (weak references)
416
417 //! \brief Map of child names to child pointers for fast lookup
419
420 //! \brief Flag indicating whether this node owns its children
422
423 //! \brief Weak reference to the parent node
425};
426
427} // namespace makVre
Provides base classes for shared pointer managed objects with factory creation support.
virtual std::string name() const
Gets the name of this object.
Definition baseClass.h:153
Sptr self()
Definition baseClass.h:198
DtSpSubClass()
Definition baseClass.h:190
virtual Sptr findChild(FindChildFn fn)
Finds a child that matches a given predicate.
Definition treeClass.h:237
virtual void setOwnsChildren(bool owns)
Sets whether this node owns its children.
Definition treeClass.h:65
virtual Sptr parent()
Gets the parent of this node.
Definition treeClass.h:371
std::shared_ptr< SELF_T > Sptr
Shared pointer type for this class.
Definition treeClass.h:41
std::map< std::string, Wptr > ChildNameMap
Type for the map of child names to child pointers.
Definition treeClass.h:410
std::function< bool(Sptr child)> ForChildFn
Function type for child traversal callbacks.
Definition treeClass.h:43
virtual void removeAllChildren()
Removes all children from this node.
Definition treeClass.h:172
virtual bool removeChild(Sptr child)
Removes a child from this node.
Definition treeClass.h:123
bool myOwnsChildren
Flag indicating whether this node owns its children.
Definition treeClass.h:421
Wptr myParent
Weak reference to the parent node.
Definition treeClass.h:424
virtual ~DtTreeClass() override
Virtual destructor.
Definition treeClass.h:58
std::function< bool(Sptr child)> FindChildFn
Function type for child search predicates.
Definition treeClass.h:45
virtual bool ownsChildren()
Checks if this node owns its children.
Definition treeClass.h:69
virtual bool isChild(Sptr child)
Checks if a given node is a child of this node.
Definition treeClass.h:268
virtual Sptr findChild(const std::string &name)
Finds a child by name.
Definition treeClass.h:304
virtual bool addChild(Sptr child)
Adds a child to this node.
Definition treeClass.h:82
std::list< Wptr > UnownedChildList
Type for the list of unowned children.
Definition treeClass.h:408
virtual unsigned int numChildren()
Gets the total number of children.
Definition treeClass.h:363
UnownedChildList myUnownedChildren
List of children not owned by this node (weak references)
Definition treeClass.h:415
std::weak_ptr< SELF_T > Wptr
Weak pointer type for this class.
Definition treeClass.h:404
ChildNameMap myChildrenByName
Map of child names to child pointers for fast lookup.
Definition treeClass.h:418
virtual void setParent(Sptr parent)
Sets the parent of this node.
Definition treeClass.h:379
DtTreeClass()
Default constructor.
Definition treeClass.h:50
std::list< Sptr > OwnedChildList
Type for the list of owned children.
Definition treeClass.h:406
virtual bool forEachChild(ForChildFn fn)
Iterates over all children and applies a function to each.
Definition treeClass.h:203
OwnedChildList myOwnedChildren
List of children owned by this node (strong references)
Definition treeClass.h:413
virtual bool hasChildren()
Checks if this node has any children.
Definition treeClass.h:367
virtual void pruneChildren()
Removes expired weak references from the unowned children list.
Definition treeClass.h:386
Provides logging functionality with various severity levels and channels.
#define LOG_WARN(channel)
Macro to log a warning message to log files.
Definition logger.h:69
Include export definitions for this library.
Definition glsVreMessageUtil.h:49