Edinburgh Speech Tools  2.4-release
 All Classes Functions Variables Typedefs Enumerations Enumerator Friends Pages
named_enum_example.cc
1  /************************************************************************/
2  /* */
3  /* Centre for Speech Technology Research */
4  /* University of Edinburgh, UK */
5  /* Copyright (c) 1996,1997 */
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: Richard Caley (rjc@cstr.ed.ac.uk) */
34  /* Date: Tue Apr 29 1997 */
35  /************************************************************************/
36  /* */
37  /* Example of the declaration and use fo the named enum type. */
38  /* */
39  /************************************************************************/
40 
41 #include <cstdlib>
42 #include <iostream>
43 #include "EST_TNamedEnum.h"
44 
45 #if defined(DATAC)
46 # define __STRINGIZE(X) #X
47 # define DATA __STRINGIZE(DATAC)
48 #endif
49 
50 // the named enum class provides an easy way to associate strings with
51 // the values of and enumerated type, for instance for IO. It's type safe and
52 // as readable as seems possible in C++.
53 
54 // A single enum element can have multiple names (eg synonyms or common typos)
55 
56 // Named enums are defined in terms of the more general valued enums which
57 // associates enum elements with members of an arbitrary type.
58 
59 // Both named enums and valued enums can have an additional piece of
60 // information (eg a struct containing creation functions or another
61 // representation) associated with each enum element.
62 
63 // --------- Declaration (eg in header or class) ------------
64 
65 // the enumerated type used in C code.
66 
67 typedef enum { c_red=1, c_blue=2, c_green=3, c_unknown=666} Colour;
68 
69 // the mapping used to get names and so on
70 extern EST_TNamedEnum<Colour> ColourMap;
71 
72 // ---------- Definition ---------------------------------------
73 // In a .C file somewhere we have to give the names in a table.
74 // The table has to be given a name and is then used to initialise the mapping.
75 
76 // The definition table ends with a repeat of the first entry and some
77 // value. This last pair gives the unknown enum value and unknown
78 // value for use when lookup fails
79 
80 // For reasons of C++ brain death we have to declare this as a
81 // ValuedEnumDefinition<X,const char *, NO_INFO> rather than a
82 // NamedEnum<X>::Definition or some other saner version
83 
84 Start_TNamedEnum(Colour, ColourMap)
85 // enum element list of names
86  { c_unknown, {"kinda brownish"}},
87  { c_red, {"red", "scarlet"}},
88  { c_blue, {"blue", "navy", "sad"}},
89  { c_unknown, {NULL}} // looking up unknown names gives c_unknown
90  // looking up unknown enum values gives NULL
91 End_TNamedEnum(Colour, ColourMap)
92 
93 // Here is a different table for the same enum type.
94 // Perhaps we want to accept input in Spanish, but not get Spanish and
95 // English names mixed up
96 
97 Start_TNamedEnum(Colour, SpanishColourMap)
98 // enum element list of names
99  { c_unknown, {"no conocido"}},
100  { c_red, {"rojo", "escarlata", "sangre"}},
101  { c_blue, {"azul", "piscina", "mar", "cielo"}},
102  { c_unknown, {NULL}}
103 End_TNamedEnum(Colour, SpanishColourMap)
104 
105 // ------- Alternative including extra information ---------------
106 
107 // Sometimes you may want to associate information with each element.
108 // The following variant associates three small integers with each
109 // colour, perhaps to enable them to be displayed.
110 
111 struct colour_info {
112  int red, green, blue;
113 };
114 
115 // a map including this extra information is declared as
116 extern EST_TNamedEnumI<Colour, colour_info> RGBColourMap;
117 
118 
119 // and here is how the values are defined.
120 
121 Start_TNamedEnumI(Colour, colour_info, RGBColourMap)
122 // enum element list of names extra info (red, green, blue)
123  { c_unknown, {"kinda grey"}, {0x7f, 0x7f, 0x7f}},
124  { c_red, {"red", "scarlet"}, {0xff, 0, 0}},
125  { c_blue, {"blue", "navy", "sad"}, {0, 0, 0xff}},
126  { c_unknown, {NULL}}
127 End_TNamedEnumI(Colour, colour_info, RGBColourMap)
128 
129 
130 
131 // --------- Use -----------------------------------------------
132 
133 int main(void)
134 {
135  Colour c1 = c_red;
136  Colour c2 = c_green;
137  const char *n;
138 
139  // get the default name for colours.
140  n = ColourMap.name(c1);
141  cout << "c1 is " << (n?n:"[NULL]") << "\n";
142 
143  n = ColourMap.name(c2);
144  cout << "c2 is " << (n?n:"[NULL]") << "\n";
145 
146 
147  // look up some names to see what they correspond to
148  const char *colours[] = { "red", "navy", "puce"};
149  for(int i=0; i<3; i++)
150  {
151  // note since enum values are universal
152  // we can get the colour by assuming English, get the
153  // information from the other map and get the name for output in
154  // spanish
155  const char *nm= colours[i];
156  Colour c = ColourMap.token(nm);
157  colour_info &info = RGBColourMap.info(c);
158  const char *spanish = SpanishColourMap.name(c);
159 
160  cout << nm << " is " << (int)c
161  << " = " << ColourMap.name(c)
162  << " (" << (spanish?spanish:"[NULL]") << " in Spanish)"
163  << " = {"
164  << info.red << ", "
165  << info.green << ", "
166  << info.blue
167  << "}\n";
168  }
169 
170  // In the special case of EST_TNamedEnum (i.e. simple mappings from
171  // enum to (const char *) with no extra information) we can save
172  // mappings to files and read them back
173 
174  // There are two ways to save a mapping, we can have the file say how
175  // names map to numeric values...
176 
177  if (ColourMap.save("tmp/colour.map") != write_ok)
178  cout << "\n\nname map write failed\n";
179  else
180  {
181  cout << "\n\ncolour name map\n";
182  cout.flush();
183  system("cat tmp/colour.map");
184  }
185 
186  // Of course this can result in the file not being valid when the
187  // enumerated type definition changes and so the assigned numbers change.
188 
189  // If there is a standard mapping defined and we are saving an
190  // alternative, the standard one can provide names for the enumerated
191  // values, meaning the file will be valid so long as the default
192  // mapping is correct.
193 
194  // For instance we can assume someone maintains the English names
195  // as the type is extended and save the Spanish names as a translation.
196 
197  if (SpanishColourMap.save("tmp/colour_spanish.map", ColourMap) != write_ok)
198  cout << "\n\nname map write failed\n";
199  else
200  {
201  cout << "\n\ncolour name map (spanish)\n";
202  cout.flush();
203  system("cat tmp/colour_spanish.map");
204  }
205 
206  // There are two corresponding ways to read in a map.
207 
208  // If the map is defined in the file by numbers we load it like this...
209 
210  EST_TNamedEnum<Colour> LoadedColourMap(c_unknown);
211  if (LoadedColourMap.load(DATA "/colours.map") !=format_ok)
212  cout << "\n\nname map read failed\n";
213  else
214  {
215  cout << "\n\nread in table\n";
216  LoadedColourMap.save("tmp/tmp.map");
217  cout.flush();
218  system("cat tmp/tmp.map");
219  }
220 
221  // If it's defined in the file using the names...
222 
223  if (LoadedColourMap.load(DATA "/colours_translation.map", ColourMap) !=format_ok)
224  cout << "\n\nname map read failed\n";
225  else
226  {
227  cout << "\n\nread in table (translation)\n";
228 
229  LoadedColourMap.save("tmp/tmp.map");
230  cout.flush();
231  system("cat tmp/tmp.map");
232  }
233 
234  exit(0);
235 }
236 
237 // ----------- Template Brain Death --------------------
238 
239 // Declaration of the template use for GCC
240 // Just which variants need to be declared is sometimes unpredictable,
241 // especially between versions of gcc.
242 // Best just compile and then find out which ones aren't there.
243 
244 Declare_TNamedEnumI(Colour, colour_info)
245 Declare_TNamedEnum(Colour)
246 
247 #if defined(INSTANTIATE_TEMPLATES)
248 #include "../base_class/EST_TNamedEnum.cc"
249 
250 Instantiate_TNamedEnumI(Colour, colour_info)
251 Instantiate_TNamedEnum(Colour)
252 
253 #endif