speech-tools/testsuite/named_enum_example.cc
2015-09-19 10:52:26 +02:00

254 lines
9.6 KiB
C++

/************************************************************************/
/* */
/* Centre for Speech Technology Research */
/* University of Edinburgh, UK */
/* Copyright (c) 1996,1997 */
/* All Rights Reserved. */
/* */
/* Permission is hereby granted, free of charge, to use and distribute */
/* this software and its documentation without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of this work, and to */
/* permit persons to whom this work is furnished to do so, subject to */
/* the following conditions: */
/* 1. The code must retain the above copyright notice, this list of */
/* conditions and the following disclaimer. */
/* 2. Any modifications must be clearly marked as such. */
/* 3. Original authors' names are not deleted. */
/* 4. The authors' names are not used to endorse or promote products */
/* derived from this software without specific prior written */
/* permission. */
/* */
/* THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK */
/* DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING */
/* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT */
/* SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS BE LIABLE */
/* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES */
/* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN */
/* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, */
/* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF */
/* THIS SOFTWARE. */
/* */
/************************************************************************/
/* Author: Richard Caley (rjc@cstr.ed.ac.uk) */
/* Date: Tue Apr 29 1997 */
/************************************************************************/
/* */
/* Example of the declaration and use fo the named enum type. */
/* */
/************************************************************************/
#include <cstdlib>
#include <iostream>
#include "EST_TNamedEnum.h"
#if defined(DATAC)
# define __STRINGIZE(X) #X
# define DATA __STRINGIZE(DATAC)
#endif
// the named enum class provides an easy way to associate strings with
// the values of and enumerated type, for instance for IO. It's type safe and
// as readable as seems possible in C++.
// A single enum element can have multiple names (eg synonyms or common typos)
// Named enums are defined in terms of the more general valued enums which
// associates enum elements with members of an arbitrary type.
// Both named enums and valued enums can have an additional piece of
// information (eg a struct containing creation functions or another
// representation) associated with each enum element.
// --------- Declaration (eg in header or class) ------------
// the enumerated type used in C code.
typedef enum { c_red=1, c_blue=2, c_green=3, c_unknown=666} Colour;
// the mapping used to get names and so on
extern EST_TNamedEnum<Colour> ColourMap;
// ---------- Definition ---------------------------------------
// In a .C file somewhere we have to give the names in a table.
// The table has to be given a name and is then used to initialise the mapping.
// The definition table ends with a repeat of the first entry and some
// value. This last pair gives the unknown enum value and unknown
// value for use when lookup fails
// For reasons of C++ brain death we have to declare this as a
// ValuedEnumDefinition<X,const char *, NO_INFO> rather than a
// NamedEnum<X>::Definition or some other saner version
Start_TNamedEnum(Colour, ColourMap)
// enum element list of names
{ c_unknown, {"kinda brownish"}},
{ c_red, {"red", "scarlet"}},
{ c_blue, {"blue", "navy", "sad"}},
{ c_unknown, {NULL}} // looking up unknown names gives c_unknown
// looking up unknown enum values gives NULL
End_TNamedEnum(Colour, ColourMap)
// Here is a different table for the same enum type.
// Perhaps we want to accept input in Spanish, but not get Spanish and
// English names mixed up
Start_TNamedEnum(Colour, SpanishColourMap)
// enum element list of names
{ c_unknown, {"no conocido"}},
{ c_red, {"rojo", "escarlata", "sangre"}},
{ c_blue, {"azul", "piscina", "mar", "cielo"}},
{ c_unknown, {NULL}}
End_TNamedEnum(Colour, SpanishColourMap)
// ------- Alternative including extra information ---------------
// Sometimes you may want to associate information with each element.
// The following variant associates three small integers with each
// colour, perhaps to enable them to be displayed.
struct colour_info {
int red, green, blue;
};
// a map including this extra information is declared as
extern EST_TNamedEnumI<Colour, colour_info> RGBColourMap;
// and here is how the values are defined.
Start_TNamedEnumI(Colour, colour_info, RGBColourMap)
// enum element list of names extra info (red, green, blue)
{ c_unknown, {"kinda grey"}, {0x7f, 0x7f, 0x7f}},
{ c_red, {"red", "scarlet"}, {0xff, 0, 0}},
{ c_blue, {"blue", "navy", "sad"}, {0, 0, 0xff}},
{ c_unknown, {NULL}}
End_TNamedEnumI(Colour, colour_info, RGBColourMap)
// --------- Use -----------------------------------------------
int main(void)
{
Colour c1 = c_red;
Colour c2 = c_green;
const char *n;
// get the default name for colours.
n = ColourMap.name(c1);
cout << "c1 is " << (n?n:"[NULL]") << "\n";
n = ColourMap.name(c2);
cout << "c2 is " << (n?n:"[NULL]") << "\n";
// look up some names to see what they correspond to
const char *colours[] = { "red", "navy", "puce"};
for(int i=0; i<3; i++)
{
// note since enum values are universal
// we can get the colour by assuming English, get the
// information from the other map and get the name for output in
// spanish
const char *nm= colours[i];
Colour c = ColourMap.token(nm);
colour_info &info = RGBColourMap.info(c);
const char *spanish = SpanishColourMap.name(c);
cout << nm << " is " << (int)c
<< " = " << ColourMap.name(c)
<< " (" << (spanish?spanish:"[NULL]") << " in Spanish)"
<< " = {"
<< info.red << ", "
<< info.green << ", "
<< info.blue
<< "}\n";
}
// In the special case of EST_TNamedEnum (i.e. simple mappings from
// enum to (const char *) with no extra information) we can save
// mappings to files and read them back
// There are two ways to save a mapping, we can have the file say how
// names map to numeric values...
if (ColourMap.save("tmp/colour.map") != write_ok)
cout << "\n\nname map write failed\n";
else
{
cout << "\n\ncolour name map\n";
cout.flush();
system("cat tmp/colour.map");
}
// Of course this can result in the file not being valid when the
// enumerated type definition changes and so the assigned numbers change.
// If there is a standard mapping defined and we are saving an
// alternative, the standard one can provide names for the enumerated
// values, meaning the file will be valid so long as the default
// mapping is correct.
// For instance we can assume someone maintains the English names
// as the type is extended and save the Spanish names as a translation.
if (SpanishColourMap.save("tmp/colour_spanish.map", ColourMap) != write_ok)
cout << "\n\nname map write failed\n";
else
{
cout << "\n\ncolour name map (spanish)\n";
cout.flush();
system("cat tmp/colour_spanish.map");
}
// There are two corresponding ways to read in a map.
// If the map is defined in the file by numbers we load it like this...
EST_TNamedEnum<Colour> LoadedColourMap(c_unknown);
if (LoadedColourMap.load(DATA "/colours.map") !=format_ok)
cout << "\n\nname map read failed\n";
else
{
cout << "\n\nread in table\n";
LoadedColourMap.save("tmp/tmp.map");
cout.flush();
system("cat tmp/tmp.map");
}
// If it's defined in the file using the names...
if (LoadedColourMap.load(DATA "/colours_translation.map", ColourMap) !=format_ok)
cout << "\n\nname map read failed\n";
else
{
cout << "\n\nread in table (translation)\n";
LoadedColourMap.save("tmp/tmp.map");
cout.flush();
system("cat tmp/tmp.map");
}
exit(0);
}
// ----------- Template Brain Death --------------------
// Declaration of the template use for GCC
// Just which variants need to be declared is sometimes unpredictable,
// especially between versions of gcc.
// Best just compile and then find out which ones aren't there.
Declare_TNamedEnumI(Colour, colour_info)
Declare_TNamedEnum(Colour)
#if defined(INSTANTIATE_TEMPLATES)
#include "../base_class/EST_TNamedEnum.cc"
Instantiate_TNamedEnumI(Colour, colour_info)
Instantiate_TNamedEnum(Colour)
#endif