Jamoma API  0.6.0.a19
TTNode.cpp
1 /*
2  * TTNode
3  * Copyright © 2008, Théo de la Hogue & Tim Place
4  *
5  * License: This code is licensed under the terms of the "New BSD License"
6  * http://creativecommons.org/licenses/BSD/
7  */
8 
9 #ifndef DISABLE_NODELIB
10 
11 #include "TTNode.h"
12 
13 TTNode::TTNode(TTSymbol& aName, TTSymbol& anInstance, TTObject& anObject, TTPtr aContext, TTNodeDirectoryPtr aDirectory):
14  parent(NULL)
15 {
16  name = aName;
17  instance = anInstance;
18  object = anObject;
19  context = aContext;
20  directory = aDirectory;
21 
22  // a new TTNode have no child
23  children = new TTHash();
24 }
25 
27 {
28  TTErr err;
29  unsigned int i, j, nb_c, nb_i;
30  TTValue hk, hk_i;
31  TTAddress anAddress;
32  TTSymbol key;
33  TTSymbol key_i;
34  TTValue c, c_i, p_c, data;
35  TTHashPtr ht_i, p_ht_i;
36  TTNodePtr n_c;
37 
38  // destroy all his children
39  nb_c = this->children->getSize();
40  if (nb_c) {
41 
42  this->children->getKeys(hk);
43 
44  for (i = 0; i < nb_c; i++) {
45 
46  key = hk[i];
47  err = this->children->lookup(key, c);
48 
49  if (err != kTTErrValueNotFound) {
50 
51  ht_i = TTHashPtr(TTPtr(c[0]));
52 
53  // if there are instances
54  nb_i = ht_i->getSize();
55  if (nb_i) {
56 
57  ht_i->getKeys(hk_i);
58 
59  // for each instance
60  for (j = 0; j < nb_i; j++) {
61 
62  key_i = hk_i[j];
63  err = ht_i->lookup(key_i, c_i);
64 
65  if (err != kTTErrValueNotFound) {
66  n_c = TTNodePtr(TTPtr(c_i[0]));
67  n_c->getAddress(anAddress);
68  this->directory->TTNodeRemove(anAddress); // remove children properly using the TTNodeDirectory
69  }
70  }
71  }
72  }
73  }
74  }
75 
76  // it is not a child of his parent anymore
77  if (this->parent) {
78  err = this->parent->children->lookup(this->name, p_c);
79 
80  if (err != kTTErrValueNotFound) {
81  p_ht_i = TTHashPtr((TTPtr)p_c[0]);
82  p_ht_i->remove(this->instance);
83 
84  // If it was the last instance
85  // remove the hashtab
86  if (p_ht_i->getSize() == 0) {
87  p_ht_i->~TTHash();
88  this->parent->children->remove(this->name);
89  }
90  }
91 
92  this->parent = NULL;
93  }
94 
95  this->children->clear();
96  this->children->~TTHash();
97 
98  this->context = NULL;
99 }
100 
101 TTErr TTNode::setNameInstance(TTAddress& aNameInstance, TTSymbol& newInstance, TTBoolean *newInstanceCreated)
102 {
103  TTErr err;
104  TTUInt32 i;
105  TTValue hk, p_c, c, n;
106  TTString temp, t;
107  TTAddress oldAddress, newAddress;
108  TTAddress old_key, new_key;
109  TTHashPtr p_ht_i;
110  TTNodePtr n_c;
111  TTHash ht_o;
112 
113  // get his actual address
114  this->getAddress(oldAddress);
115 
116  // for each key of the directory
117  this->directory->getDirectory()->getKeys(hk);
118 
119  for (i=0; i<hk.size(); i++) {
120 
121  old_key = hk[i];
122 
123  // if the key starts by the oldAddress
124  if (strstr(old_key.c_str(), oldAddress.c_str()) == old_key.c_str()) {
125 
126  // get the TTNode
127  err = this->directory->getDirectory()->lookup(old_key, c);
128  if (err != kTTErrValueNotFound) {
129  n_c = TTNodePtr((TTPtr)c[0]);
130 
131  // notify directory observers that an address will be destroyed BEFORE the unregistration
132  this->directory->notifyObservers(old_key, n_c, kAddressDestroyed);
133 
134  // remove the old key
135  this->directory->getDirectory()->remove(old_key);
136 
137  // append to a temporary table to rename them later
138  ht_o.append(old_key, TTPtr(n_c));
139  }
140  }
141  }
142 
143  // remove the his actual name in the parent TTNode
144  err = this->parent->children->lookup(this->name, p_c);
145 
146  if (err != kTTErrValueNotFound) {
147  p_ht_i = TTHashPtr((TTPtr)p_c[0]);
148  p_ht_i->remove(this->instance);
149 
150  // If it was the last instance
151  // remove the hashtab
152  if (p_ht_i->getSize() == 0) {
153  p_ht_i->~TTHash();
154  this->parent->children->remove(this->name);
155  }
156  }
157 
158  // change his name and his instance
159  this->name = aNameInstance.getName();
160  this->instance = aNameInstance.getInstance();
161 
162  // add this TTNode to his parent
163  // and change his instance if already exists
164  *newInstanceCreated = false;
165  while (this->parent->setChild(this) == kTTErrGeneric) {
166  this->parent->generateInstance(this->name, this->instance);
167  newInstance = this->instance;
168  *newInstanceCreated = true;
169  }
170 
171  // get the new address
172  this->getAddress(newAddress);
173 
174  // for all the address witch starts by oldAddress :
175  // replace the beginning by the newAddress
176  ht_o.getKeys(hk);
177 
178  // for each key of the temprary table
179  for (i=0; i<hk.size(); i++) {
180 
181  old_key = hk[i];
182 
183  ht_o.lookup(old_key, n);
184  n_c = TTNodePtr((TTPtr)n[0]);
185 
186  // create a new key : /newAddress/end_of_the_old_key
187  temp = newAddress.c_str();
188  t = (char *)(old_key.c_str() + strlen(oldAddress.c_str()));
189  temp += t;
190  new_key = TTAddress(temp);
191 
192  // append the new key
193  this->directory->getDirectory()->append(new_key, n_c);
194 
195  // notify directory observers that an address have been created AFTER the registration
196  this->directory->notifyObservers(new_key, n_c, kAddressCreated);
197  }
198 
199  return kTTErrNone;
200 }
201 
202 TTErr TTNode::setParent(TTAddress parentAddress, TTBoolean *newParentCreated)
203 {
204  TTValue found;
205  TTObject empty;
206  TTErr err;
207 
208  // look into the hashtab to check if the address exist in the directory
209  err = this->directory->getDirectory()->lookup(parentAddress, found);
210 
211  // if the address doesn't exist
212  if (err == kTTErrValueNotFound) {
213 
214  // we create a container TTNode
215  this->directory->TTNodeCreate(parentAddress, empty, NULL, &this->parent, newParentCreated);
216 
217  // Is it a good test ?
218  if (*newParentCreated && (this->parent->instance != NO_INSTANCE))
219  return kTTErrGeneric;
220  }
221  else
222  this->parent = TTNodePtr((TTPtr)found[0]);
223 
224  return kTTErrNone;
225 }
226 
228 {
229  TTErr err;
230  TTValue c, c_i;
231  TTHashPtr ht_i;
232 
233  // Is an instance of this child
234  // already exist in the children table ?
235  err = this->children->lookup(child->name, c);
236 
237  if (err == kTTErrValueNotFound) {
238 
239  // create an instance table
240  // with this child as first instance
241  ht_i = new TTHash();
242  ht_i->append(child->instance,child);
243 
244  // add the instance table to the children table
245  this->children->append(child->name, ht_i);
246 
247  // no instance created
248  return kTTErrNone;
249  }
250  else {
251 
252  // get the instance table
253  ht_i = TTHashPtr((TTPtr)c[0]);
254 
255  // check if the instance already exists
256  err = ht_i->lookup(child->instance, c_i);
257 
258  // if not
259  if (err == kTTErrValueNotFound) {
260 
261  // add the child to the hashtab
262  ht_i->append(child->instance,child);
263 
264  return kTTErrNone;
265  }
266  else
267  return kTTErrGeneric;
268  }
269 }
270 
272 {
273  this->object = anObject;
274  return kTTErrNone;
275 }
276 
278 {
279  this->context = aContext;
280  return kTTErrNone;
281 }
282 
283 
284 
285 
287 {
288  return this->name;
289 }
290 
292 {
293 return this->instance;
294 }
295 
297 {
298 return this->parent;
299 }
300 
301 TTErr TTNode::getChildren(TTSymbol& aName, TTSymbol& anInstance, TTList& returnedChildren)
302 {
303  unsigned int i, j;
304  TTErr err;
305  TTValue hk, hk_i, c, c_i;
306  TTSymbol key;
307  TTSymbol key_i;
308  TTHashPtr ht_i;
309  TTNodePtr n_c;
310 
311  // default : no child
312  returnedChildren.clear();
313 
314  // if there are children
315  if (this->children->getSize()) {
316 
317  this->children->getKeys(hk);
318 
319  if (aName == S_WILDCARD) {
320  // for each children
321  for (i=0; i<this->children->getSize(); i++) {
322 
323  key = hk[i];
324  this->children->lookup(key, c);
325  ht_i = TTHashPtr((TTPtr)c[0]);
326 
327  // if there are instances
328  if (ht_i->getSize()) {
329 
330  ht_i->getKeys(hk_i);
331 
332  if (anInstance == S_WILDCARD) {
333  // for each instance
334  for (j=0; j<ht_i->getSize(); j++) {
335  key_i = hk_i[j];
336  ht_i->lookup(key_i, c_i);
337  n_c = TTNodePtr((TTPtr)c_i[0]);
338 
339  returnedChildren.append(n_c);
340  }
341  }
342  // there is an instance
343  else {
344  err = ht_i->lookup(anInstance, c_i);
345  if (err == kTTErrNone) {
346  n_c = TTNodePtr((TTPtr)c_i[0]);
347  returnedChildren.append(n_c);
348  }
349  // don't stop because there are maybe other names
350  }
351  }
352  }
353  }
354  // there is a name
355  else {
356  err = this->children->lookup(aName, c);
357  if (err == kTTErrNone) {
358  ht_i = TTHashPtr((TTPtr)c[0]);
359 
360  // if there are instances
361  if (ht_i->getSize()) {
362 
363  ht_i->getKeys(hk_i);
364 
365  if (anInstance == S_WILDCARD) {
366  // for each instance
367  for (j=0; j<ht_i->getSize(); j++) {
368  key_i = hk_i[j];
369  ht_i->lookup(key_i, c_i);
370  n_c = TTNodePtr((TTPtr)c_i[0]);
371 
372  returnedChildren.append(n_c);
373  }
374  }
375  // there is an instance
376  else {
377  err = ht_i->lookup(anInstance, c_i);
378  if (err == kTTErrNone) {
379  n_c = TTNodePtr((TTPtr)c_i[0]);
380  returnedChildren.append(n_c);
381  }
382  else
383  return err;
384  }
385  }
386  }
387  else
388  return err;
389  }
390  }
391  else
392  return kTTErrGeneric;
393 
394  return kTTErrNone;
395 }
396 
397 TTErr TTNode::getChildrenName(TTList& returnedChildrenName)
398 {
399  unsigned int i;
400  TTValue hk;
401  TTSymbol key;
402 
403  // default : no child
404  returnedChildrenName.clear();
405 
406  // if there are children
407  if(this->children->getSize()){
408 
409  this->children->getKeys(hk);
410 
411  // for each children
412  for(i=0; i<this->children->getSize(); i++){
413 
414  key = hk[i];
415  returnedChildrenName.append(key);
416  }
417  }
418  else
419  return kTTErrGeneric;
420 
421  return kTTErrNone;
422 }
423 
424 TTErr TTNode::getChildrenInstance(TTSymbol& aName, TTList& returnedChildrenInstance)
425 {
426  unsigned int j;
427  TTErr err;
428  TTValue hk, hk_i, c;
429  TTSymbol key_i;
430  TTHashPtr ht_i;
431 
432  // default : no child
433  returnedChildrenInstance.clear();
434 
435  // if there are children
436  if(this->children->getSize()){
437 
438  this->children->getKeys(hk);
439 
440  err = this->children->lookup(aName, c);
441  if(err == kTTErrNone){
442  ht_i = TTHashPtr((TTPtr)c[0]);
443 
444  // if there are instances
445  if(ht_i->getSize()){
446 
447  ht_i->getKeys(hk_i);
448 
449  // for each instance
450  for(j=0; j<ht_i->getSize(); j++){
451 
452  key_i = hk_i[j];
453  returnedChildrenInstance.append(key_i);
454  }
455  }
456  else
457  return kTTErrGeneric;
458  }
459  else
460  return kTTErrGeneric;
461  }
462  else
463  return kTTErrGeneric;
464 
465  return kTTErrNone;
466 }
467 
469 {
470  return this->object;
471 }
472 
474 {
475  return this->context;
476 }
477 
479 {
480  unsigned int i, nb_ancestor, len = 0;
481  TTAddress fromNorm;
482  TTAddress returnedPart1;
483  TTAddress returnedPart2;
484  TTNodePtr ptr;
485  TTValue ancestor;
486  TTString anAddressString;
487 
488  // First, count the number of ancestor
489  // and the length of the entire address (with slash and dot)
490  nb_ancestor = 0;
491 
492  if (this->name != NO_NAME)
493  len = strlen(this->name.c_str());
494 
495  if (this->instance != NO_INSTANCE)
496  len += strlen(this->instance.c_str()) + 1;
497 
498  ptr = this;
499 
500  while (ptr->parent) {
501 
502  ptr = ptr->parent;
503  nb_ancestor++;
504 
505  if (ptr->name != NO_NAME)
506  len += (strlen(ptr->name.c_str()) + 1); // +1 for /
507 
508  if (ptr->instance != NO_INSTANCE)
509  len += (strlen(ptr->instance.c_str()) + 1); // +1 for .
510  }
511 
512  // Then, prepare a value to store all the ancestor and a string
513  if (nb_ancestor)
514  ancestor.resize(nb_ancestor);
515 
516  // this is the root
517  else {
518  returnedAddress = kTTAdrsRoot;
519  return kTTErrNone;
520  }
521 
522  // The root have to be the first ancestor
523  i = nb_ancestor;
524  ptr = this;
525  while (ptr->parent) {
526  i--;
527  ptr = ptr->parent;
528  ancestor[i] = (TTPtr)ptr;
529  }
530 
531  // Finaly, copy the name of each ancestor
532  // copy the root before
533  anAddressString = TTNodePtr((TTPtr)ancestor[0])->name.c_str();
534  for (i=1; i<nb_ancestor; i++) {
535 
536  if (TTNodePtr((TTPtr)ancestor[i])->name != NO_NAME)
537  anAddressString += TTNodePtr((TTPtr)ancestor[i])->name.c_str();
538 
539  if (TTNodePtr((TTPtr)ancestor[i])->instance != NO_INSTANCE) {
540  anAddressString += S_INSTANCE.c_str();
541  anAddressString += TTNodePtr((TTPtr)ancestor[i])->instance.c_str();
542  }
543 
544  anAddressString += S_SEPARATOR.c_str();
545  }
546 
547  if (this->name != NO_NAME)
548  anAddressString += this->name.c_str();
549 
550  if (this->instance != NO_INSTANCE) {
551  anAddressString += S_INSTANCE.c_str();
552  anAddressString += this->instance.c_str();
553  }
554 
555  if (len) {
556 
557  returnedAddress = TTAddress(anAddressString);
558 
559  // make it relative from
560  if (from != kTTAdrsEmpty) {
561 
562  fromNorm = from.normalize();
563  if (fromNorm == kTTAdrsRoot)
564  returnedAddress.splitAt(0, returnedPart1, returnedPart2);
565  else
566  returnedAddress.splitAt(fromNorm.countSeparator(), returnedPart1, returnedPart2);
567 
568  returnedAddress = returnedPart2;
569  }
570 
571  return kTTErrNone;
572  }
573 
574 // *returnedAddress = NULL;
575  return kTTErrGeneric;
576 }
577 
579 {
580  TTErr err;
581  unsigned int i;
582  char instances[8];
583  TTValue c, c_i;
584  TTHashPtr ht_i;
585 
586  // first check if an instance of this child
587  // already exist in the HashTab.
588  err = this->children->lookup(childName, c);
589 
590  if (err == kTTErrValueNotFound) {
591  // no child with that name
592  return kTTErrGeneric;
593  }
594  else {
595  // get the instance table
596  ht_i = TTHashPtr((TTPtr)c[0]);
597 
598  // create a new instance
599  i = 1;
600  err = kTTErrNone;
601  while (err != kTTErrValueNotFound) {
602  snprintf(instances,8,"%u",i);
603  err = ht_i->lookup(TT(instances), c_i);
604  i++;
605  }
606 
607  // return the new instance created
608  newInstance = TT(instances);
609  return kTTErrNone;
610  }
611 }
612 
613 #endif
614 
TTErr setContext(TTPtr aContext)
Set the context of the node.
Definition: TTNode.cpp:277
bool TTBoolean
Boolean flag, same as Boolean on the Mac.
Definition: TTBase.h:167
TTErr setParent(TTAddress parentAddress, TTBoolean *newParentCreated)
Set the parent of the node.
Definition: TTNode.cpp:202
this flag means that a TTNode have been destroyed in the tree structure
Definition: TTAddressBase.h:56
TTSymbol & getInstance()
Get the instance part.
Definition: TTAddress.h:124
TTSymbol & getName()
Get the name of the node.
Definition: TTNode.cpp:286
TTErr lookup(const TTSymbol key, TTValue &value)
Find the value for the given key.
Definition: TTHash.cpp:76
TTErr TTNodeCreate(TTAddress &anAddress, TTObject &newObject, void *aContext, TTNodePtr *returnedTTNode, TTBoolean *nodeCreated)
Create a new TTNode, at the given location in the tree.
virtual ~TTNode()
Destructor.
Definition: TTNode.cpp:26
We build a directory of TTNodes, and you can request a pointer for any TTNode, or add an observer to ...
Definition: TTNode.h:59
TTErr setObject(TTObject anObject=TTObject())
Set the object of the node.
Definition: TTNode.cpp:271
TTPtr getContext()
Get a pointer to the context of this node.
Definition: TTNode.cpp:473
The TTAddress class is used to represent a string and efficiently pass and compare that string...
Definition: TTAddress.h:29
Create and use Jamoma object instances.
Definition: TTObject.h:29
TTObject & getObject()
Get the object binded by this node.
Definition: TTNode.cpp:468
size_type size() const noexcept
Return the number of elements.
TTUInt32 getSize()
Return the number of keys in the hash table.
Definition: TTHash.cpp:199
TTAddress normalize()
Normalize an address for lookup and other directory operations This would return an address without d...
Definition: TTAddress.h:149
TTErr getKeys(TTValue &hashKeys)
Get an array of all of the keys for the hash table.
Definition: TTHash.cpp:126
TTErr notifyObservers(TTAddress anAddress, TTNodePtr aNode, TTAddressNotificationFlag flag)
Notify life cycle observers that something appends below this TTNode.
TTErr TTNodeRemove(TTAddress &anAddress)
Remove a TTNodefrom the directory.
Maintain a collection of TTValue objects indexed by TTSymbol pointers.
Definition: TTHash.h:36
#define TT
This macro is defined as a shortcut for doing a lookup in the symbol table.
Definition: TTSymbol.h:155
void append(const T &anElementValueToAppend)
Insert a single TTElement at the end.
Definition: TTValue.h:243
void * TTPtr
A generic pointer.
Definition: TTBase.h:248
TTErr setChild(TTNodePtr child)
Add a node as a child of the node.
Definition: TTNode.cpp:227
TTSymbol & getInstance()
Get the instance of the node.
Definition: TTNode.cpp:291
The TTSymbol class is used to represent a string and efficiently pass and compare that string...
Definition: TTSymbol.h:26
TTErr append(const TTSymbol key, const TTValue &value)
Insert an item into the hash table.
Definition: TTHash.cpp:70
TTNode(TTSymbol &aName, TTSymbol &anInstance, TTObject &anObject, TTPtr aContext, TTNodeDirectoryPtr aDirectory)
Constructor.
Definition: TTNode.cpp:13
A value was not found when doing a look up for it (in a TTHash, TTList, or other class).
Definition: TTBase.h:352
const char * c_str() const
Return a pointer to the internal string as a C-string.
Definition: TTSymbol.h:77
TTErr getChildrenInstance(TTSymbol &aName, TTList &returnedChildrenInstance)
Get a linklist of children instance for a given name.
Definition: TTNode.cpp:424
TTErr clear()
Remove all items from the hash table.
Definition: TTHash.cpp:117
TTErr getChildrenName(TTList &returnedChildrenName)
Get a linklist of children name.
Definition: TTNode.cpp:397
TTErr getAddress(TTAddress &returnedAddress, TTAddress from=kTTAdrsEmpty)
Get the address of the node.
Definition: TTNode.cpp:478
Something went wrong, but what exactly is not known. Typically used for context-specific problems...
Definition: TTBase.h:344
TTErr remove(const TTSymbol key)
Remove an item from the hash table.
Definition: TTHash.cpp:108
TTErr
Jamoma Error Codes Enumeration of error codes that might be returned by any of the TTBlue functions a...
Definition: TTBase.h:342
this flag means that a TTNode have been created in the tree structure
Definition: TTAddressBase.h:57
std::uint32_t TTUInt32
32 bit unsigned integer
Definition: TTBase.h:178
TTHashPtr getDirectory()
Get the directory of the TTNodeDirectory.
TTErr splitAt(TTUInt32 whereToSplit, TTAddress &returnedPart1, TTAddress &returnedPart2)
A parsing tool : split address in two part from a given '/' position.
Definition: TTAddress.h:192
TTErr getChildren(TTSymbol &name, TTSymbol &instance, TTList &returnedChildren)
Get a linklist of children of the node : select them by name and instance (use wilcards to select the...
Definition: TTNode.cpp:301
References an object using a name, an instance and any contextual environnement information.
No Error.
Definition: TTBase.h:343
The TTString class is used to represent a string.
Definition: TTString.h:34
TTErr generateInstance(TTSymbol &childName, TTSymbol &newInstance)
Generate a new instance of a given child.
Definition: TTNode.cpp:578
TTUInt32 countSeparator()
A parsing tool : count how many C_SEPARATOR there is in the address.
Definition: TTAddress.h:206
TTSymbol & getName()
Get the name part.
Definition: TTAddress.h:118
void resize(size_type n)
Change the number of elements.
We build a tree of TTNodes, and you can request a pointer for any TTNode, or add an observer to any T...
TTErr setNameInstance(TTAddress &aNameInstance, TTSymbol &newInstance, TTBoolean *newInstanceCreated)
Set the name and the instance of the node.
Definition: TTNode.cpp:101
[doxygenAppendixC_copyExample]
Definition: TTValue.h:34
TTNodePtr getParent()
Get a pointer to the parent node of the node.
Definition: TTNode.cpp:296