FAUST compiler  0.9.9.6b8
tree.cpp
Go to the documentation of this file.
1 /************************************************************************
2  ************************************************************************
3  FAUST compiler
4  Copyright (C) 2003-2004 GRAME, Centre National de Creation Musicale
5  ---------------------------------------------------------------------
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program; if not, write to the Free Software
18  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  ************************************************************************
20  ************************************************************************/
21 
22 
23 
24 /*****************************************************************************
25 ******************************************************************************
26  TREE
27  Y. Orlarey, (c) Grame 2002
28 ------------------------------------------------------------------------------
29 Trees are made of a Node associated with a list of branches : (Node x [CTree]).
30 Up to 4 branches are allowed in this implementation. A hash table is used to
31 maximize the sharing of trees during construction : trees at different
32 addresses always have a different content. Reference counting is used for
33 garbage collection, and smart pointers P<CTree> should be used for permanent
34 storage of trees.
35 
36  API:
37  ----
38  tree (n) : tree of node n with no branch
39  tree (n, t1) : tree of node n with a branch t
40  tree (n, t1,...,tm) : tree of node n with m branches t1,...,tm
41 
42  Pattern matching :
43 
44  if (isTree (t, n)) ... : t has node n and no branches;
45  if (isTree (t, n, &t1) ... : t has node n and 1 branch, t1 is set accordingly;
46  if (isTree (t, n, &t1...&tm)...: t has node n and m branches, ti's are set accordingly;
47 
48  Accessors :
49 
50  t->node() : the node of t { return fNode; }
51  t->arity() : the number of branches of t return fArity; }
52  t->branch(i) : the ith branch of t
53 
54  Attributs :
55 
56  t->attribut() : return the attribut (also a tree) of t
57  t->attribut(t') : set the attribut of t to t'
58 
59  Warning :
60  ---------
61  Since reference counters are used for garbage collecting, one must be careful not to
62  create cycles in trees The only possible source of cycles is by setting the attribut
63  of a tree t to a tree t' that contains t as a subtree.
64 
65  Properties:
66  -----------
67  If p and q are two CTree pointers :
68  p != q <=> *p != *q
69 
70  History :
71  ---------
72  2002-02-08 : First version
73  2002-10-14 : counts for height and recursiveness added
74 
75 ******************************************************************************
76 *****************************************************************************/
77 
78 #include <stdlib.h>
79 #include <stdio.h>
80 #include <string.h>
81 #include <limits.h>
82 #include "tree.hh"
83 #include <fstream>
84 #include <cstdlib>
85 
86 Tabber TABBER(1);
87 extern Tabber TABBER;
88 
89 
90 static void error(const char * s, Tree t)
91 {
92  //fprintf(stderr, "ERROR : %s (%p)\n", s, t);
93  cerr << "ERROR : " << s << " : " << *t << endl;
94 }
95 
96 #define ERROR(s,t) { error(s,t); exit(1); }
97 
98 
99 Tree CTree::gHashTable[kHashTableSize];
100 bool CTree::gDetails = false;
101 unsigned int CTree::gVisitTime = 0;
102 
103 // Constructor : add the tree to the hash table
104 CTree::CTree (unsigned int hk, const Node& n, const tvec& br)
105  : fNode(n),
106  fType(0),
107  fHashKey(hk),
108  fAperture(calcTreeAperture(n,br)),
109  fVisitTime(0),
110  fBranch(br)
111 {
112  // link dans la hash table
113  int j = hk % kHashTableSize;
114  fNext = gHashTable[j];
115  gHashTable[j] = this;
116 
117 }
118 
119 // Destructor : remove the tree form the hash table
121 {
122  int i = fHashKey % kHashTableSize;
123  Tree t = gHashTable[i];
124 
125  //printf("Delete of "); this->print(); printf("\n");
126  if (t == this) {
127  gHashTable[i] = fNext;
128  } else {
129  Tree p;
130  while (t != this) {
131  p = t;
132  t = t->fNext;
133  }
134  p->fNext = fNext;
135  }
136 }
137 
138 // equivalence
139 bool CTree::equiv (const Node& n, const tvec& br) const
140 {
141  return (fNode == n) && (fBranch == br);
142 }
143 
144 Sym PROCESS = symbol("process");
145 
146 
147 
148 
149 unsigned int CTree::calcTreeHash( const Node& n, const tvec& br )
150 {
151  unsigned int hk = n.type() ^ n.getInt();
152  tvec::const_iterator b = br.begin();
153  tvec::const_iterator z = br.end();
154 
155  while (b != z) {
156  hk = (hk << 1) ^ (hk >> 20) ^ ((*b)->fHashKey);
157  ++b;
158  }
159  return hk;
160 }
161 
162 
163 Tree CTree::make(const Node& n, int ar, Tree* tbl)
164 {
165  tvec br(ar);
166 
167  for (int i=0; i<ar; i++) br[i] = tbl[i];
168 
169  unsigned int hk = calcTreeHash(n, br);
170  Tree t = gHashTable[hk % kHashTableSize];
171 
172  while (t && !t->equiv(n, br)) {
173  t = t->fNext;
174  }
175  return (t) ? t : new CTree(hk, n, br);
176 }
177 
178 
179 Tree CTree::make(const Node& n, const tvec& br)
180 {
181  unsigned int hk = calcTreeHash(n, br);
182  Tree t = gHashTable[hk % kHashTableSize];
183 
184  while (t && !t->equiv(n, br)) {
185  t = t->fNext;
186  }
187  return (t) ? t : new CTree(hk, n, br);
188 }
189 
190 ostream& CTree::print (ostream& fout) const
191 {
192  if (gDetails) {
193  // print the adresse of the tree
194  fout << "<" << this << ">@";
195  }
196  fout << node();
197  int a = arity();
198  if (a > 0) {
199  int i; char sep;
200  for (sep = '[', i = 0; i < a; sep = ',', i++) {
201  fout << sep; branch(i)->print(fout);
202  }
203  fout << ']';
204  }
205 
206  return fout;
207 }
208 
209 
211 {
212  printf("\ngHashTable Content :\n\n");
213  for (int i = 0; i < kHashTableSize; i++) {
214  Tree t = gHashTable[i];
215  if (t) {
216  printf ("%4d = ", i);
217  while (t) {
218  /*t->print();*/
219  printf(" => ");
220  t = t->fNext;
221  }
222  printf("VOID\n");
223  }
224  }
225  printf("\nEnd gHashTable\n");
226 
227 }
228 
229 // if t has a node of type int, return it otherwise error
230 int tree2int (Tree t)
231 {
232  double x;
233  int i;
234 
235  if (isInt(t->node(), &i)) {
236  // nothing to do
237  } else if (isDouble(t->node(), &x)) {
238  i = int(x);
239  } else {
240  ERROR("the node of the tree is not an int nor a float", t);
241  }
242  return i;
243 }
244 
245 // if t has a node of type float, return it otherwise error
246 double tree2float (Tree t)
247 {
248  double x;
249  int i;
250 
251  if (isInt(t->node(), &i)) {
252  x = double(i);
253  } else if (isDouble(t->node(), &x)) {
254  //nothing to do
255  } else {
256  ERROR("the node of the tree is not a float nor an int", t);
257  }
258  return x;
259 }
260 
261 // if t has a node of type float, return it as a double otherwise error
262 double tree2double (Tree t)
263 {
264  double x;
265  int i;
266 
267  if (isInt(t->node(), &i)) {
268  x = double(i);
269  } else if (isDouble(t->node(), &x)) {
270  //nothing to do
271  } else {
272  ERROR("the node of the tree is not a float nor an int", t);
273  }
274  return double(x);
275 }
276 
277 // if t has a node of type symbol, return its name otherwise error
278 const char* tree2str (Tree t)
279 {
280  Sym s;
281  if (!isSym(t->node(), &s)) {
282  ERROR("the node of the tree is not a symbol", t);
283  }
284  return name(s);
285 }
286 
287 // if t has a node of type ptr, return it otherwise error
288 void* tree2ptr (Tree t)
289 {
290  void* x;
291  if (! isPointer(t->node(), &x)) {
292  ERROR("the node of the tree is not a pointer", t);
293  }
294  return x;
295 }
296 
297 /*
298 bool isTree (const Tree& t, const Node& n)
299 {
300  return (t->node() == n) && (t->arity() == 0);
301 }
302 */
303 
304 // Si ca ne pose pas de probl�es, c'est plus pratique
305 bool isTree (const Tree& t, const Node& n)
306 {
307  return (t->node() == n);
308 }
309 
310 bool isTree (const Tree& t, const Node& n, Tree& a)
311 {
312  if ((t->node() == n) && (t->arity() == 1)) {
313  a=t->branch(0);
314  return true;
315  } else {
316  return false;
317  }
318 }
319 
320 bool isTree (const Tree& t, const Node& n, Tree& a, Tree& b)
321 {
322  if ((t->node() == n) && (t->arity() == 2)) {
323  a=t->branch(0);
324  b=t->branch(1);
325  return true;
326  } else {
327  return false;
328  }
329 }
330 
331 bool isTree (const Tree& t, const Node& n, Tree& a, Tree& b, Tree& c)
332 {
333  if ((t->node() == n) && (t->arity() == 3)) {
334  a=t->branch(0);
335  b=t->branch(1);
336  c=t->branch(2);
337  return true;
338  } else {
339  return false;
340  }
341 }
342 
343 bool isTree (const Tree& t, const Node& n, Tree& a, Tree& b, Tree& c, Tree& d)
344 {
345  if ((t->node() == n) && (t->arity() == 4)) {
346  a=t->branch(0);
347  b=t->branch(1);
348  c=t->branch(2);
349  d=t->branch(3);
350  return true;
351  } else {
352  return false;
353  }
354 }
355 
356 bool isTree (const Tree& t, const Node& n, Tree& a, Tree& b, Tree& c, Tree& d, Tree& e)
357 {
358  if ((t->node() == n) && (t->arity() == 5)) {
359  a=t->branch(0);
360  b=t->branch(1);
361  c=t->branch(2);
362  d=t->branch(3);
363  e=t->branch(4);
364  return true;
365  } else {
366  return false;
367  }
368 }
369 
370 // July 2005, support for symbol user data
371 
373 {
374  Sym s;
375  if (isSym(t->node(), &s)) {
376  return getUserData(s);
377  } else {
378  return 0;
379  }
380 }
381 
382 
388 void CTree::exportProperties(vector<Tree>& keys, vector<Tree>& values)
389 {
390  for (plist::const_iterator p = fProperties.begin(); p != fProperties.end(); p++) {
391  keys.push_back(p->first);
392  values.push_back(p->second);
393  }
394 }
395 
A tree library with hashconsing and maximal sharing capabilities.
Class Node = (type x (int + double + Sym + void*))
Definition: node.hh:75
bool equiv(const Node &n, const tvec &br) const
used to check if an equivalent tree already exists
Definition: tree.cpp:139
int tree2int(Tree t)
if t has a node of type int, return it otherwise error
Definition: tree.cpp:230
vector< Tree > tvec
Definition: tree.hh:90
#define ERROR(s, t)
Definition: tree.cpp:96
static unsigned int calcTreeHash(const Node &n, const tvec &br)
compute the hash key of a tree according to its node and branches
Definition: tree.cpp:149
A CTree = (Node x [CTree]) is a Node associated with a list of subtrees called branches.
Definition: tree.hh:109
const Node & node() const
return the content of the tree
Definition: tree.hh:143
static Tree make(const Node &n, int ar, Tree br[])
return a new tree or an existing equivalent one
int type() const
Definition: node.hh:102
static Tree gHashTable[kHashTableSize]
hash table used for "hash consing"
Definition: tree.hh:113
static const int kHashTableSize
Definition: tree.hh:112
tvec fBranch
the subtrees
Definition: tree.hh:128
static void error(const char *s, Tree t)
Definition: tree.cpp:90
void * getUserData(Tree t)
if t has a node of type symbol, return the associated user data
Definition: tree.cpp:372
plist fProperties
the properties list attached to the tree
Definition: tree.hh:124
bool isDouble(const Node &n)
Definition: node.hh:143
bool isSym(const Node &n)
Definition: node.hh:199
Definition: tree.hh:250
ostream & print(ostream &fout) const
print recursively the content of a tree on a stream
Definition: tree.cpp:190
unsigned int fHashKey
the hashtable key
Definition: tree.hh:125
static bool gDetails
Ctree::print() print with more details when true.
Definition: tree.hh:116
Tree fNext
next tree in the same hashtable entry
Definition: tree.hh:121
~CTree()
Definition: tree.cpp:120
int arity() const
return the number of branches (subtrees) of a tree
Definition: tree.hh:144
const char * name(Symbol *sym)
Returns the name of a symbol.
Definition: symbol.hh:98
void * tree2ptr(Tree t)
if t has a node of type ptr, return it otherwise error
Definition: tree.cpp:288
static void control()
print the hash table content (for debug purpose)
Definition: tree.cpp:210
Symbols are unique objects with a name stored in a hash table.
Definition: symbol.hh:53
int getInt() const
Definition: node.hh:104
Sym PROCESS
Definition: tree.cpp:144
bool isTree(const Tree &t, const Node &n)
Definition: tree.cpp:305
CTree(unsigned int hk, const Node &n, const tvec &br)
construction is private, uses tree::make instead
Definition: tree.cpp:104
Node fNode
the node content of the tree
Definition: tree.hh:122
Symbol * symbol(const char *str)
Returns (and creates if new) the symbol of name str.
Definition: symbol.hh:95
bool isPointer(const Node &n)
Definition: node.hh:216
double tree2double(Tree t)
if t has a node of type float, return it otherwise error
Definition: tree.cpp:262
static unsigned int gVisitTime
Should be incremented for each new visit to keep track of visited tree.
Definition: tree.hh:117
Tabber TABBER(1)
Definition: tree.cpp:87
bool isInt(const Node &n)
Definition: node.hh:126
double tree2float(Tree t)
if t has a node of type float, return it otherwise error
Definition: tree.cpp:246
void exportProperties(vector< Tree > &keys, vector< Tree > &values)
export the properties of a CTree as two vectors, one for the keys and one for the associated values ...
Definition: tree.cpp:388
const char * tree2str(Tree t)
if t has a node of type symbol, return its name otherwise error
Definition: tree.cpp:278
Tree branch(int i) const
return the ith branch (subtree) of a tree
Definition: tree.hh:145