Edinburgh Speech Tools  2.4-release
EST_Item.cc
1 /*************************************************************************/
2 /* */
3 /* Centre for Speech Technology Research */
4 /* University of Edinburgh, UK */
5 /* Copyright (c) 1998 */
6 /* All Rights Reserved. */
7 /* */
8 /* Permission is hereby granted, free of charge, to use and distribute */
9 /* this software and its documentation without restriction, including */
10 /* without limitation the rights to use, copy, modify, merge, publish, */
11 /* distribute, sublicense, and/or sell copies of this work, and to */
12 /* permit persons to whom this work is furnished to do so, subject to */
13 /* the following conditions: */
14 /* 1. The code must retain the above copyright notice, this list of */
15 /* conditions and the following disclaimer. */
16 /* 2. Any modifications must be clearly marked as such. */
17 /* 3. Original authors' names are not deleted. */
18 /* 4. The authors' names are not used to endorse or promote products */
19 /* derived from this software without specific prior written */
20 /* permission. */
21 /* */
22 /* THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK */
23 /* DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING */
24 /* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT */
25 /* SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS BE LIABLE */
26 /* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES */
27 /* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN */
28 /* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, */
29 /* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF */
30 /* THIS SOFTWARE. */
31 /* */
32 /*************************************************************************/
33 /* Author : Alan W Black */
34 /* Date : May 1998 */
35 /*-----------------------------------------------------------------------*/
36 /* Linguistic items (e.g. words, phones etc) held as part of Relations */
37 /* */
38 /* These objects may be held in relations within an utterance. They */
39 /* fact contain two sections, a structural part and a contents part */
40 /* (EST_Item_Content) though the user will usually only see the whole */
41 /* object. The content part may be shared between linguistic items in */
42 /* other relations, e.g. the word item may appear both in the word */
43 /* relation and the syntax relation. */
44 /* */
45 /* Each linguistic item is in a particular relation but it is easy */
46 /* to link to that item in another relation. Traversal of the relation */
47 /* for an item in it is trivial. */
48 /* */
49 /*=======================================================================*/
50 #include <cstdlib>
51 #include <cstdio>
52 #include <iostream>
53 #include <fstream>
54 #include "ling_class/EST_Item.h"
55 #include "ling_class/EST_Relation.h"
56 #include "ling_class/EST_Utterance.h"
57 #include "EST_TKVL.h"
58 #include "EST_UList.h"
59 #include "EST_string_aux.h"
60 
61 #include "ling_class_init.h"
62 
63 /* Class initialisation. This is where you should register
64  * feature functions and so on.
65  */
66 void EST_Item::class_init(void)
67 {
68 #ifdef EST_DEBUGGING
69  cerr << "Calling EST_Item init\n";
70 #endif
71 
72  ling_class_init::use();
73 
74  EST_register_feature_functions(standard);
75 
76 #ifdef EST_DEBUGGING
77  cerr << "Finished EST_Item init\n";
78 #endif
79 }
80 
82 {
83  p_relation = 0;
84  p_contents = 0;
85  n=p=u=d=0;
86  set_contents(0);
87 }
88 
89 void EST_Item::copy(const EST_Item &s)
90 {
91  // You can't really do this in general as a node is doubly
92  // linked to its neighbours and item. Copying all the fields would
93  // mean it was no longer true (unless you copied everything).
94  // So all you get for this is a *copy* of the contents (not a reference
95  // to)
96  p_relation = 0;
97  p_contents = 0;
98  n=p=u=d=0;
99  set_contents(0); // get an empty contents structure
100  *p_contents = *s.p_contents;
101 }
102 
104 {
105  copy(i);
106 }
107 
109 {
110  // Delete this item and its daughters (and the contents with no
111  // other links)
112  // Assumes a tree structure
113  EST_Item *ds,*nds;
114 
115  // Tidy up pointers to this
116  if (n != 0)
117  {
118  n->p = p;
119  n->u = u; // when deleting first daughter.
120  }
121  if (p != 0) p->n = n;
122  if (u != 0) u->d = n;
123 
124  if (p_relation)
125  {
126  if (p_relation->p_head == this)
127  p_relation->p_head = n;
128  if (p_relation->p_tail == this)
129  p_relation->p_tail = p;
130  }
131 
132  // A little cleverer with the daughters
133  for (ds=d; ds != 0; ds=nds)
134  {
135  nds=ds->n;
136  delete ds;
137  }
138 
139  unref_contents();
140 }
141 
143 {
144  p_relation = rel;
145  p_contents = 0;
146  n=p=u=d=0;
147 }
148 
149 // all internal ids are found by getting the next id number from
150 // the utterance and prefixing a "_" to show that this is internally
151 // generated.
152 static void assign_id(EST_Item *s)
153 {
154  if (s->f_present("id"))
155  return;
156 
157  EST_Utterance *u = get_utt(s);
158  if (u != 0)
159  s->set("id", "_" + itoString(u->next_id()));
160 }
161 
163 {
164  p_relation = rel;
165  p_contents = 0;
166  n=p=u=d=0;
167  if (li)
168  set_contents(li->contents());
169  else
170  set_contents(0);
171 
172  assign_id(this);
173 }
174 
176 {
177  evaluate(this,p_contents->f);
178 }
179 
180 void EST_Item::unref_contents()
181 {
182  // Unref the related contents to this item, delete if no-one else is
183  // referencing it
184  if (p_contents != 0)
185  {
186  if (p_contents->unref_relation(relation_name()))
187  delete p_contents;
188  p_contents = 0;
189  }
190 }
191 
192 void EST_Item::unref_all()
193 {
194  // Unreference this item from all its relations, deleting its contents
195 
196  p_contents->unref_and_delete();
197 }
198 
200 {
201  return ((this == 0) || (p_relation == 0)) ?
202  EST_String::Empty : p_relation->name();
203 }
204 
205 void EST_Item::set_contents(EST_Item_Content *new_contents)
206 {
207  // This function is for internal use only, general use of this
208  // is likely to be unsafe.
209  EST_Item_Content *c;
210  if (new_contents == 0)
211  c = new EST_Item_Content;
212  else
213  c = new_contents;
214 
215  if (p_contents != c)
216  {
217  unref_contents();
218  p_contents = c;
219 
220  EST_Item *nn_item = p_contents->Relation(relation_name());
221  if (nn_item) // this is already linked to this relation
222  { // can't recurse on set_contents
223  nn_item->p_contents = new EST_Item_Content;
224  nn_item->p_contents->relations.add_item(relation_name(),
225  est_val(nn_item));
226  }
227  p_contents->relations.add_item(relation_name(),est_val(this));
228  }
229 }
230 
231 int EST_Item::length() const
232 {
233  int i=0;
234  EST_Item *nn = (EST_Item *)(void *)this;
235  for (; nn; nn=nn->n,i++);
236  return i;
237 }
238 
239 EST_Item *EST_Item::insert_after(EST_Item *si)
240 {
241  // Create a new item and add it after t, and return it.
242  // Include the cross link from this new item's contents to si, and
243  // from si's relations fields back to the new node
244  EST_Item *new_node = new EST_Item(p_relation,si);
245 
246  new_node->p = this;
247  new_node->n = this->n;
248  if (new_node->n != 0)
249  new_node->n->p = new_node;
250  this->n = new_node;
251 
252  if (p_relation && (p_relation->p_tail == this))
253  p_relation->p_tail = new_node;
254 
255  return new_node;
256 }
257 
258 EST_Item *EST_Item::insert_before(EST_Item *si)
259 {
260  // Create a new node and add it before this, and return it.
261  EST_Item *new_node = new EST_Item(p_relation,si);
262 
263  new_node->n = this;
264  new_node->p = this->p;
265  if (new_node->p != 0)
266  new_node->p->n = new_node;
267  this->p = new_node;
268  // This makes an assumption that we represent trees with only
269  // the first daughter pointing to the parent
270  if (this->u)
271  {
272  new_node->u = this->u;
273  new_node->u->d = new_node;
274  this->u = 0;
275  }
276 
277  if (p_relation && (p_relation->p_head == this))
278  p_relation->p_head = new_node;
279 
280  return new_node;
281 }
282 
283 EST_Item *EST_Item::insert_below(EST_Item *si)
284 {
285  // Create a new node and add it below this, and return it.
286  EST_Item *new_node = new EST_Item(p_relation,si);
287 
288  new_node->u = this;
289  new_node->d = this->d;
290  if (new_node->d != 0)
291  new_node->d->u = new_node;
292  this->d = new_node;
293 
294  return new_node;
295 }
296 
297 EST_Item *EST_Item::insert_above(EST_Item *si)
298 {
299  // Create a new node and add it above this, and return it.
300  EST_Item *new_node = new EST_Item(p_relation,si);
301 
302  new_node->d = this;
303  new_node->u = this->u;
304  if (new_node->u != 0)
305  new_node->u->d = new_node;
306  this->u = new_node;
307 
308  if (p_relation && (p_relation->p_head == this))
309  p_relation->p_head = new_node;
310  if (p_relation && (p_relation->p_tail == this))
311  p_relation->p_tail = new_node;
312 
313  return new_node;
314 }
315 
316 EST_Item *EST_Item::insert_parent(EST_Item *si)
317 {
318  // Insert new parent here, by added a new below node and moving
319  // the contents down to it.
320  insert_below(0);
321  d->set_contents(grab_contents());
322  if (si != 0)
323  set_contents(si->grab_contents());
324  else
325  set_contents(0);
326 
327  return this;
328 }
329 
330 EST_Item *inext(const EST_Item *x)
331 {
332  if (x == NULL)
333  return NULL;
334  else
335  return x->n;
336 }
337 
338 EST_Item *iprev(const EST_Item *x)
339 {
340  if (x == NULL)
341  return NULL;
342  else
343  return x->p;
344 }
345 
346 EST_Item *idown(const EST_Item *x)
347 {
348  if (x == NULL)
349  return NULL;
350  else
351  return x->d;
352 }
353 
354 EST_Item *iup(const EST_Item *x)
355 {
356  if (x == NULL)
357  return NULL;
358  else
359  return x->u;
360 }
361 
362 EST_Item *last(const EST_Item *x)
363 {
364  // To get round the const access to this
365  EST_Item *node = (EST_Item *)(void *)x;
366 
367  for (; node && inext(node) != 0; node=inext(node));
368  return node;
369 }
370 
371 EST_Item *first(const EST_Item *x)
372 {
373  // To get round the const access to this
374  EST_Item *node = (EST_Item *)(void *)x;
375 
376  for (; node && iprev(node) != 0; node=iprev(node));
377  return node;
378 }
379 
380 EST_Item *top(const EST_Item *x)
381 {
382  EST_Item *node = (EST_Item *)(void *)x;
383 
384  for (; node && parent(node) != 0; node=parent(node));
385  return node;
386 }
387 
388 EST_Item *next_leaf(const EST_Item *x)
389 {
390  if (x == NULL) return NULL;
391  if (inext(x) != NULL)
392  return first_leaf(inext(x));
393  else
394  return next_leaf(parent(x));
395 }
396 
397 EST_Item *next_item(const EST_Item *x)
398 {
399  // For traversal through a relation, in pre-order (root then daughters)
400  if (x == NULL)
401  return NULL;
402  else if (idown(x) != NULL)
403  return idown(x);
404  else if (inext(x) != NULL)
405  return inext(x);
406  else
407  { // at the right most leaf so go up until you find a parent with a next
408  for (EST_Item *pp = parent(x); pp != 0; pp = parent(pp))
409  if (inext(pp)) return inext(pp);
410  return NULL;
411  }
412 }
413 
414 EST_Item *first_leaf(const EST_Item *x)
415 {
416  // Leafs are defined as those nodes with no daughters
417  if (x == NULL) return NULL;
418  if (idown(x) == NULL)
419  return (EST_Item *)(void *)x;
420  else
421  return first_leaf(idown(x));
422 }
423 
424 EST_Item *last_leaf(const EST_Item *x)
425 {
426  // Leafs are defined as those nodes with no daughters
427  if (x == NULL) return NULL;
428  if (inext(x))
429  return last_leaf(last(x));
430  else if (idown(x))
431  return last_leaf(idown(x));
432  else
433  return (EST_Item *)(void *)x;
434 }
435 
436 EST_Item *first_leaf_in_tree(const EST_Item *root)
437 {
438  if (root == NULL) return NULL;
439  return first_leaf(root);
440 }
441 
442 EST_Item *last_leaf_in_tree(const EST_Item *root)
443 {
444  if (root == NULL) return NULL;
445  if (idown(root) == NULL)
446  return (EST_Item *)(void *)root;
447  else
448  return last_leaf(idown(root));
449 }
450 
451 EST_Item *EST_Item::append_daughter(EST_Item *si)
452 {
453  EST_Item *nnode;
454  EST_Item *its_downs;
455  EST_Item *c = NULL;
456 
457  // Because we don't distinguish forests properly we need
458  // to do nasty things if this si is already associated to a
459  // this relation and its "in the top list"
460  if (si)
461  c = si->as_relation(relation_name());
462  if (in_list(c,p_relation->head()))
463  {
464  // need to save its daughters to put on the new node
465  its_downs = c->d;
466  c->d = 0; // otherwise it could delete its sub tree
467  if (its_downs) its_downs->u = 0;
468 
469  if (d == 0)
470  nnode = insert_below(si);
471  else
472  nnode = last(d)->insert_after(si);
473  // put daughters back on the new item
474  if (its_downs)
475  {
476  its_downs->u = nnode;
477  nnode->d = its_downs;
478  }
479 
480  delete c; // delete its old form from the top level
481  }
482  else if (d == 0)
483  nnode = insert_below(si);
484  else
485  nnode = last(d)->insert_after(si);
486 
487  return nnode;
488 }
489 
490 EST_Item *EST_Item::prepend_daughter(EST_Item *si)
491 {
492  EST_Item *nnode;
493  EST_Item *its_downs;
494 
495  // Because we don't distinguish forests properly we need
496  // to do nasty things if this si is already associated to a
497  // this relation and its "in the top list"
498  EST_Item *c = si->as_relation(relation_name());
499  if (in_list(c,p_relation->head()))
500  {
501  // need to save its daughters to put on the new node
502  its_downs = c->d;
503  c->d = 0; // otherwise it could delete its sub tree
504  if (its_downs) its_downs->u = 0;
505 
506  if (d == 0)
507  nnode = insert_below(si);
508  else
509  nnode = d->insert_before(si);
510  // put daughters back on the new item
511  if (its_downs)
512  {
513  its_downs->u = nnode;
514  nnode->d = its_downs;
515  }
516 
517  delete c; // delete its old form from the top level
518  }
519  else if (d == 0)
520  nnode = insert_below(si);
521  else
522  nnode = d->insert_before(si);
523 
524  return nnode;
525 }
526 
527 EST_Item *EST_Item::grab_daughters()
528 {
529  EST_Item *dd = d;
530  if (dd)
531  {
532  dd->u = 0;
533  d = 0;
534  }
535  return dd;
536 }
537 
538 EST_Item_Content *EST_Item::grab_contents(void)
539 {
540  // Unreference contents, but don't delete them if that's the
541  // last reference. It is the caller's responsibility to deal
542  // with these contents, typically they are just about to be set
543  // as contents of someone else so are only orphaned for a short
544  // time
545  EST_Item_Content *c = contents();
546  c->unref_relation(relation_name());
547  p_contents = 0;
548  set_contents(0); // can't sit without contents
549  return c;
550 }
551 
552 void copy_node_tree(EST_Item *from, EST_Item *to)
553 {
554  // Copy this node and all its siblings and daughters
555 
556  if (inext(from) != 0)
557  copy_node_tree(inext(from),to->insert_after(inext(from)));
558 
559  if (idown(from) != 0)
560  copy_node_tree(idown(from),to->insert_below(idown(from)));
561 
562 }
563 
564 void copy_node_tree_contents(EST_Item *from, EST_Item *to)
565 {
566  // Copy this node and all its siblings and daughters
567  // also copy the item's contents
568 
569  if (inext(from) != 0)
570  {
571  EST_Item i = *inext(from); // copies the contents
572  copy_node_tree_contents(inext(from),to->insert_after(&i));
573  }
574 
575  if (idown(from) != 0)
576  {
577  EST_Item i = *idown(from);
578  copy_node_tree_contents(idown(from),to->insert_below(&i));
579  }
580 
581 }
582 
583 int EST_Item::verify() const
584 {
585  // Return FALSE if this node and its neighbours aren't
586  // properly linked
587 
588  if (((d == 0) || (d->u == this)) &&
589  ((n == 0) || (n->p == this)))
590  {
591  if ((d) && (!d->verify()))
592  return FALSE;
593  if ((n) && (!n->verify()))
594  return FALSE;
595  return TRUE;
596 }
597  else
598  return FALSE;
599 }
600 
601 EST_Item *append_daughter(EST_Item *n, EST_Item *p)
602 {
603  return n->append_daughter(p);
604 }
605 
606 EST_Item *append_daughter(EST_Item *n,const char *relname, EST_Item *p)
607 {
608  return append_daughter(as(n,relname),p);
609 }
610 
611 EST_Item *prepend_daughter(EST_Item *n, EST_Item *p)
612 {
613  return n->prepend_daughter(p);
614 }
615 
616 EST_Item *prepend_daughter(EST_Item *n, const char *relname, EST_Item *p)
617 {
618  return prepend_daughter(as(n,relname),p);
619 }
620 
621 void remove_item(EST_Item *l, const char *relname)
622 {
623  EST_Item *lr = l->as_relation(relname);
624  EST_Relation *r = lr->relation();
625 
626  if ((lr != 0) && (r != 0))
627  r->remove_item(lr);
628 }
629 
630 EST_Item &EST_Item::operator=(const EST_Item &s)
631 {
632  copy(s);
633  return *this;
634 }
635 
636 ostream& operator << (ostream &s, const EST_Item &a)
637 {
638  a.features().save(s);
639  return s;
640 }
641 
642 
643 void evaluate(EST_Item *a,EST_Features &f)
644 {
646 
647  for(p.begin(f); p; ++p)
648  if (p->v.type() == val_type_featfunc)
649  {
650  if (featfunc(p->v) != NULL)
651  p->v = (featfunc(p->v))(a);
652  else
653  {
654  fprintf(stderr, "NULL %s function\n", (const char *) p->k );
655  p->v = EST_Features::feature_default_value;
656  }
657  }
658 }
659 
660 VAL_REGISTER_CLASS_NODEL(item,EST_Item)
EST_Item::relation_name
const EST_String & relation_name() const
The relation name of this particular item.
Definition: EST_Item.cc:199
EST_Item_Content
Definition: EST_Item_Content.h:67
EST_TRwStructIterator< EST_Features, IPointer, Entry >
EST_Relation::name
const EST_String & name() const
Definition: EST_Relation.h:122
EST_Utterance::next_id
int next_id()
return the id of the next item
Definition: EST_Utterance.cc:79
EST_Features
Definition: EST_Features.h:62
EST_Item::~EST_Item
~EST_Item()
Deletes it and references to it in its contents.
Definition: EST_Item.cc:108
EST_Item::as_relation
EST_Item * as_relation(const char *relname) const
View item from another relation (const char *) method.
Definition: EST_Item.h:302
EST_Item::f_present
int f_present(const EST_String &name) const
Definition: EST_Item.h:230
EST_Item::evaluate_features
void evaluate_features()
Definition: EST_Item.cc:175
EST_Item::relation
EST_Relation * relation(void) const
The relation of this particular item.
Definition: EST_Item.h:316
EST_Utterance
Definition: EST_Utterance.h:54
EST_Item::EST_Item
EST_Item()
Default constructor.
Definition: EST_Item.cc:81
EST_Relation
Definition: EST_Relation.h:67
EST_String
Definition: EST_String.h:70
EST_Features::save
EST_write_status save(ostream &outf) const
save features in already opened ostream
Definition: EST_features_io.cc:111
EST_Item::set
void set(const EST_String &name, int ival)
Definition: EST_Item.h:179
EST_String::Empty
static const EST_String Empty
Constant empty string.
Definition: EST_String.h:111
EST_Relation::head
EST_Item * head() const
Definition: EST_Relation.h:125
EST_TKVL::add_item
int add_item(const K &rkey, const V &rval, int no_search=0)
add key-val pair to list
Definition: EST_TKVL.cc:248
EST_Relation::remove_item
void remove_item(EST_Item *item)
Definition: EST_Relation.cc:165
EST_Item_Content::f
EST_Features f
General features for this item.
Definition: EST_Item_Content.h:83
EST_Item
Definition: EST_Item.h:82