ufe  2.0
Universal Front End is a DCC-agnostic component that will allow a DCC to browse and edit data in multiple data models
trie.imp.h
Go to the documentation of this file.
1 #line 1 "S:/jenkins/workspace/ufe-full-windows/ufe/include/trie.imp.h"
2 #ifndef _ufeTrie_imp
3 #define _ufeTrie_imp
4 // =======================================================================
5 // Copyright 2019 Autodesk, Inc. All rights reserved.
6 //
7 // This computer source code and related instructions and comments are the
8 // unpublished confidential and proprietary information of Autodesk, Inc.
9 // and are protected under applicable copyright and trade secret law. They
10 // may not be disclosed to, copied or used by any third party without the
11 // prior written consent of Autodesk, Inc.
12 // =======================================================================
13 
14 #include "trie.h"
15 #include "ufeAssert.h"
16 
17 #include <numeric>
18 
19 UFE_NS_DEF {
20 
21 //==============================================================================
22 // CLASS Ufe::TrieNode
23 //==============================================================================
24 
25 template<typename T>
27  : fComponent(component), fParent(), fChildren(), fHasData(false),
28  fData()
29 {}
30 
31 template<typename T>
33 {}
34 
35 template<typename T>
36 void TrieNode<T>::add(const Ptr& child)
37 {
38  // Child must not exist yet.
39  UFE_ASSERT_MSG(fChildren.find(child->component()) == fChildren.end(),
40  "Child trie node already exists.");
41 
42  fChildren[child->component()] = child;
43  // Go through this pointer to prevent "no arguments to ‘shared_from_this’
44  // that depend on a template parameter" error.
45  child->setParent(this->shared_from_this());
46 }
47 
48 template<typename T>
49 void TrieNode<T>::remove(const Ptr& child)
50 {
51  UFE_ASSERT_COMPILED(typename Children::size_type nbErased = )
52  fChildren.erase(child->component());
53  UFE_ASSERT_MSG(nbErased == 1, "Child trie node does not exist.");
54  child->setParent(Ptr());
55 }
56 
57 template<typename T>
59 {
60  fComponent = PathComponent();
61  fParent = ParentPtr();
62  fChildren.clear();
63  fHasData = false;
64 }
65 
66 template<typename T>
68 {
69  return fParent.lock();
70 }
71 
72 template<typename T>
73 bool TrieNode<T>::contains(const PathComponent& component) const
74 {
75  return fChildren.find(component) != fChildren.end();
76 }
77 
78 template<typename T>
79 typename TrieNode<T>::Ptr TrieNode<T>::operator[](const PathComponent& component) const
80 {
81  typename Children::const_iterator const found = fChildren.find(component);
82  return found == fChildren.end() ? Ptr() : found->second;
83 }
84 
85 template<typename T>
86 int TrieNode<T>::closestCommonAncestor( int depth ) const
87 {
88  std::size_t sz = size();
89 
90  // If this node has data or it's a leaf node then return
91  // before incrementing. The common ancestor is our
92  // parent.
93  //
94  // In practice both of these conditions should be the same,
95  // but we can call this function with an empty trie in which
96  // case we will have size 0 and no data in the empty root node.
97  if ( hasData() || 0 == sz) {
98  return depth;
99  }
100 
101  depth++;
102 
103  // If this node has multiple children then it is the
104  // common ancestor.
105  if (1 < sz) {
106  return depth;
107  }
108 
109  // Else we need to keep going...
110  typename Children::const_iterator const next = fChildren.begin();
111  return next->second->closestCommonAncestor(depth);
112 }
113 
114 template<typename T>
115 std::size_t TrieNode<T>::size() const
116 {
117  return fChildren.size();
118 }
119 
120 template<typename T>
121 std::size_t TrieNode<T>::treeSize() const
122 {
123  return std::accumulate(
124  fChildren.begin(), fChildren.end(), std::size_t(1),
125  [](std::size_t treeSize, const typename Children::value_type& child) {
126  return treeSize+child.second->treeSize();
127  });
128 }
129 
130 template<typename T>
131 bool TrieNode<T>::empty() const
132 {
133  return size() == 0;
134 }
135 
136 template<typename T>
138 {
139  return fComponent;
140 }
141 
142 template<typename T>
143 void TrieNode<T>::rename(const PathComponent& component)
144 {
145  UFE_ASSERT_MSG(parent()->contains(fComponent),
146  "Cannot rename child trie node, not found in parent.");
147  auto self = this->shared_from_this();
148  auto p = parent();
149  p->remove(self);
150  fComponent = component;
151  p->add(self);
152 }
153 
154 template<typename T>
155 void TrieNode<T>::setData(const T& data)
156 {
157  fHasData = true;
158  fData = data;
159 }
160 
161 template<typename T>
163 {
164  fHasData = false;
165 }
166 
167 template<typename T>
168 const T& TrieNode<T>::data() const
169 {
170  return fData;
171 }
172 
173 template<typename T>
175 {
176  return fHasData;
177 }
178 
179 template<typename T>
181 {
182  fParent = ParentPtr(parent);
183 }
184 
185 //==============================================================================
186 // CLASS Ufe::Trie
187 //==============================================================================
188 
189 template<typename T>
190 Trie<T>::Trie() : fRoot(std::make_shared< TrieNode<T> >())
191 {}
192 
193 template<typename T>
194 Trie<T>::Trie(Trie&& rhs) : fRoot(std::move(rhs.fRoot))
195 {
196  rhs.fRoot = std::make_shared< TrieNode<T> >();
197 }
198 
199 template<typename T>
201 {
202  fRoot = std::move(rhs.fRoot);
203  rhs.fRoot = std::make_shared< TrieNode<T> >();
204  return *this;
205 }
206 
207 template<typename T>
209 {
210  return fRoot;
211 }
212 
213 template<typename T>
214 typename TrieNode<T>::Ptr Trie<T>::add(const Path& path, const T& data)
215 {
216  // Walk down the path inside the tree, adding trie nodes if required.
217  typename TrieNode<T>::Ptr trieNode = root();
218  for (const PathComponent& c : path) {
219  typename TrieNode<T>::Ptr child = (*trieNode)[c];
220  if (!child) {
221  child = std::make_shared< TrieNode<T> >(c);
222  trieNode->add(child);
223  }
224  trieNode = child;
225  }
226  // Last trie node gets the data.
227  trieNode->setData(data);
228  return trieNode;
229 }
230 
231 template<typename T>
232 typename TrieNode<T>::Ptr Trie<T>::find(const Path& path) const
233 {
234  // Walk down the path inside the tree.
235  typename TrieNode<T>::Ptr trieNode = root();
236  for (const PathComponent& c : path) {
237  typename TrieNode<T>::Ptr child = (*trieNode)[c];
238  if (!child) {
239  return typename TrieNode<T>::Ptr();
240  }
241  trieNode = child;
242  }
243  return trieNode->hasData() ? trieNode : typename TrieNode<T>::Ptr();
244 }
245 
246 template<typename T>
247 typename TrieNode<T>::Ptr Trie<T>::node(const Path& path) const
248 {
249  // Walk down the path inside the tree.
250  typename TrieNode<T>::Ptr trieNode = root();
251  for (const PathComponent& c : path) {
252  typename TrieNode<T>::Ptr child = (*trieNode)[c];
253  if (!child) {
254  return typename TrieNode<T>::Ptr();
255  }
256  trieNode = child;
257  }
258  return trieNode;
259 }
260 
261 template<typename T>
262 bool Trie<T>::contains(const Path& path) const
263 {
264  return bool(find(path));
265 }
266 
267 template<typename T>
269 {
270  // Algorithm summary: walk down the path tree to the end of the argument
271  // path. If that trie node has children, a descendant is in the trie.
272 
273  // By definition, an empty path has no descendants.
274  if (path.empty()) {
275  return false;
276  }
277 
278  // Walk down the complete path inside the tree, if possible.
279  typename TrieNode<T>::Ptr trieNode = root();
280  for (const PathComponent& c : path) {
281  typename TrieNode<T>::Ptr child = (*trieNode)[c];
282  // If we've reached a trie leaf node before the end of our path, there
283  // cannot be any descendants in the trie.
284  if (!child) {
285  return false;
286  }
287  trieNode = child;
288  }
289  // We reached the end of the argument path. Whether the trieNode we
290  // reached has data or not, return true if it has descendants. To
291  // implement a containsDescendantInclusive, which would include the
292  // argument path, we would simply return true: at this point we've reached
293  // either an internal node, which by definition has children, or a leaf
294  // node with no descendants, which by definition has data.
295  return !trieNode->empty();
296 }
297 
298 template<typename T>
299 bool Trie<T>::containsAncestor(const Path& descendantPath) const
300 {
301  // Algorithm summary: walk down the path tree trying to find a node
302  // with data.
303 
304  // By definition, an empty path has no ancestors.
305  if (descendantPath.empty()) {
306  return false;
307  }
308 
309  // Finding the path itself in the trie does not count, therefore we remove
310  // the tail of the path.
311  auto parentPath = descendantPath.pop();
312 
313  // Walk down the path inside the tree. As soon as we find a trieNode with
314  // data, return true.
315  typename TrieNode<T>::Ptr trieNode = root();
316  for (const PathComponent& c : parentPath) {
317  typename TrieNode<T>::Ptr child = (*trieNode)[c];
318  // If we've reached a trie leaf node before the end of our path, there
319  // is no trie node with data as ancestor of the path.
320  if (!child) {
321  return false;
322  }
323  trieNode = child;
324  // Found a trieNode with data.
325  if (trieNode->hasData()) {
326  return true;
327  }
328  }
329  // We reached the end of the parent path without returning true, therefore
330  // there are no ancestors.
331  return false;
332 }
333 
334 template<typename T>
336 {
337  return root()->closestCommonAncestor(-1);
338 }
339 
340 template<typename T>
342 {
343  typename TrieNode<T>::Ptr found = find(p);
344  if (!found) {
345  return found;
346  }
347 
348  // First, clear the data from the trie node.
349  UFE_ASSERT_MSG(found->hasData(), "Trie node has no associated data.");
350  found->clearData();
351 
352  // Next, clean up trie if required. If trie node has no children and
353  // no data, remove it, and recurse up to its parent.
354  typename TrieNode<T>::Ptr child = found;
355  while (child->empty() && !child->hasData() && child != root()) {
356  typename TrieNode<T>::Ptr parent = child->parent();
357  parent->remove(child);
358  child = parent;
359  }
360 
361  return found;
362 }
363 
364 template<typename T>
366 {
367  root()->clear();
368 }
369 
370 template<typename T>
371 std::size_t Trie<T>::size() const
372 {
373  return root()->treeSize();
374 }
375 
376 template<typename T>
377 bool Trie<T>::empty() const
378 {
379  return size() == 0;
380 }
381 
382 }
383 
384 #endif /* _ufeTrie_imp */
void setData(const T &data)
Definition: trie.imp.h:155
TrieNode< T >::Ptr node(const Path &path) const
Definition: trie.imp.h:247
void clear()
Definition: trie.imp.h:58
std::size_t treeSize() const
Definition: trie.imp.h:121
bool empty() const
bool containsAncestor(const Path &path) const
Definition: trie.imp.h:299
void remove(const Ptr &child)
Definition: trie.imp.h:49
std::shared_ptr< ObservableSelection > Ptr
Constant string representation with fixed space and O(1) comparison.
Definition: pathComponent.h:33
Definition: path.h:178
const T & data() const
Definition: trie.imp.h:168
Trie & operator=(const Trie &)=delete
bool contains(const Path &path) const
Definition: trie.imp.h:262
void setParent(Ptr parent)
Definition: trie.imp.h:180
PathComponent component() const
Definition: trie.imp.h:137
Node for Universal Front End trie.
#define UFE_ASSERT_MSG(EXPR, MSG)
Definition: ufeAssert.h:34
bool containsDescendant(const Path &path) const
Definition: trie.imp.h:268
void rename(const PathComponent &component)
Definition: trie.imp.h:143
void add(const Ptr &child)
Definition: trie.imp.h:36
Identify an object or 3D path in the scene.
Definition: path.h:37
int closestCommonAncestor() const
Definition: trie.imp.h:335
std::size_t size() const
Definition: trie.imp.h:115
void clearData()
Definition: trie.imp.h:162
bool contains(const PathComponent &child) const
Definition: trie.imp.h:73
Ptr operator[](const PathComponent &child) const
Definition: trie.imp.h:79
TrieNode< T >::Ptr remove(const Path &)
Definition: trie.imp.h:341
#define UFE_NS_DEF
Definition: ufe.h:35
Ptr parent() const
Definition: trie.imp.h:67
bool hasData() const
Definition: trie.imp.h:174
TrieNode< T >::Ptr root() const
Definition: trie.imp.h:208
bool empty() const
Definition: trie.imp.h:131
std::size_t size() const
Definition: trie.imp.h:371
TrieNode< T >::Ptr find(const Path &path) const
Definition: trie.imp.h:232
std::weak_ptr< TrieNode > ParentPtr
Definition: trie.h:95
int closestCommonAncestor(int depth) const
Definition: trie.imp.h:86
std::shared_ptr< TrieNode > Ptr
Definition: trie.h:45
void clear()
Definition: trie.imp.h:365
Path path(const std::string &pathString)
#define UFE_ASSERT_COMPILED(CODE)
Definition: ufeAssert.h:37
Path pop() const
TrieNode< T >::Ptr add(const Path &path, const T &data)
Definition: trie.imp.h:214
bool empty() const
Definition: trie.imp.h:377