Jamoma API  0.6.0.a19
TTNodeDirectory.cpp
1 /*
2  * TTNodeDirectory
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 "TTNodeDirectory.h"
12 #include <algorithm>
13 
15  root(NULL),
16  mutex(NULL)
17 {
18  // set the name of the tree
19  name = aName;
20 
21  // protect lifeCycleObservers from multithreading access
22  // why ? because observers could disappear when they know an address is destroyed
23  observers.setThreadProtection(true);
24 
25  mutex = new TTMutex(true);
26 
27  init();
28 }
29 
31 {
32  delete root;
33 }
34 
36 {
37  TTBoolean nodeCreated = NO;
38  TTObject empty;
39 
40  // create a new directory
41  directory.clear();
42 
43  // create a new aliases table
44  aliases.clear();
45 
46  // don't clear observers !
47 
48  // create a root with no object
49  return TTNodeCreate(kTTAdrsRoot, empty, this, &this->root, &nodeCreated);
50 }
51 
53 {
54  name = aName;
55  return kTTErrNone;
56 }
57 
59 {
60  return name;
61 }
62 
64 {
65  return root;
66 }
67 
69 {
70  return &directory;
71 }
72 
73 TTErr TTNodeDirectory::getTTNode(const char* anAddress, TTNodePtr* returnedTTNode)
74 {
75  return getTTNode(TTAddress(anAddress), returnedTTNode);
76 }
77 
78 TTErr TTNodeDirectory::getTTNode(TTAddress anAddress, TTNodePtr* returnedTTNode)
79 {
80  TTAddress noAlias;
81  TTErr err;
82  TTValue found;
83 
84  // look into the hashtab to check if the address exist in the tree
85  err = directory.lookup(anAddress.normalize(), found);
86 
87  // if the address exists : return the TTNode
88  if (err != kTTErrValueNotFound) {
89  *returnedTTNode = TTNodePtr((TTPtr)found[0]);
90  return kTTErrNone;
91  }
92 
93  noAlias = anAddress;
94  if (!this->replaceAlias(noAlias))
95  return getTTNode(noAlias, returnedTTNode);
96  else
97  return kTTErrGeneric;
98 }
99 
101 {
102  TTValue v, ak;
103  TTAddress alias;
104  TTAddress aliasAddress;
106  TTInt8 d;
107 
108  // Retrieve the alias binding on this address
109  aliases.getKeys(ak);
110  for (int i=0; i < aliases.getKeys(ak); i++) {
111 
112  alias = ak[i];
113  aliases.lookup(*alias, v);
114  aliasAddress = v[1];
115  comp = anAddress.compare(aliasAddress, d);
116 
117  if (comp == kAddressEqual) {
118  returnedAlias = aliasAddress;
119  break;
120  }
121  }
122 
123  return kTTErrNone;
124 }
125 
127 {
128  TTInt8 d;
129  TTUInt32 s, i, c;
130  TTAddress alias;
131  TTAddress aliasAddress;
132  TTAddress p1;
133  TTAddress p2;
134  TTValue ak, found;
136 
137  // if this address doesn't exist look into aliases
138  this->aliases.getKeys(ak);
139  s = ak.size();
140  if (s == 0)
141  return kTTErrGeneric;
142 
143  // compare the address to each aliases
144  for (i = 0; i < s; i++) {
145 
146  alias = ak[i];
147  comp = anAddress.compare(alias, d);
148 
149  // if the address is an alias : return the TTNode
150  if (comp == kAddressEqual) {
151  aliases.lookup(alias, found);
152  aliasAddress = found[1];
153 
154  anAddress = aliasAddress;
155  break;
156  }
157 
158  // the address is under an alias :
159  // get the address of the alias and join anAddress (without the alias part)
160  if (comp == kAddressLower) {
161  aliases.lookup(alias, found);
162  aliasAddress = found[1];
163  c = found[2];
164 
165  anAddress.splitAt(c, p1, p2);
166  anAddress = aliasAddress.appendAddress(p2);
167  break;
168  }
169  }
170 
171  if (found.empty())
172  return kTTErrGeneric;
173  else
174  return kTTErrNone;
175 }
176 
177 TTErr TTNodeDirectory::fillAddressItem(TTAddressItemPtr anAddressItem, TTAddress startAddress)
178 {
179  TTAddressItemPtr anItem;
180  TTNodePtr aNode;
181  TTList aNodeList;
182  TTAddress anAddress;
183 
184  // get the node where to start from
185  if (!getTTNode(startAddress, &aNode)) {
186 
187  // get all children of the node
188  aNode->getChildren(S_WILDCARD, S_WILDCARD, aNodeList);
189 
190  // sort the NodeList using object priority order
191  aNodeList.sort(&compareNodePriorityThenNameThenInstance);
192 
193  // append each name.instance to the sub namespace
194  for (aNodeList.begin(); aNodeList.end(); aNodeList.next()) {
195 
196  aNode = TTNodePtr((TTPtr)aNodeList.current()[0]);
197 
198  // get name.instance
199  aNode->getAddress(anAddress, startAddress);
200 
201  // if the item doesn't exist yet
202  if (anAddressItem->find(anAddress, &anItem) == kTTErrValueNotFound) {
203 
204  // append it to the namespace
205  anAddressItem->append(anAddress, &anItem);
206 
207  // select the item
208  anItem->setSelection(YES);
209  }
210 
211  // fill this item
212  fillAddressItem(anItem, startAddress.appendAddress(anAddress));
213  }
214 
215  return kTTErrNone;
216  }
217 
218  return kTTErrGeneric;
219 }
220 
221 TTErr TTNodeDirectory::TTNodeCreate(TTAddress& anAddress, TTObject& newObject, void *aContext, TTNodePtr *returnedTTNode, TTBoolean *newInstanceCreated)
222 {
223  TTAddress normalizedAddress, effectiveAddress;
224  TTSymbol newInstance;
225  TTBoolean parent_created;
226  TTValue found;
227  TTNodePtr newTTNode = NULL;
228  TTNodePtr n_found = NULL;
229  TTErr err;
230  TTValue v, c;
231 
232  // remove any directory or attribute part
233  normalizedAddress = anAddress.normalize();
234 
235  // is there a TTNode with this address in the tree ?
236  err = directory.lookup(normalizedAddress, found);
237 
238  // if it's the first at this address
239  if (err == kTTErrValueNotFound) {
240 
241  // keep the instance found in the address
242  newInstance = normalizedAddress.getInstance();
243  *newInstanceCreated = false;
244  }
245  else {
246 
247  // this address already exists
248  // get the TTNode at this address
249  n_found = TTNodePtr((TTPtr)found[0]);
250 
251  // Autogenerate a new instance
252  n_found->getParent()->generateInstance(n_found->getName(), newInstance);
253  *newInstanceCreated = true;
254  }
255 
256  // CREATION OF A NEW TTNode
257  ///////////////////////////
258 
259  // 1. Create a new TTNode
260  newTTNode = new TTNode(normalizedAddress.getName(), newInstance, newObject, aContext, this);
261 
262  // 2. Ensure that the path to the new TTNode exists
263  if (normalizedAddress.getParent() != NO_PARENT) {
264 
265  // set his parent
266  parent_created = false;
267  newTTNode->setParent(normalizedAddress.getParent(), &parent_created);
268 
269  // add the new TTNode as a children of his parent
270  newTTNode->getParent()->setChild(newTTNode);
271 
272  // if the new TTNode have a NULL context, set the parent context
273  if (!aContext) newTTNode->setContext(newTTNode->getParent()->getContext());
274  }
275  else
276  // the new TTNode is the root : no parent
277  ;
278 
279  // 3. Add the effective address (with the generated instance) to the global hashtab
280  newTTNode->getAddress(effectiveAddress);
281  directory.append(effectiveAddress, newTTNode);
282 
283  // 4. Notify observers that a node have been created AFTER the creation
284  this->notifyObservers(effectiveAddress, newTTNode, kAddressCreated);
285 
286  // 5. returned the new TTNode
287  *returnedTTNode = newTTNode;
288 
289  return kTTErrNone;
290 }
291 
293 {
294  TTErr err;
295  TTNodePtr oldNode, parentNode;
296  TTList childrenList;
297  TTValue v;
298  TTObject obj;
299  TTAddress parentAddress, normalizedAddress;
300 
301  // remove any directory or attribute part
302  normalizedAddress = anAddress.normalize();
303 
304  // can't destroy the root (use the TTNodeDirectory destructor)
305  if (normalizedAddress != kTTAdrsRoot) {
306 
307  // find the TTNode in the directory
308  err = this->getTTNode(normalizedAddress, &oldNode);
309 
310  if (!err) {
311 
312  // Notify observers that a node will be destroyed BEFORE the destruction
313  this->notifyObservers(normalizedAddress, oldNode, kAddressDestroyed);
314 
315  // Remove his address
316  err = directory.remove(normalizedAddress);
317 
318  // Get parent node
319  parentNode = oldNode->getParent();
320 
321  // Destroy the TTNode
322  if (!err)
323  delete oldNode;
324 
325  // If parent node have no more child and refers to a none valid object : destroy
326  parentNode->getChildren(S_WILDCARD, S_WILDCARD, childrenList);
327  obj = parentNode->getObject();
328 
329  if (childrenList.isEmpty() && !obj.valid()) {
330  // find the TTNode in the directory
331  parentNode->getAddress(parentAddress);
332  TTNodeRemove(parentAddress);
333  }
334  }
335  }
336  else
337  return kTTErrGeneric;
338 
339  return err;
340 }
341 
343 {
344  TTNodePtr aNode;
345  TTValue v;
346  TTErr err;
347 
348  if (alias.getType() == kAddressRelative ||
349  alias.getAttribute() != NO_ATTRIBUTE ||
350  anAddress.getAttribute() != NO_ATTRIBUTE)
351  return kTTErrGeneric;
352 
353  // find the address in the directory
354  err = this->getTTNode(anAddress, &aNode);
355 
356  if (!err) {
357 
358  // add the alias and store the TTNode and info usefull for replaceAlias method
359  v = TTValue(aNode);
360  v.append(anAddress);
361  v.append(alias.countSeparator());
362 
363  err = aliases.append(alias, v);
364 
365  if (!err)
366  // notify observers that an address has been created
367  this->notifyObservers(alias, aNode, kAddressCreated);
368  }
369 
370  return err;
371 }
372 
374 {
375  TTNodePtr aNode;
376  TTAddress anAddress;
377  TTErr err;
378 
379  // find the alias in the directory
380  err = this->getTTNode(alias, &aNode);
381 
382  if (!err) {
383 
384  // check if the alias is an effective alias
385  aNode->getAddress(anAddress);
386  if (alias == anAddress)
387  return kTTErrGeneric;
388 
389  // remove the alias from the directory
390  err = aliases.remove(alias);
391 
392  if (!err)
393  // notify observers that an address has been removed
394  this->notifyObservers(alias, aNode, kAddressDestroyed);
395  }
396 
397  return err;
398 }
399 
400 TTErr TTNodeDirectory::Lookup(TTAddress anAddress, TTList& returnedTTNodes, TTNodePtr *firstReturnedTTNode)
401 {
402  TTList lk_selection, lk_children;
403  TTNodePtr n_r;
404  TTErr err;
405 
406  // Make sure we are dealing with an absolute address
407  if (anAddress.getType() != kAddressAbsolute)
408  return kTTErrGeneric;
409 
410  // lonely wilcard case : * equals *.*
411  if (anAddress.getName() == S_WILDCARD && anAddress.getInstance() == kTTSymEmpty)
412  return Lookup(anAddress.appendInstance(S_WILDCARD), returnedTTNodes, firstReturnedTTNode);
413 
414  // Is there a wild card anywhere else ?
415  if (strrchr(anAddress.c_str(), C_WILDCARD)) {
416 
417  // Here is a recursive call to the TTNodeDirectory Lookup to get all TTNodes at upper levels
418  err = Lookup(anAddress.getParent(), returnedTTNodes, firstReturnedTTNode);
419 
420  // for each returned TTNodes at upper levels
421  // select all corresponding "name.instance" TTNodes
422  // among the TTNode list.
423  if (!returnedTTNodes.isEmpty()) {
424 
425  // select all children of all parent nodes
426  for (returnedTTNodes.begin(); returnedTTNodes.end(); returnedTTNodes.next()) {
427 
428  n_r = TTNodePtr((TTPtr)returnedTTNodes.current()[0]);
429  n_r->getChildren(anAddress.getName(), anAddress.getInstance(), lk_children);
430 
431  if (!lk_children.isEmpty())
432  lk_selection.merge(lk_children);
433  }
434 
435  // return the selection
436  returnedTTNodes.clear();
437 
438  if (!lk_selection.isEmpty()) {
439  returnedTTNodes.merge(lk_selection);
440  *firstReturnedTTNode = TTNodePtr((TTPtr)returnedTTNodes.getHead()[0]);
441  }
442  else
443  err = kTTErrGeneric;
444  }
445 
446  return err;
447  }
448  // no wild card : do a lookup in the global hashtab
449  else {
450 
451  // look into the hashtab
452  err = getTTNode(anAddress, &n_r);
453 
454  // if the node exists
455  if (err == kTTErrNone) {
456  returnedTTNodes.append(n_r);
457  *firstReturnedTTNode = n_r;
458  }
459 
460  return err;
461  }
462 }
463 
464 TTErr TTNodeDirectory::LookFor(TTListPtr whereToSearch, TTBoolean(*testFunction)(TTNodePtr node, TTPtr args), void *argument, TTList& returnedTTNodes, TTNodePtr *firstReturnedTTNode, TTUInt8 depthLimit, TTBoolean(*comparisonFunction)(TTValue& v1, TTValue& v2))
465 {
466  TTList lk_children;
467  TTNodePtr n_r, n_child, n_first;
468  TTBoolean limitReached = false;
469  TTUInt8 newLimit = 0;
470  TTErr err;
471 
472  *firstReturnedTTNode = NULL;
473 
474  // is the limit is reached ?
475  if (depthLimit > 0) {
476  newLimit = depthLimit - 1;
477  limitReached = newLimit <= 0;
478  }
479 
480  // if there are nodes from where to start
481  if (!whereToSearch->isEmpty()) {
482 
483  // Launch a recursive research below each given nodes
484  for (whereToSearch->begin(); whereToSearch->end(); whereToSearch->next()) {
485 
486  // get all children of the node
487  n_r = TTNodePtr((TTPtr)whereToSearch->current()[0]);
488  n_r->getChildren(S_WILDCARD, S_WILDCARD, lk_children);
489 
490  // sort children if needed
491  if (comparisonFunction)
492  lk_children.sort(comparisonFunction);
493 
494  // if there are children
495  if (!lk_children.isEmpty()) {
496 
497  // test each of them and add those which are ok
498  n_first = NULL;
499  for (lk_children.begin(); lk_children.end(); lk_children.next())
500  {
501  n_child = TTNodePtr((TTPtr)lk_children.current()[0]);
502 
503  // test the child and fill the returnedTTNodes
504  if (testFunction(n_child, argument))
505  {
506  returnedTTNodes.append(n_child);
507 
508  if (!n_first)
509  n_first = n_child;
510  }
511 
512  // go one step deeper in the tree if possible
513  if (!limitReached)
514  {
515  TTList oneNodeList;
516  oneNodeList.append((TTPtr)n_child);
517  if (LookFor(&oneNodeList, testFunction, argument, returnedTTNodes, firstReturnedTTNode, newLimit, comparisonFunction))
518  err = kTTErrGeneric;
519  }
520  else
521  err = kTTErrNone;
522  }
523 
524  if(!returnedTTNodes.isEmpty() && !n_first)
525  *firstReturnedTTNode = TTNodePtr((TTPtr)returnedTTNodes.getHead()[0]);
526  else if (n_first)
527  *firstReturnedTTNode = n_first;
528 
529  if (err != kTTErrNone)
530  return err;
531  }
532  }
533  return kTTErrNone;
534  }
535  return kTTErrGeneric;
536 }
537 
538 TTErr TTNodeDirectory::IsThere(TTListPtr whereToSearch, TTBoolean(*testFunction)(TTNodePtr node, void*args), void *argument, bool *isThere, TTNodePtr *firstTTNode)
539 {
540  TTList lk_children;
541  TTNodePtr n_r, n_child;
542  TTErr err, err_look;
543 
544  // if there are nodes from where to start
545  if (!whereToSearch->isEmpty()) {
546 
547  // Launch a recursive research below each given nodes
548  for (whereToSearch->begin(); whereToSearch->end(); whereToSearch->next()) {
549 
550  // get all children of the node
551  n_r = TTNodePtr((TTPtr)whereToSearch->current()[0]);
552  err = n_r->getChildren(S_WILDCARD, S_WILDCARD, lk_children);
553 
554  // if there are children
555  if (err == kTTErrNone) {
556 
557  // test each of them and add those which are ok
558  for (lk_children.begin(); lk_children.end(); lk_children.next()) {
559 
560  n_child = TTNodePtr((TTPtr)lk_children.current()[0]);
561 
562  // test the child and fill the returnedTTNodes
563  if (testFunction(n_child, argument)) {
564  (*isThere) = true;
565  (*firstTTNode) = n_child;
566  return kTTErrNone;
567  }
568  else
569  (*isThere) = false;
570  }
571 
572  // continu the research from all children
573  err_look = IsThere(&lk_children, testFunction, argument, isThere, firstTTNode);
574 
575  if (err_look != kTTErrNone)
576  return err_look;
577 
578  // if a node is found below, stop the research
579  if ((*isThere))
580  return kTTErrNone;
581  }
582  else
583  (*isThere) = false;
584  }
585  return kTTErrNone;
586  }
587  return kTTErrGeneric;
588 }
589 
591 {
592  TTErr err;
593  TTValue lk;
594  TTValue o = anObserver;
595  TTListPtr lk_o;
596  TTAddress adrs;
597 
598  // enable observers protection
599  mutex->lock();
600 
601  // don't look at attribute and directory
602  adrs = anAddress.normalize();
603 
604  // append maxDepthDifference criteria if it is different from 0
605  if (maxDepthDifference >= 0)
606  o.append(maxDepthDifference);
607 
608  // is the key already exists ?
609  err = this->observers.lookup(adrs, lk);
610 
611  // create a new observers list for this address
612  if (err == kTTErrValueNotFound){
613  lk_o = new TTList();
614  lk_o->appendUnique(o);
615 
616  this->observers.append(adrs, lk_o);
617  }
618  // add it to the existing list
619  else {
620  lk_o = TTListPtr((TTPtr)lk[0]);
621  lk_o->appendUnique(o);
622  }
623 
624  // disable observers protection
625  mutex->unlock();
626 
627  return kTTErrNone;
628 }
629 
631 {
632  TTErr err;
633  TTValue lk, o, v;
634  TTListPtr lk_o;
635  TTAddress adrs;
636 
637  // enable observers protection
638  mutex->lock();
639 
640  // don't look at attribute and directory
641  adrs = anAddress.normalize();
642 
643  // is the key exists ?
644  err = this->observers.lookup(adrs, lk);
645 
646  if (err != kTTErrValueNotFound){
647 
648  // get the observers list
649  lk_o = TTListPtr((TTPtr)lk[0]);
650 
651  // is observer exists ?
652  err = lk_o->find(&findObserver, anObserver.instance(), v);
653  if (!err)
654  lk_o->remove(v);
655 
656  // was it the last observer ?
657  if (lk_o->isEmpty()) {
658 
659  // remove the key
660  this->observers.remove(adrs);
661 
662  // delete the list
663  delete lk_o;
664  }
665  }
666 
667  // disable observers protection
668  mutex->unlock();
669 
670  return err;
671 }
672 
674 {
676  TTValue hk, lk, o, f, data;
677  TTAddress key, adrs, noAlias;
678  TTListPtr lk_o;
679  TTObject anObserver;
680  TTInt8 depthDifference, maxDepthDifference;
681  TTUInt32 i;
682  TTBoolean foundObsv = NO;
683 
684  // if there are observers
685  if (!this->observers.isEmpty()) {
686 
687  // enable observers protection
688  mutex->lock();
689 
690  this->observers.getKeys(hk);
691 
692  // don't look at attribute and address
693  adrs = anAddress.normalize();
694 
695  // for each key of mObserver tab
696  for (i = 0; i < hk.size(); i++) {
697 
698  key = hk[i];
699 
700  // compare the key
701  comp = adrs.compare(key, depthDifference);
702 
703  // if the address is upper in the tree : the observer don't need to be notified
704  if (comp == kAddressUpper)
705  continue;
706 
707  // if the address is different : maybe the observer used an alias
708  if (comp == kAddressDifferent) {
709 
710  // remove the alias part of the key if exists
711  noAlias = key;
712  if (!this->replaceAlias(noAlias))
713  comp = adrs.compare(noAlias, depthDifference);
714  }
715 
716  // if the address is equal or lower : the observer have to be notified
717  if ((comp == kAddressEqual) || (comp == kAddressLower)) {
718 
719  // get the Observers list
720  if (!this->observers.lookup(key, lk)) {
721 
722  lk_o = NULL;
723  lk_o = TTListPtr((TTPtr)lk[0]);
724 
725  if (!lk_o->isEmpty()) {
726 
727  for (lk_o->begin(); lk_o->end(); lk_o->next()) {
728 
729  anObserver = lk_o->current()[0];
730 
731  // filter on the depth difference if specified
732  if (lk_o->current().size() > 1) {
733  maxDepthDifference = lk_o->current()[1];
734 
735  // we can cast the depth difference because it is always positive in the lower case
736  if (depthDifference > maxDepthDifference)
737  continue;
738  }
739 
740  data.append(anAddress);
741  data.append(aNode);
742  data.append((TTInt8)flag);
743  data.append(anObserver);
744  anObserver.send("notify", data);
745  }
746 
747  foundObsv = true;
748  }
749  }
750  }
751  }
752 
753  // disable observers protection
754  mutex->unlock();
755 
756  if (foundObsv)
757  return kTTErrNone;
758  else
759  return kTTErrGeneric;
760  }
761  else
762  return kTTErrGeneric;
763 }
764 
765 /***********************************************************************************
766  *
767  * GLOBAL METHODS
768  *
769  ************************************************************************************/
770 
771 TTBoolean testNodeObject(TTNodePtr n, TTPtr args)
772 {
773  TTObject o;
774 
775  o = n->getObject();
776 
777  return o.instance() == TTObjectBasePtr(args);
778 }
779 
780 TTBoolean testNodeObjectType(TTNodePtr n, TTPtr args)
781 {
782  TTObject o;
783 
784  o = n->getObject();
785 
786  if (o.valid())
787  return o.name().rawpointer() == args;
788  else
789  return NO;
790 }
791 
792 TTBoolean testNodeContext(TTNodePtr n, TTPtr args)
793 {
794  TTPtr c;
795 
796  c = n->getContext();
797 
798  if (c)
799  return c == args;
800  else
801  return NO;
802 }
803 
804 TTBoolean testNodeUsingCallback(TTNodePtr n, TTPtr args)
805 {
806  TTValue v = TTValue((TTPtr)n);
807  TTCallbackPtr aCallback = (TTCallbackPtr)args;
808 
809  aCallback->notify(v,v);
810 
811  return v == 1;
812 }
813 
814 TTBoolean testNodeUsingFilter(TTNodePtr n, TTPtr args)
815 {
816  TTValuePtr argsValue = (TTValuePtr)args;
817  TTHashPtr filterBank;
818  TTListPtr filterList;
819  TTSymbol aFilterName;
820  TTSymbol filterMode;
821  TTDictionaryBasePtr aFilter;
822  TTObject anObject;
823  TTAddress anAddress;
824  TTValue v;
825  TTBoolean resultFilter, result = YES;
826  TTBoolean firstFilter = YES;
827  TTErr err;
828 
829  filterBank = TTHashPtr((TTPtr)(*argsValue)[0]);
830  filterList = TTListPtr((TTPtr)(*argsValue)[1]);
831 
832  if (!filterList->isEmpty()) {
833 
834  // get object
835  anObject = n->getObject();
836 
837  // get address
838  n->getAddress(anAddress, kTTAdrsRoot);
839 
840  // for each filter name
841  for (filterList->begin(); filterList->end(); filterList->next()) {
842 
843  // if no filter all nodes are included in the result
844  filterMode = kTTSym_restrict;
845 
846  // get the next filter name from the list
847  // and get it from the bank
848  aFilter = NULL;
849  aFilterName = filterList->current()[0];
850  err = filterBank->lookup(aFilterName, v);
851 
852  // TEST FILTER : the result is YES if the node have to be in the result
853  if (!err) {
854 
855  // local declarations for the test
856  TTBoolean resultObject = YES;
857  TTBoolean resultAttribute = YES;
858  TTBoolean resultValue = YES;
859  TTBoolean resultPart = YES;
860  TTBoolean resultParent = YES;
861  TTBoolean resultName = YES;
862  TTBoolean resultInstance = YES;
863 
864  TTRegex* aRegex;
865  TTString s_toParse;
866  TTStringIter begin, end;
867 
868  // get filter
869  aFilter = TTDictionaryBasePtr((TTPtr)v[0]);
870 
871  // get filter mode :
872  // - in default exclusion mode, if one field of a filter matches a node, this node is excluded.
873  // - in inclusion mode, if all fields of a filter match a node, this node is included.
874  if (!aFilter->lookup(kTTSym_mode, v))
875  filterMode = v[0];
876 
877  // test object name
878  if (!aFilter->lookup(kTTSym_object, v)) {
879 
880  TTSymbol objectFilter;
881  objectFilter = v[0];
882 
883  // a node without object can be selected using the none symbol
884  if (!anObject.valid())
885  resultObject = objectFilter == kTTSym_none;
886  else
887  resultObject = objectFilter == anObject.name();
888  }
889 
890  // test attribute name
891  if (!aFilter->lookup(kTTSym_attribute, v)) {
892 
893  TTSymbol attributeFilter;
894  TTValue valueFilter;
895  attributeFilter = v[0];
896 
897  // a node without object have no attribute
898  if (!anObject.valid()) {
899  resultAttribute = NO;
900  resultValue = NO;
901  }
902  else {
903 
904  err = anObject.get(attributeFilter, v);
905 
906  // the existence of the attribute is also a way to filter nodes
907  resultAttribute = err == kTTErrNone;
908 
909  // if the attribute exists
910  if (!err) {
911 
912  // test value
913  if (!aFilter->lookup(kTTSym_value, valueFilter)) {
914 
915  // special case for tag attribute : just check if one element of the value to filter exist in the tag
916  if (attributeFilter == kTTSym_tags) {
917 
918  for (TTUInt32 i = 0; i < valueFilter.size(); i++) {
919 
920  TTSymbol tagFilter = valueFilter[i];
921 
922  for (TTUInt32 j = 0; j < v.size(); j++) {
923 
924  TTSymbol aTag = v[j];
925 
926  resultValue = aTag == tagFilter;
927 
928  if (resultValue)
929  break;
930  }
931 
932  if (resultValue)
933  break;
934  }
935  }
936 
937  // compare the whole value
938  else
939  resultValue = valueFilter == v;
940  }
941  }
942  }
943  }
944 
945  // test any part of address
946  if (!aFilter->lookup(kTTSym_part, v)) {
947 
948  TTSymbol partFilter;
949  partFilter = v[0];
950  aRegex = new TTRegex(partFilter.c_str());
951 
952  s_toParse = anAddress.c_str();
953  begin = s_toParse.begin();
954  end = s_toParse.end();
955 
956  // test if the regex find something
957  if (!aRegex->parse(begin, end))
958  resultPart = begin != end;
959  else
960  resultPart = NO;
961 
962  delete aRegex;
963  }
964 
965  // test address parent part
966  if (!aFilter->lookup(kTTSym_parent, v)) {
967 
968  TTSymbol parentFilter;
969  parentFilter = v[0];
970  aRegex = new TTRegex(parentFilter.c_str());
971 
972  s_toParse = anAddress.getParent().c_str();
973  begin = s_toParse.begin();
974  end = s_toParse.end();
975 
976  // test if the regex find something
977  if (!aRegex->parse(begin, end))
978  resultParent = begin != end;
979  else
980  resultParent = NO;
981 
982  delete aRegex;
983  }
984 
985  // test address name part
986  if (!aFilter->lookup(kTTSym_name, v)) {
987 
988  TTSymbol nameFilter;
989  nameFilter = v[0];
990  aRegex = new TTRegex(nameFilter.c_str());
991 
992  s_toParse = anAddress.getName().c_str();
993  begin = s_toParse.begin();
994  end = s_toParse.end();
995 
996  // test if the regex find something
997  if (!aRegex->parse(begin, end))
998  resultName = begin != end && begin == s_toParse.begin();
999  else
1000  resultName = NO;
1001 
1002  delete aRegex;
1003  }
1004 
1005  // test address instance part
1006  if (!aFilter->lookup(kTTSym_instance, v)) {
1007 
1008  TTSymbol instanceFilter;
1009  instanceFilter = v[0];
1010  aRegex = new TTRegex(instanceFilter.c_str());
1011 
1012  s_toParse = anAddress.getInstance().c_str();
1013  begin = s_toParse.begin();
1014  end = s_toParse.end();
1015 
1016  // test if the regex find something
1017  if (!aRegex->parse(begin, end))
1018  resultInstance = begin != end && begin == s_toParse.begin();
1019  else
1020  resultInstance = NO;
1021 
1022  delete aRegex;
1023  }
1024 
1025  // process the filter statement
1026  resultFilter = resultObject && resultAttribute && resultValue && resultPart && resultParent && resultName && resultInstance;
1027  }
1028 
1029  // the next filter will not be a first filter anymore...
1030  if (firstFilter)
1031  firstFilter = NO;
1032 
1033  // propagate the resultFilter to the
1034  // final result depending on the filter mode
1035  if (filterMode == kTTSym_include)
1036  result = result || resultFilter; // keep the node if it matches this filter (what ever the first filters)
1037  else if (filterMode == kTTSym_restrict)
1038  result = result & resultFilter; // keep the node if it matches this filter (and matches the first filters)
1039  else if (filterMode == kTTSym_exclude)
1040  result = result & !resultFilter; // keep the node if it doesn't matches this filter (and matches the first filters)
1041  else if (filterMode == TTSymbol("hamlet"))
1042  result = result || !resultFilter; // keep the node if it doesn't match this filter (what ever the first filters)
1043 
1044  }
1045  }
1046  // if the filter list is empty return YES
1047  else
1048  result = YES;
1049 
1050  return result;
1051 }
1052 
1053 TTBoolean compareNodePriorityThenNameThenInstance(TTValue& v1, TTValue& v2)
1054 {
1055  TTNodePtr n1, n2;
1056  TTObject o1, o2;
1057  TTValue v;
1058  TTValue name1;
1059  TTValue name2;
1060  TTValue instance1;
1061  TTValue instance2;
1062  TTInt32 p1 = 0;
1063  TTInt32 p2 = 0;
1064 
1065  // get priority of v1
1066  n1 = TTNodePtr((TTPtr)v1[0]);
1067  if (n1) {
1068 
1069  name1 = TTString(n1->getName().c_str()); // to convert number name
1070  instance1 = TTString(n1->getInstance().c_str()); // to convert number instance
1071  o1 = n1->getObject();
1072 
1073  if (o1.valid())
1074  if (!o1.get(kTTSym_priority, v))
1075  p1 = v[0];
1076  }
1077 
1078  // get priority of v2
1079  n2 = TTNodePtr((TTPtr)v2[0]);
1080  if (n2) {
1081 
1082  name2 = TTString(n2->getName().c_str());
1083  instance2 = TTString(n2->getInstance().c_str());
1084  o2 = n2->getObject();
1085 
1086  if (o2.valid())
1087  if (!o2.get(kTTSym_priority, v))
1088  p2 = v[0];
1089  }
1090 
1091  if (p1 == p2) {
1092 
1093  name1.fromString();
1094  name2.fromString();
1095 
1096  if (name1.size() != name2.size())
1097  return YES;
1098 
1099  if (name1[0].type() != name2[0].type())
1100  return YES;
1101 
1102  if (name1 == name2) {
1103 
1104  instance1.fromString();
1105  instance2.fromString();
1106 
1107  if (instance1.size() != instance2.size())
1108  return YES;
1109 
1110  if (instance1[0].type() != instance2[0].type())
1111  return YES;
1112 
1113  if (instance1 == instance2)
1114  return v1 < v2;
1115  else
1116  return instance1 < instance2;
1117  }
1118  else
1119  return name1 < name2;
1120  }
1121 
1122  if (p1 == 0) return NO;
1123  if (p2 == 0) return YES;
1124 
1125  return p1 < p2;
1126 }
1127 
1128 void findObserver(const TTValue& value, TTPtr observerToMatch, TTBoolean& found)
1129 {
1130  TTObject anObserver = value[0];
1131  found = anObserver.instance() == TTObjectBasePtr(observerToMatch);
1132 }
1133 
1134 #endif
TTAddress appendAddress(const TTAddress &toAppend)
Return a new TTAddress with the appended part.
Definition: TTAddress.h:167
TTErr setContext(TTPtr aContext)
Set the context of the node.
Definition: TTNode.cpp:277
TTErr replaceAlias(TTAddress &anAddress)
Given an address with alias, return an address with no alias if exists.
bool TTBoolean
Boolean flag, same as Boolean on the Mac.
Definition: TTBase.h:167
void fromString(TTBoolean numberAsSymbol=NO)
Convert a single string into individual elements using space to divide items.
Definition: TTValue.h:386
TTErr setParent(TTAddress parentAddress, TTBoolean *newParentCreated)
Set the parent of the node.
Definition: TTNode.cpp:202
TTDictionaryBase * TTDictionaryBasePtr
Pointer to a TTDictionary.
this flag means that a TTNode have been destroyed in the tree structure
Definition: TTAddressBase.h:56
This class is used to be sensitive to any TTObject notifications and report them using a function wit...
Definition: TTCallback.h:28
TTErr send(const TTSymbol aName)
Send a message to this object with no arguments.
Definition: TTObject.cpp:135
TTSymbol & getInstance()
Get the instance part.
Definition: TTAddress.h:124
this flag means that address1 an address2 refer to nodes which are in a different branch in the tree ...
Definition: TTAddressBase.h:47
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.
We build a directory of TTNodes, and you can request a pointer for any TTNode, or add an observer to ...
Definition: TTNode.h:59
A type that contains a key and a value.
TTSymbol getName()
Get the name of the TTNodeDirectory.
TTErr AliasRemove(TTAddress alias)
Create an alias address.
TTAddress getParent()
Get a pointer to the parent address.
Definition: TTAddress.h:112
TTPtr getContext()
Get a pointer to the context of this node.
Definition: TTNode.cpp:473
TTNodePtr getRoot()
Get the root of the TTNodeDirectory.
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.
TTAddressNotificationFlag
Notification flags to notify observers of a directory.
Definition: TTAddressBase.h:55
TTErr AliasCreate(TTAddress alias, TTAddress anAddress)
Create an alias address.
TTAddress appendInstance(const TTSymbol anInstance)
Return a new TTAddress with a instance part.
Definition: TTAddress.h:173
TTAddress normalize()
Normalize an address for lookup and other directory operations This would return an address without d...
Definition: TTAddress.h:149
this flag means that an address have no leading slash
Definition: TTAddressBase.h:64
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.
Base class for all first-class Jamoma objects.
Definition: TTObjectBase.h:109
TTErr TTNodeRemove(TTAddress &anAddress)
Remove a TTNodefrom the directory.
Maintain a collection of TTValue objects indexed by TTSymbol pointers.
Definition: TTHash.h:36
TTErr Lookup(TTAddress anAddress, TTList &returnedTTNodes, TTNodePtr *firstReturnedTTNode)
Find TTNodes by address.
virtual ~TTNodeDirectory()
Destructor.
TTErr setName(TTSymbol aname)
Set the name of the TTNodeDirectory.
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 get(const TTSymbol aName, T &aReturnedValue) const
Get an attribute value for an object.
TTPtr rawpointer() const
Get the value of the raw pointer into the symbol table.
Definition: TTSymbol.h:134
TTErr setChild(TTNodePtr child)
Add a node as a child of the node.
Definition: TTNode.cpp:227
TTSymbol name() const
Return the name of this class.
Definition: TTObject.cpp:129
this flag means that address1 an address2 refer to the same node in the tree structure ...
Definition: TTAddressBase.h:48
TTSymbol & getInstance()
Get the instance of the node.
Definition: TTNode.cpp:291
TTErr getAlias(TTAddress anAddress, TTAddress &returnedAlias)
Given an address, return an alias if exists.
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
TTErr addObserverForNotifications(TTAddress anAddress, TTObject &anObserver, TTInt8 maxDepthDifference=-1)
Add a TTCallback as a life cycle observer of all nodes below this one.
TTBoolean isEmpty()
Return true if the hash has nothing stored in it.
Definition: TTHash.cpp:205
TTErr IsThere(TTListPtr whereToSearch, TTBoolean(*testFunction)(TTNodePtr node, void *args), void *argument, bool *isThere, TTNodePtr *firstTTNode)
Is there is one TTNode or more that respect a test below an address.
TTSymbol & getAttribute()
Get the attribute part.
Definition: TTAddress.h:130
A value was not found when doing a look up for it (in a TTHash, TTList, or other class).
Definition: TTBase.h:352
this flag means that an address have a leading slash
Definition: TTAddressBase.h:65
TTErr lookup(const TTSymbol key, TTValue &value) const
Find the value for the given key.
this flag means that address1 refers to a node at a lower level than address2 in the tree structure ...
Definition: TTAddressBase.h:46
const char * c_str() const
Return a pointer to the internal string as a C-string.
Definition: TTSymbol.h:77
std::int32_t TTInt32
32 bit signed integer
Definition: TTBase.h:177
TTErr clear()
Remove all items from the hash table.
Definition: TTHash.cpp:117
TTErr fillAddressItem(TTAddressItemPtr anAddressItem, TTAddress startAddress=kTTAdrsRoot)
fill an address item using the TTNodeDirectory from an address
TTErr LookFor(TTListPtr whereToSearch, TTBoolean(*testFunction)(TTNodePtr node, TTPtr args), void *argument, TTList &returnedTTNodes, TTNodePtr *firstReturnedTTNode, TTUInt8 depthLimit=0, TTBoolean(*comparisonFunction)(TTValue &v1, TTValue &v2)=NULL)
Find TTNodes by testing each TTNodes below an address.
TTCallback * TTCallbackPtr
Pointer to a TTCallback object.
Definition: TTCallback.h:75
TTAddressComparisonFlag
Comparison flags between address returned by address1->compare(address2).
Definition: TTAddressBase.h:45
TTErr getAddress(TTAddress &returnedAddress, TTAddress from=kTTAdrsEmpty)
Get the address of the node.
Definition: TTNode.cpp:478
this flag means that address1 refers to a node at a upper level than address2 in the tree structure ...
Definition: TTAddressBase.h:49
Something went wrong, but what exactly is not known. Typically used for context-specific problems...
Definition: TTBase.h:344
TTAddressType getType()
Get the type.
Definition: TTAddress.h:136
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
signed char TTInt8
8 bit signed integer (char)
Definition: TTBase.h:173
this flag means that a TTNode have been created in the tree structure
Definition: TTAddressBase.h:57
TTErr removeObserverForNotifications(TTAddress anAddress, TTObject &anObserver)
Remove a TTCallback as a life cycle observer of all nodes below this one.
TTErr init()
Initialize the TTNodeDirectory.
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
size_t size() const
Find out the length of a string.
Definition: TTString.h:144
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
TTObjectBase * instance() const
Return a direct pointer to the internal instance.
Definition: TTObject.cpp:105
No Error.
Definition: TTBase.h:343
TTAddressComparisonFlag compare(const TTAddress &toCompare, TTInt8 &depthDifference)
A comparison tool.
Definition: TTAddress.h:182
TTErr notify(const TTValue &anInputValue, TTValue &anUnusedOutputValue)
Message called because we are registered as an observer to some other object, and then calls our exte...
Definition: TTCallback.cpp:69
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
TTBoolean valid() const
Determine if the object contained by this TTObject is truly ready for use.
Definition: TTObject.cpp:179
TTSymbol & getName()
Get the name part.
Definition: TTAddress.h:118
TTNodeDirectory(TTSymbol aName)
Constructor.
[doxygenAppendixC_copyExample]
Definition: TTValue.h:34
TTNodePtr getParent()
Get a pointer to the parent node of the node.
Definition: TTNode.cpp:296
TTErr getTTNode(const char *anAddress, TTNodePtr *returnedTTNode)
Given an address, return a pointer to a TTNode.
unsigned char TTUInt8
8 bit unsigned integer (char)
Definition: TTBase.h:174