Honeycomb  0.1
Component-Model Framework
TreeClone.h
Go to the documentation of this file.
1 // Honeycomb, Copyright (C) 2015 NewGamePlus Inc. Distributed under the Boost Software License v1.0.
2 #pragma once
3 
4 #include "Honey/Graph/Tree.h"
6 
7 namespace honey
8 {
9 
11 template<class TreeNode>
12 class TreeClone
13 {
14 public:
15 
17  {
18  _listeners.push_back(&ListenerQueue::create<typename TreeNode::sigDestroy>(bind_fill(&TreeClone::onDestroy, this)));
19  _listeners.push_back(&ListenerQueue::create<typename TreeNode::sigSetData>(bind_fill(&TreeClone::onSetData, this)));
20  _listeners.push_back(&ListenerQueue::create<typename TreeNode::sigSetKey>(bind_fill(&TreeClone::onSetKey, this)));
21  _listeners.push_back(&ListenerQueue::create<typename TreeNode::sigInsertChild>(bind_fill(&TreeClone::onInsertChild, this)));
22  _listeners.push_back(&ListenerQueue::create<typename TreeNode::sigRemoveChild>(bind_fill(&TreeClone::onRemoveChild, this)));
23  }
24 
25  ~TreeClone() { clear(); }
26 
28 
39  TreeNode& regNode(const TreeNode& rootNode)
40  {
41  //Check if node is already registered
42  auto clone = getRegClone(rootNode);
43  if (clone) return *clone;
44  //Create a phantom that will be made into a proper clone after update
45  return createPhantom(rootNode);
46  }
47 
49 
58  TreeNode* unregNode(const TreeNode& rootNode)
59  {
60  TreeNode* ret = nullptr;
61 
62  //We must be completely up-to-date to safely unregister
63  update();
64 
65  for (auto& e : rootNode.preOrd())
66  {
67  auto clone = unregNodeSingle(e);
68  if (!ret) ret = clone;
69  }
70 
71  return ret;
72  }
73 
75 
79  const TreeNode* unregClone(const TreeNode& rootClone)
80  {
81  const TreeNode* ret = nullptr;
82 
83  //We must be completely up-to-date to safely unregister
84  update();
85 
86  for (auto& e : rootClone.preOrd())
87  {
88  auto node = getOrigNode(e);
89  if (!node) continue;
90  auto res = unregNodeSingle(*node);
91  if (!ret && res) ret = node;
92  }
93 
94  return ret;
95  }
96 
98  void update()
99  {
100  //Process all signals to bring cloned nodes into the latest up-to-date state
101  for (auto& e : _listeners) e->process();
102 
103  //Clone any phantoms that were registered or attached as unknown children
104  while (!_phantomMap.empty())
105  cloneTree(*_phantomMap.begin()->first);
106  }
107 
109  void clear()
110  {
111  //Remove listeners from orig nodes
112  for (auto& node : keys(_regMap)) for (auto& e : _listeners) const_cast<TreeNode*>(node)->listeners().remove(*e);
113  for (auto& e : _listeners) e->clear();
114 
115  //Free clone resources
116  deleteRange(values(_cloneMap));
117  _cloneMap.clear();
118  _cloneRMap.clear();
119  _regMap.clear();
120  _phantomMap.clear();
121  _unregMap.clear();
122  }
123 
125  TreeNode* getClone(const TreeNode& node) const
126  {
127  auto it = _cloneMap.find(&node);
128  if (it == _cloneMap.end()) return nullptr;
129  return it->second;
130  }
131 
133  const TreeNode* getOrigNode(const TreeNode& clone) const
134  {
135  auto it = _cloneRMap.find(const_cast<TreeNode*>(&clone));
136  if (it == _cloneRMap.end()) return nullptr;
137  return it->second;
138  }
139 
141  bool isRegNode(const TreeNode& node) const { return getRegClone(node); }
143  bool isRegClone(const TreeNode& clone) const { auto node = getOrigNode(clone); return node ? isRegNode(*node) : false; }
144 
146  szt cloneCount() const { return _cloneMap.size(); }
148  szt regNodeCount() const { return _regMap.size() + _phantomMap.size(); }
149 
150 private:
151 
152  void onDestroy(TreeNode& src)
153  {
154  auto clone = getRegClone(src);
155  assert(clone && !_phantomMap.count(&src) && !_unregMap.count(&src));
156  deleteClone(*clone);
157  }
158 
159  void onSetData(TreeNode& src, const typename TreeNode::Data& data)
160  {
161  auto clone = getRegClone(src);
162  assert(clone && !_phantomMap.count(&src) && !_unregMap.count(&src));
163  clone->setData(data);
164  }
165 
166  void onSetKey(TreeNode& src, const typename TreeNode::Key& key)
167  {
168  auto clone = getRegClone(src);
169  assert(clone && !_phantomMap.count(&src) && !_unregMap.count(&src));
170  clone->setKey(key);
171  }
172 
173  void onInsertChild(TreeNode& src, TreeNode* childPos, TreeNode& child)
174  {
175  auto clone = getRegClone(src);
176  assert(clone && !_phantomMap.count(&src) && !_unregMap.count(&src));
177 
178  //A null original child means insert at end of list
179  auto it = end(clone->children());
180  if (childPos)
181  {
182  //Original child not null, get the original child's clone
183  childPos = getRegClone(*childPos);
184  assert(childPos && !_unregMap.count(childPos));
185  it = clone->childPos(*childPos);
186  }
187 
188  //Child could be an unknown node, create phantom if necessary
189  auto& cloneChild = regNode(child);
190 
191  clone->insertChild(it, cloneChild);
192  }
193 
194  void onRemoveChild(TreeNode& src, TreeNode& child)
195  {
196  auto clone = getRegClone(src);
197  assert(clone && !_phantomMap.count(&src) && !_unregMap.count(&src));
198 
199  //Get the original child's clone
200  auto cloneChild = getRegClone(child);
201  assert(cloneChild && !_unregMap.count(cloneChild));
202 
203  auto it = clone->childPos(*cloneChild);
204  assert(it != end(clone->children()));
205 
206  clone->removeChild(it);
207  }
208 
209  void deleteClone(TreeNode& clone)
210  {
211  auto it = _cloneRMap.find(&clone);
212  assert(it != _cloneRMap.end() && it->second && !_phantomMap.count(it->second) && !_unregMap.count(it->second));
213  _cloneMap.erase(it->second);
214  _regMap.erase(it->second);
215  _cloneRMap.erase(it);
216  delete_(&clone);
217  }
218 
219  TreeNode& allocClone(const TreeNode& node)
220  {
221  assert(!_cloneMap.count(&node));
222  auto clone = new TreeNode();
223  _cloneMap[&node] = clone;
224  _cloneRMap[clone] = &node;
225  return *clone;
226  }
227 
228  TreeNode* phantom(const TreeNode& node) const
229  {
230  auto it = _phantomMap.find(&node);
231  if (it == _phantomMap.end()) return nullptr;
232  return it->second;
233  }
234 
235  TreeNode* getRegClone(const TreeNode& regNode) const
236  {
237  auto it = _regMap.find(&regNode);
238  if (it == _regMap.end()) return nullptr;
239  return it->second;
240  }
241 
242  TreeNode* getUnregClone(const TreeNode& node) const
243  {
244  auto it = _unregMap.find(&node);
245  if (it == _unregMap.end()) return nullptr;
246  return it->second;
247  }
248 
250  TreeNode& createPhantom(const TreeNode& node)
251  {
252  //Phantom must not already exist
253  assert(!_phantomMap.count(&node));
254  //Pull a new clone from the unregistered list if possible
255  auto phantom = getUnregClone(node);
256  if (phantom) _unregMap.erase(&node);
257  else phantom = &allocClone(node);
258  _phantomMap[&node] = phantom;
259  _regMap[&node] = phantom;
260  phantom->setParent(nullptr);
261  phantom->clearChildren();
262  phantom->setData(node.getData());
263  phantom->setKey(node.getKey());
264  return *phantom;
265  }
266 
267  void cloneTree(const TreeNode& parent)
268  {
269  auto phantom = this->phantom(parent);
270  assert(phantom);
271  _phantomMap.erase(&parent);
272 
273  //Recurse through original node's children, clone each child link
274  for (auto& child : parent.children())
275  {
276  auto phantomChild = getRegClone(child);
277  if (!phantomChild || phantomChild == this->phantom(child))
278  {
279  //Unknown node, need to clone it using phantom
280  if (!phantomChild) phantomChild = &createPhantom(child);
281  cloneTree(child);
282  }
283  phantom->addChild(*phantomChild);
284  }
285 
286  for (auto& e : _listeners) const_cast<TreeNode&>(parent).listeners().add(*e);
287  }
288 
290  TreeNode* unregNodeSingle(const TreeNode& node)
291  {
292  auto clone = getRegClone(node);
293  if (!clone) return nullptr;
294 
295  //Clone's parent must not be registered
296  assert(!clone->getParent() || !isRegClone(*clone->getParent()),
297  sout() << "Node can't be unregistered because its parent is registered. Parent Id: "
298  << clone->getParent()->getKey() << " ; Child Id: " << clone->getKey());
299 
300  for (auto& e : _listeners) const_cast<TreeNode&>(node).listeners().remove(*e);
301 
302  _regMap.erase(&node);
303  _phantomMap.erase(&node);
304  _unregMap[&node] = clone;
305 
306  return clone;
307  }
308 
310  typedef unordered_map<const TreeNode*, TreeNode*> CloneMap;
312  typedef unordered_map<TreeNode*, const TreeNode*> CloneRMap;
313 
314  vector<ListenerQueue::Ptr> _listeners;
315  CloneMap _cloneMap;
316  CloneRMap _cloneRMap;
317  CloneMap _regMap;
318  CloneMap _phantomMap;
319  CloneMap _unregMap;
320 };
321 
322 }
const TreeNode * unregClone(const TreeNode &rootClone)
Stop a clone and its entire subtree from tracking changes to their original nodes. Returns original node of first clone unregistered (or null if none found).
Definition: TreeClone.h:79
bool isRegNode(const TreeNode &node) const
Check if a node is registered.
Definition: TreeClone.h:141
void update()
Update clones to make them mirror the current data and hierarchy of registered nodes.
Definition: TreeClone.h:98
Unrooted acyclic tree.
Definition: Tree.h:17
Clone and track changes to an entire tree.
Definition: TreeClone.h:12
void delete_(T *&p)
Destruct object, free memory and set pointer to null.
Definition: Allocator.h:75
void clear()
Reset the state of the tree clone structure, unregister all nodes and destroy all clones...
Definition: TreeClone.h:109
const TreeNode * getOrigNode(const TreeNode &clone) const
Get the original node of a clone. Returns null if not found.
Definition: TreeClone.h:133
~TreeClone()
Definition: TreeClone.h:25
auto bind_fill(Func &&f, Args &&...args) -> decltype( priv::bind_fill< mt::funcTraits< typename mt::removeRef< Func >::type >::arity >()(forward< Func >(f), forward< Args >(args)...))
Version of bind that automatically fills in placeholders for unspecified arguments.
Definition: StdUtil.h:138
szt cloneCount() const
Get total number of clones being handled by this tree.
Definition: TreeClone.h:146
TreeNode * getClone(const TreeNode &node) const
Get the cloned version of a node (node may be registered or unregistered). Returns null if not found...
Definition: TreeClone.h:125
auto keys(Range &&range) -> Range_< TupleIter< mt_iterOf(range), 0 >, TupleIter< mt_iterOf(range), 0 >>
Create a range over the keys of a map or map iterator range.
Definition: StdUtil.h:23
ostringstream sout()
Shorthand to create ostringstream.
Definition: Stream.h:15
Range_< PreOrdConstIter, PreOrdConstIter > preOrd() const
Get a depth-first pre-order range.
Definition: Tree.h:378
#define assert(...)
Forwards to assert_#args. See assert_1(), assert_2().
Definition: Debug.h:24
szt regNodeCount() const
Get total number of registered nodes.
Definition: TreeClone.h:148
void deleteRange(Range &&range)
Delete all elements in range.
Definition: Range.h:428
bool isRegClone(const TreeNode &clone) const
Check if a clone is registered.
Definition: TreeClone.h:143
size_t szt
Size type, shorthand for size_t.
Definition: Core.h:90
auto values(Range &&range) -> Range_< TupleIter< mt_iterOf(range), 1 >, TupleIter< mt_iterOf(range), 1 >>
Create a range over the values of a map or map iterator range.
Definition: StdUtil.h:30
TreeNode & regNode(const TreeNode &rootNode)
Register a node to clone. Returns clone. Clone's state is invalid (not equal to original) until updat...
Definition: TreeClone.h:39
Global Honeycomb namespace.
Key_ Key
Definition: Tree.h:22
TreeClone()
Definition: TreeClone.h:16
TreeNode * unregNode(const TreeNode &rootNode)
Stop tracking changes to a node and its entire subtree. Returns clone of first node unregistered (or ...
Definition: TreeClone.h:58
Data_ Data
Definition: Tree.h:21