Edinburgh Speech Tools 2.4-release
 
Loading...
Searching...
No Matches
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 */
66void 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
89void 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.
152static 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
180void 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
192void 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
205void 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.
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
231int 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
239EST_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
258EST_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
283EST_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
297EST_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
316EST_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
330EST_Item *inext(const EST_Item *x)
331{
332 if (x == NULL)
333 return NULL;
334 else
335 return x->n;
336}
337
338EST_Item *iprev(const EST_Item *x)
339{
340 if (x == NULL)
341 return NULL;
342 else
343 return x->p;
344}
345
346EST_Item *idown(const EST_Item *x)
347{
348 if (x == NULL)
349 return NULL;
350 else
351 return x->d;
352}
353
354EST_Item *iup(const EST_Item *x)
355{
356 if (x == NULL)
357 return NULL;
358 else
359 return x->u;
360}
361
362EST_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
371EST_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
380EST_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
388EST_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
397EST_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
414EST_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
424EST_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
436EST_Item *first_leaf_in_tree(const EST_Item *root)
437{
438 if (root == NULL) return NULL;
439 return first_leaf(root);
440}
441
442EST_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
451EST_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
490EST_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"
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
527EST_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
538EST_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
552void 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
564void 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
583int 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
601EST_Item *append_daughter(EST_Item *n, EST_Item *p)
602{
603 return n->append_daughter(p);
604}
605
606EST_Item *append_daughter(EST_Item *n,const char *relname, EST_Item *p)
607{
608 return append_daughter(as(n,relname),p);
609}
610
611EST_Item *prepend_daughter(EST_Item *n, EST_Item *p)
612{
613 return n->prepend_daughter(p);
614}
615
616EST_Item *prepend_daughter(EST_Item *n, const char *relname, EST_Item *p)
617{
618 return prepend_daughter(as(n,relname),p);
619}
620
621void 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
630EST_Item &EST_Item::operator=(const EST_Item &s)
631{
632 copy(s);
633 return *this;
634}
635
636ostream& operator << (ostream &s, const EST_Item &a)
637{
638 a.features().save(s);
639 return s;
640}
641
642
643void 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
660VAL_REGISTER_CLASS_NODEL(item,EST_Item)
EST_write_status save(ostream &outf) const
save features in already opened ostream
EST_Features f
General features for this item.
EST_Relation * relation(void) const
The relation of this particular item.
Definition EST_Item.h:316
void set(const EST_String &name, int ival)
Definition EST_Item.h:179
void evaluate_features()
Definition EST_Item.cc:175
const EST_String & relation_name() const
The relation name of this particular item.
Definition EST_Item.cc:199
EST_Item * as_relation(const char *relname) const
View item from another relation (const char *) method.
Definition EST_Item.h:302
EST_Item()
Default constructor.
Definition EST_Item.cc:81
int f_present(const EST_String &name) const
Definition EST_Item.h:230
~EST_Item()
Deletes it and references to it in its contents.
Definition EST_Item.cc:108
void remove_item(EST_Item *item)
EST_Item * head() const
const EST_String & name() const
static const EST_String Empty
Constant empty string.
Definition EST_String.h:111
int add_item(const K &rkey, const V &rval, int no_search=0)
add key-val pair to list
Definition EST_TKVL.cc:248
void begin(Container &over)
Set the iterator ready to run over this container.
int next_id()
return the id of the next item