254 lines
9.6 KiB
C++
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
|