#ifndef __LookupTable_h__
#define __LookupTable_h__
/////////////////////////////////////////////////////////////////////////////
// LookupTable.h | Declaration of a simple lookup table.
#pragma warning(disable: 4786)
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// Declares a template structure that holds a pair of values of types
// /key/ and /Value/. This is used by the TCLookupTable macros.
//
// Template Parameters:
// Key - The type of the m_key public data member.
// Value - The type of the m_value public data member;
//
// See Also: TCLookupTable Macros, TCLookupTable_DECLARE
template <class Key, class Value, class KeyRef = Key const &>
struct TCLookupTablePair
{
typedef Key KeyT; // {secret}
typedef Value ValueT; // {secret}
typedef KeyRef KeyRefT; // {secret}
KeyT m_key; // {secret}
ValueT m_value; // {secret}
};
/////////////////////////////////////////////////////////////////////////////
// Iterates through the entries of the specified lookup table until either
// the specified /key/ is found or the number of table entries specified by
// /nSize/ have been searched.
//
// This is used by the TCLookupTable_FIND macro and probably has limited use
// outside of that macro.
//
// Template Parameters:
// Key - The type of the table's keys.
// Value - The type of the table's associated values.
// Parameters:
// pTable - The address of the first entry in the table.
// nSize - The number of table entries in the table.
// key - The key to be located in the table.
// value - A reference to where the located key's associated value will be
// copied. If the key is not found, this parameter is not used.
//
// Return Value: true if the specified key was located in the specified
// table, otherwise false;
//
// See Also: TCLookupTable Macros, TCLookupTable_FIND
template <class Key, class Value, class KeyRef>
bool TCLookupTable_Find(TCLookupTablePair<Key, Value, KeyRef>* ptable,
UINT nSize, KeyRef key, Value& value)
{
for (UINT i = 0; i < nSize; i++)
{
if (key == ptable[i].m_key)
{
value = ptable[i].m_value;
return true;
}
}
return false;
}
#ifdef _DOCJET_ONLY
///////////////////////////////////////////////////////////////////////////
// Macro Group: TCLookupTable Macros
//
// There is often the need during development to define lookup tables for a
// variety of uses. Regardless of the use, this involves mapping a
// /key/ to one or more /values/. For dynamic lookup tables, those that
// will be built and modified during run-time, an obvious choice might be
// the STL std::map class. However, many lookup tables are static in nature
// and, as such, can be defined at compile time and do not change during
// the course of the program. The TCLookupTable macros provide a reusable
// mechanism to assist in the declaration and initialization of such static
// lookup tables.
//
// Note: These macros are not designed to be used to declare static tables
// in template classes. This is mostly due to limitations of the
// C++ preprocessor which, for example, make it difficult (or impossible)
// to specify a template class name with multiple template arguments as a
// macro parameter; the comma's get in the way. However, for efficiency
// reasons, using static tables in a template class is *not* recommended,
// anyway.
// It could be inefficient since multiple template instances would each
// have their own copy of the static data. If you need a static table in a
// template class, derive the template class from a non-template base class
// that declares (and initializes) the table. Be sure to make the tables
// *public* or *protected* in the non-template base class so that the
// derived template class has access to them.
//
// To declare a static lookup table in your class, add the
// TCLookupTable_DECLARE macro inside your class declaration:
//
// class CMyClass
// {
// // ...(Other members)...
// …
// // Data Members
// protected:
// TCLookupTable_DECLARE(fruits, int, LPCTSTR)
// };
//
// The above example declares a static lookup table named "fruits" as a
// protected data member of CMyClass. The table will map integers to
// strings. For the sake of the example, forget that all localizable
// strings should be put into String Table resources.
//
// A class can declare as many tables as needed. If the CMyClass also
// needed a table of vegetables, it could simply specify the macro again,
// with a different table name:
//
// class CMyClass
// {
// // ...(Other members)...
// …
// // Data Members
// protected:
// TCLookupTable_DECLARE(fruits, int, LPCTSTR)
// TCLookupTable_DECLARE(vegetables, int, LPCTSTR)
// };
//
// To initialize each table, use the TCLookupTable_ENTRY macros, enclosed
// within the TCLookupTable_BEGIN and TCLookupTable_END macros. Keep in
// mind that the table is a static data member of the class. So the best
// place to initialize the static data members is in your class
// implementation (CPP) file:
//
// // (In MyClass.cpp)
// // Static Initialization
// TCLookupTable_BEGIN(CMyClass, fruits)
// TCLookupTable_ENTRY(10, TEXT("Apple"))
// TCLookupTable_ENTRY(20, TEXT("Banana"))
// TCLookupTable_ENTRY(30, TEXT("Orange"))
// TCLookupTable_END()
//
// The above example only shows the TCLookupTable_ENTRY macro, but several
// other macros are provided to assist in the declaration of other common
// scenarios, such as when the associated value type is a structure.
//
// Now that your lookup table is initialized, the TCLookupTable_FIND macro
// allows a key and its associated value to easily be found in the table:
//
// LPCTSTR CMyClass::FruitToString(int idFruit) const
// {
// // Lookup the specified fruit ID
// LPCTSTR pszName;
// bool bFound = TCLookupTable_FIND(fruit, idFruit, pszName);
// return bFound ? pszName : NULL;
// }
//
// While the above example demonstrates the most common use for a lookup
// table, it is sometimes useful to manually iterate through the table
// entries. To assist with this, the TCLookupTable_SIZE macro is provided.
// As its name implies, it provides the number of entries in the table. The
// table consists of a regular array of TCLookupTablePair structures. Since
// this structure is a template, the TCLookupTable_DECLARE macro declares
// a type definition consisting of the table name suffixed with _ValueType.
// In the following example, the /entry/ variable is a reference of type
// /fruit_ValueType/, which is the type definition declared by the
// TCLookupTable_DECLARE macro:
//
// void CMyClass::DumpFruitTable() const
// {
// for (int i = 0; i < TCLookupTable_SIZE(fruit); ++i)
// {
// fruit_ValueType& entry = fruit[i];
// _TRACE2("Fruit ID %d = %s\n", entry.m_key, entry.m_value);
// }
// }
//
// See Also: TCLookupTablePair, TCLookupTable_DECLARE,
// TCLookupTable_DECLARE, TCLookupTable_BEGIN, TCLookupTable_END,
// TCLookupTable_ENTRY Macros, TCLookupTable_SIZE, TCLookupTable_FIND,
// TCLookupTable_Find
#define TCLookupTable
#endif // _DOCJET_ONLY
/////////////////////////////////////////////////////////////////////////////
// Declares a static lookup table as a static member variable. Also declares
// a type definition for the entries of the table by suffixing the
// /table/ parameter with _ValueType.
//
// Use this macro within a class declaration. More than one table can be
// declared in a class by specifying a different /table/ name in each macro
// statement.
//
// Parameters:
// table - The table name, which doubles as the name of the static member
// variable.
// Key - The type of the table's keys.
// Value - The type of the table's associated values.
//
// See Also: TCLookupTable Macros, TCLookupTable_BEGIN, TCLookupTablePair
#define TCLookupTable_DECLARE(table, Key, Value) \
typedef TCLookupTablePair<Key, Value> table##_ValueType; \
static table##_ValueType table [];
#define TCLookupTable_DECLARE_REF(table, Key, Value, KeyRef) \
typedef TCLookupTablePair<Key, Value, KeyRef> table##_ValueType; \
static table##_ValueType table [];
/////////////////////////////////////////////////////////////////////////////
// Begins the initialization scope of a static lookup table. This scope
// should contain TCLookupTable_ENTRY macros and should end with the
// TCLookupTable_END macro.
//
// Since this initializes a static member variable of the specified class, it
// needs to be specified *outside* of the class declaration and positioned so
// that it is included exactly *once* by the linker. The best place to
// initialize the static data members is in the class implementation (CPP)
// file.
//
// Parameters:
// theClass - the name of the class which declares the static lookup table.
// table - the name of the table in /theClass/.
//
// See Also: TCLookupTable Macros, TCLookupTable_ENTRY Macros,
// TCLookupTable_END
#define TCLookupTable_BEGIN(theClass, table) \
theClass::table##_ValueType theClass::table [] = {
/////////////////////////////////////////////////////////////////////////////
// {alias: TCLookupTable_ENTRY2, TCLookupTable_ENTRY3, TCLookupTable_ENTRY4}
// {alias: TCLookupTable_ENTRY_PREFIX, TCLookupTable_ENTRY_SUFFIX}
// Initializes an entry in a static lookup table. These macros should only
// be used within the initialization scope of a static lookup table. This
// scope should begin with the TCLookupTable_BEGIN macro and should end with
// the TCLookupTable_END macro.
//
// TCLookupTable_ENTRY is the simplest of these macros, taking just a key
// and a value with which to initialize the table entry.
//
// TCLookupTable_ENTRY2 through TCLookupTable_ENTRY4 require the key and from
// 2 to 4 value parameters, respectively. The multiple value parameters are
// used to initialize the members of a structure when a structure is used as
// the table's value type.
//
// TCLookupTable_ENTRY_PREFIX and TCLookupTable_ENTRY_SUFFIX are used when
// the key and/or value are symbolic and the symbols contain some element of
// identical text. For example, if a lookup table was being used to map error
// code identifiers to string table identifiers, the following sets of
// entries would be equivalent:
//
// This way is tedious and the repetition may introduce typing errors:
//
// TCLookupTable_ENTRY(E_FILENOTFOUND, IDS_E_FILENOTFOUND)
// TCLookupTable_ENTRY(E_INPUTIS2UGLY, IDS_E_INPUTIS2UGLY)
//
// This way results in the exact same table initialization:
//
// TCLookupTable_ENTRY_PREFIX(E_FILENOTFOUND, IDS_)
// TCLookupTable_ENTRY_PREFIX(E_INPUTIS2UGLY, IDS_)
//
// TODO: It may also be useful to provide a macro to "stringize" the key
// symbol to derive the value:
//
// #define TCLookupTable_ENTRY_STRING(key) \
// TCLookupTable_Entry(key, TEXT(#key))
//
// Parameters:
// key - The value with which to initialize the table entry's key.
// value - The value to which the table entry's key is associated.
// value1_thru_value4 - The values with which to initialize the structure
// associated with the table entry's key.
// prefix - Used to create a value name based on the key parameter prefixed
// with the specified parameter.
// suffix - Used to create a value name based on the key parameter suffixed
// with the specified parameter.
//
// Macro Group: TCLookupTable_ENTRY Macros
//
// Declaration:
// #define TCLookupTable_ENTRY(key, value)
// #define TCLookupTable_ENTRY2(key, value1, value2)
// #define TCLookupTable_ENTRY3(key, value1, value2, value3)
// #define TCLookupTable_ENTRY4(key, value1, value2, value3, value4)
// #define TCLookupTable_ENTRY_PREFIX(key, prefix)
// #define TCLookupTable_ENTRY_SUFFIX(key, suffix)
//
// See Also: TCLookupTable Macros, TCLookupTable_BEGIN, TCLookupTable_END
#define TCLookupTable_ENTRY(key, value) \
{ key, value },
/////////////////////////////////////////////////////////////////////////////
// {partof:TCLookupTable_ENTRY}
#define TCLookupTable_ENTRY2(key, value1, value2) \
{ key, {value1, value2} },
/////////////////////////////////////////////////////////////////////////////
// {partof:TCLookupTable_ENTRY}
#define TCLookupTable_ENTRY3(key, value1, value2, value3) \
{ key, {value1, value2, value3} },
/////////////////////////////////////////////////////////////////////////////
// {partof:TCLookupTable_ENTRY}
#define TCLookupTable_ENTRY4(key, value1, value2, value3, value4) \
{ key, {value1, value2, value3, value4} },
/////////////////////////////////////////////////////////////////////////////
// {partof:TCLookupTable_ENTRY}
#define TCLookupTable_ENTRY_PREFIX(key, prefix) \
TCLookupTable_ENTRY(key, prefix##key)
/////////////////////////////////////////////////////////////////////////////
// {partof:TCLookupTable_ENTRY}
#define TCLookupTable_ENTRY_SUFFIX(key, suffix) \
TCLookupTable_ENTRY(key, key##suffix)
/////////////////////////////////////////////////////////////////////////////
// Ends the initialization scope of a static lookup table. This scope should
// begin with the TCLookupTable_BEGIN macro and should contain
// TCLookupTable_ENTRY macros.
//
// See Also: TCLookupTable Macros, TCLookupTable_BEGIN, TCLookupTable_ENTRY
// Macros
#define TCLookupTable_END() };
/////////////////////////////////////////////////////////////////////////////
// Computes the number of entries in a static lookup table. Since the size of
// the table is known at compile time, this macro will compile out to a
// constant value.
//
// Parameters:
// table - The name of the table.
//
// Return Value: The number of elements in the table.
//
// See Also: TCLookupTable Macros
#define TCLookupTable_SIZE(table) (sizeof(table) / sizeof(table[0]))
/////////////////////////////////////////////////////////////////////////////
// Iterates through the entries of the specified lookup table until either
// the specified /key/ is found or the end of the table is reached.
//
// Parameters:
// table - The name of the table.
// key - The key to be located in the table.
// value - A reference to where the located key's associated value will be
// copied. If the key is not found, this parameter is not used.
//
// Return Value: true if the specified key was located in the specified
// table, otherwise false;
//
// See Also: TCLookupTable Macros, TCLookupTable_Find
#define TCLookupTable_FIND(table, key, value) \
TCLookupTable_Find<table##_ValueType::KeyT, \
table##_ValueType::ValueT, table##_ValueType::KeyRefT>(table, \
TCLookupTable_SIZE(table), key, value)
/////////////////////////////////////////////////////////////////////////////
#endif // !__LookupTable_h__