Commit fb497164 authored by Mark Olesen's avatar Mark Olesen
Browse files

ENH: cleanup of NamedEnum

- Remove the unused enums() method since it delivers wholly unreliable
  results. It is not guaranteed to cover the full enumeration range,
  but only the listed names.

- Remove the unused strings() method.
  Duplicated functionality of the words(), but was never used.

- Change access of words() method from static to object.
  Better code isolation. Permits the constructor to take over
  as the single point of failure for bad input.

- Add values() method

- do not expose internal (HashTable) lookup since it makes it more
  difficult to enforce constness and the implementation detail should
  not be exposed. However leave toc() and sortedToc() for the interface.

STYLE: relocated NamedEnum under primitives (was containers)

- internal typedef as 'value_type' for some consistency with STL conventions
parent dd54aa30
......@@ -34,15 +34,15 @@ class namedEnumTest
{
public:
enum option
enum class option
{
a,
b,
c,
d
A,
B,
C,
D
};
static const Foam::NamedEnum<option, 4> namedEnum;
static const Foam::NamedEnum<option, 4> optionNamed;
};
......@@ -52,10 +52,10 @@ const char* Foam::NamedEnum<namedEnumTest::option, 4>::names[] =
"a",
"b",
"c",
"d"
"d",
};
const Foam::NamedEnum<namedEnumTest::option, 4> namedEnumTest::namedEnum;
const Foam::NamedEnum<namedEnumTest::option, 4> namedEnumTest::optionNamed;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
......@@ -69,56 +69,43 @@ int main(int argc, char *argv[])
dictionary testDict;
testDict.add("lookup1", "c");
Info<< "enums: " << options << nl;
Info<< "loop over enums (as list):" << nl;
forAll(options, i)
{
const namedEnumTest::option& opt = options[i];
Info<< "option[" << opt
<< "] = '" << namedEnumTest::namedEnum[opt] << "'" << nl;
}
Info<< "loop over enums (C++11 for range):" << nl;
for (const auto& opt : options)
{
Info<< "option[" << opt
<< "] = '" << namedEnumTest::namedEnum[opt] << "'" << nl;
}
Info<< nl
<< namedEnumTest::namedEnum["a"] << nl
<< namedEnumTest::namedEnum[namedEnumTest::a] << nl;
<< int(namedEnumTest::optionNamed["a"]) << nl
<< namedEnumTest::optionNamed[namedEnumTest::option::A] << nl;
Info<< "--- test dictionary lookup ---" << endl;
{
Info<< "dict: " << testDict << endl;
namedEnumTest::option gotOpt =
namedEnumTest::namedEnum.lookupOrDefault
(
"test",
testDict,
namedEnumTest::option::a
);
Info<< "got: " << gotOpt << endl;
gotOpt = namedEnumTest::namedEnum.lookupOrDefault
(
"lookup1",
testDict,
namedEnumTest::option::a
);
Info<< "got: " << gotOpt << endl;
Info<< "got: "
<< int
(
namedEnumTest::optionNamed.lookupOrDefault
(
"notFound",
testDict,
namedEnumTest::option::A
)
)
<< nl;
Info<< "got: "
<< int
(
namedEnumTest::optionNamed.lookupOrDefault
(
"lookup1",
testDict,
namedEnumTest::option::A
)
)
<< nl;
}
Info<< "--- test read construction ---" << endl;
Info<< "--- test read ---" << endl;
namedEnumTest::option dummy(namedEnumTest::namedEnum.read(Sin));
Info<< namedEnumTest::namedEnum[dummy] << endl;
namedEnumTest::option dummy(namedEnumTest::optionNamed.read(Sin));
Info<< namedEnumTest::optionNamed[dummy] << endl;
Info<< "End\n" << endl;
......
......@@ -44,22 +44,9 @@ void Foam::DelaunayMeshTools::writeOBJ
OFstream str(fName);
Pout<< nl
<< "Writing points of types:" << nl;
forAllConstIter
(
HashTable<int>,
indexedVertexEnum::vertexTypeNames_,
iter
)
{
if (iter() >= startPointType && iter() <= endPointType)
{
Pout<< " " << iter.key() << nl;
}
}
Pout<< "to " << str.name() << endl;
<< "Writing points of types ("
<< int(startPointType) << "-" << int(endPointType)
<< ") to " << str.name() << endl;
for
(
......@@ -265,7 +252,7 @@ void Foam::DelaunayMeshTools::drawDelaunayCell
<< "f " << 1 + offset << " " << 4 + offset << " " << 3 + offset << nl
<< "f " << 1 + offset << " " << 2 + offset << " " << 4 + offset << endl;
// os << "# cicumcentre " << endl;
// os << "# circumcentre " << endl;
// meshTools::writeOBJ(os, c->dual());
......
......@@ -229,7 +229,7 @@ int main(int argc, char *argv[])
word patchMapMethod;
if (meshToMesh::interpolationMethodNames_.found(mapMethod))
if (meshToMesh::interpolationMethodNames_.hasEnum(mapMethod))
{
// Lookup corresponding AMI method
meshToMesh::interpolationMethod method =
......
......@@ -25,46 +25,25 @@ License
#include "NamedEnum.H"
#include "dictionary.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
template<class Enum, int nEnum>
template<class StringType>
Foam::List<StringType> Foam::NamedEnum<Enum, nEnum>::getNamesList()
{
List<StringType> lst(nEnum);
label count = 0;
for (int enumi=0; enumi < nEnum; ++enumi)
{
if (names[enumi] && names[enumi][0])
{
lst[count++] = names[enumi];
}
}
lst.setSize(count);
return lst;
}
#include "stdFoam.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class Enum, int nEnum>
Foam::NamedEnum<Enum, nEnum>::NamedEnum()
template<class EnumType, int nEnum>
Foam::NamedEnum<EnumType, nEnum>::NamedEnum()
:
table_type(2*nEnum)
lookup_(2*nEnum)
{
for (int enumi=0; enumi < nEnum; ++enumi)
{
if (names[enumi] && names[enumi][0])
{
insert(names[enumi], enumi);
lookup_.insert(names[enumi], enumi);
}
else
{
// Bad name - generate error message
stringList goodNames(enumi);
List<string> goodNames(enumi);
for (int i = 0; i < enumi; ++i)
{
......@@ -74,7 +53,7 @@ Foam::NamedEnum<Enum, nEnum>::NamedEnum()
FatalErrorInFunction
<< "Illegal enumeration name at position " << enumi << nl
<< "after entries " << goodNames << nl
<< "Possibly your NamedEnum<Enum, nEnum>::names array"
<< "Possibly your NamedEnum<EnumType, nEnum>::names array"
<< " is not of size " << nEnum << endl
<< abort(FatalError);
}
......@@ -84,57 +63,93 @@ Foam::NamedEnum<Enum, nEnum>::NamedEnum()
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class Enum, int nEnum>
Enum Foam::NamedEnum<Enum, nEnum>::read(Istream& is) const
template<class EnumType, int nEnum>
Foam::wordList Foam::NamedEnum<EnumType, nEnum>::words() const
{
const word enumName(is);
table_type::const_iterator iter = find(enumName);
List<word> lst(nEnum);
if (!iter.found())
label count = 0;
for (int enumi=0; enumi < nEnum; ++enumi)
{
FatalIOErrorInFunction(is)
<< enumName << " is not in enumeration: "
<< sortedToc() << exit(FatalIOError);
if (names[enumi] && names[enumi][0])
{
lst[count++] = names[enumi];
}
}
lst.setSize(count);
return lst;
}
template<class EnumType, int nEnum>
Foam::List<int> Foam::NamedEnum<EnumType, nEnum>::values() const
{
List<int> lst(nEnum);
label count = 0;
for (int enumi=0; enumi < nEnum; ++enumi)
{
if (names[enumi] && names[enumi][0])
{
auto iter = lookup_.cfind(names[enumi]);
if (iter.found())
{
lst[count++] = iter.object();
}
}
}
return Enum(iter.object());
lst.setSize(count);
return lst;
}
template<class Enum, int nEnum>
void Foam::NamedEnum<Enum, nEnum>::write(const Enum e, Ostream& os) const
template<class EnumType, int nEnum>
bool Foam::NamedEnum<EnumType, nEnum>::hasName(const EnumType e) const
{
os << names[int(e)];
const int enumValue(e);
forAllConstIters(lookup_, iter)
{
if (iter.object() == enumValue)
{
return true;
}
}
return false;
}
template<class Enum, int nEnum>
Enum Foam::NamedEnum<Enum, nEnum>::lookup
template<class EnumType, int nEnum>
EnumType Foam::NamedEnum<EnumType, nEnum>::lookup
(
const word& key,
const dictionary& dict
) const
{
const word enumName(dict.lookup(key));
table_type::const_iterator iter = find(enumName);
auto iter = lookup_.cfind(enumName);
if (!iter.found())
{
FatalIOErrorInFunction(dict)
<< enumName << " is not in enumeration: "
<< sortedToc() << exit(FatalIOError);
<< lookup_.sortedToc() << nl
<< exit(FatalIOError);
}
return Enum(iter.object());
return EnumType(iter.object());
}
template<class Enum, int nEnum>
Enum Foam::NamedEnum<Enum, nEnum>::lookupOrDefault
template<class EnumType, int nEnum>
EnumType Foam::NamedEnum<EnumType, nEnum>::lookupOrDefault
(
const word& key,
const dictionary& dict,
const enum_type deflt
const EnumType deflt
) const
{
if (dict.found(key))
......@@ -148,36 +163,49 @@ Enum Foam::NamedEnum<Enum, nEnum>::lookupOrDefault
}
template<class Enum, int nEnum>
Foam::List<Enum> Foam::NamedEnum<Enum, nEnum>::enums()
template<class EnumType, int nEnum>
EnumType Foam::NamedEnum<EnumType, nEnum>::read(Istream& is) const
{
List<Enum> lst(nEnum);
const word enumName(is);
auto iter = lookup_.cfind(enumName);
label count = 0;
for (int enumi = 0; enumi < nEnum; ++enumi)
if (!iter.found())
{
if (names[enumi] && names[enumi][0])
{
lst[count++] = Enum(enumi);
}
FatalIOErrorInFunction(is)
<< enumName << " is not in enumeration: "
<< lookup_.sortedToc() << nl
<< exit(FatalIOError);
}
lst.setSize(count);
return lst;
return EnumType(iter.object());
}
template<class Enum, int nEnum>
Foam::stringList Foam::NamedEnum<Enum, nEnum>::strings()
template<class EnumType, int nEnum>
void Foam::NamedEnum<EnumType, nEnum>::write
(
const EnumType e,
Ostream& os
) const
{
return getNamesList<string>();
const int idx = int(e);
if (idx >= 0 && idx < nEnum)
{
os << names[idx];
}
}
template<class Enum, int nEnum>
Foam::wordList Foam::NamedEnum<Enum, nEnum>::words()
// * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
template<class EnumType, int nEnum>
Foam::Ostream& Foam::operator<<
(
Ostream& os,
const NamedEnum<EnumType, nEnum>& wrapped
)
{
return getNamesList<word>();
return wrapped.lookup_.writeKeys(os, 10);
}
......
......@@ -25,9 +25,8 @@ Class
Foam::NamedEnum
Description
A NamedEnum is a wrapper around a static list of names that represent
a particular enumeration. Internally it uses a HashTable for quicker
lookups.
A NamedEnum is a wrapper around a list of names that represent
particular enumeration values.
SourceFiles
NamedEnum.C
......@@ -38,7 +37,6 @@ SourceFiles
#define NamedEnum_H
#include "HashTable.H"
#include "stringList.H"
#include "wordList.H"
#include <type_traits>
......@@ -46,32 +44,31 @@ SourceFiles
namespace Foam
{
// Forward declarations
class dictionary;
template<class EnumType, int nEnum> class NamedEnum;
template<class EnumType, int nEnum>
Ostream& operator<<(Ostream& os, const NamedEnum<EnumType, nEnum>& wrapped);
// Forward declaration
template<class Enum, int> class NamedEnum;
/*---------------------------------------------------------------------------*\
Class NamedEnum Declaration
\*---------------------------------------------------------------------------*/
template<class Enum, int nEnum>
template<class EnumType, int nEnum>
class NamedEnum
:
public HashTable<int>
{
//- The nEnum must be positive (non-zero)
static_assert(nEnum > 0, "nEnum must be positive (non-zero)");
//- The type of HashTable used for the lookup.
typedef HashTable<int> table_type;
// Private Member Data
//- The values for the enum
HashTable<int> lookup_;
// Private Member Functions
//- The names as a list of strings
template<class StringType>
static List<StringType> getNamesList();
// Private Member Functions
//- Disallow default bitwise copy construct
NamedEnum(const NamedEnum&) = delete;
......@@ -83,12 +80,12 @@ class NamedEnum
public:
//- The type of enumeration wrapped by NamedEnum
typedef Enum enum_type;
typedef EnumType value_type;
// Static data members
//- The set of names corresponding to the enumeration Enum
//- The set of names corresponding to the enumeration EnumType
static const char* names[nEnum];
......@@ -100,17 +97,39 @@ public:
// Member Functions
//- Read a word from Istream and return the corresponding
// enumeration element
enum_type read(Istream& is) const;
// Access
//- Write the name representation of the enumeration to an Ostream
void write(const enum_type e, Ostream& os) const;
//- The number of lookup names for the enumeration
inline label size() const;
//- The list of enum names
inline wordList toc() const;
//- The sorted list of enum names
inline wordList sortedToc() const;
//- The list of enum names, in construction order
wordList words() const;
//- The list of enum values, in construction order
List<int> values() const;
// Query
//- Test if there is an enumeration corresponding to the given name.
inline bool hasEnum(const word& enumName) const;
//- Test if there is a name corresponding to the given enumeration.
bool hasName(const EnumType e) const;
// Lookup
//- Lookup the key in the dictionary and return the corresponding
// enumeration element based on its name.
// Fatal if anything is incorrect.
enum_type lookup
EnumType lookup
(
const word& key,
const dictionary& dict
......@@ -120,42 +139,42 @@ public:
// enumeration element based on its name.
// Return the default value if the key was not found in the dictionary.
// Fatal if enumerated name was incorrect.
enum_type lookupOrDefault
EnumType lookupOrDefault
(
const word& key,
const dictionary& dict,
const enum_type deflt
const EnumType deflt
) const;
//- List of enumerations
static List<enum_type> enums();
//- The set of names as a list of strings
static stringList strings();
// IO
//- Read a word from Istream and return the corresponding enumeration
EnumType read(Istream& is) const;
//- The set of names as a list of words
static wordList words();
//- Write the name representation of the enumeration to an Ostream
// A noop if the enumeration wasn't found.
void write(const EnumType e, Ostream& os) const;
// Member Operators
//- Return the enumeration element corresponding to the given name
inline const enum_type operator[](const char* name) const
{
return enum_type(table_type::operator[](name));
}
//- Return the enumeration element corresponding to the given name
inline const enum_type operator[](const word& name) const
{
return enum_type(table_type::operator[](name));
}
inline const EnumType operator[](const word& name) const;
//- Return the name of the given enumeration element
inline const char* operator[](const enum_type e) const
{
return names[int(e)];
}
inline const char* operator[](const EnumType e) const;
// IOstream operators
//- Write names to Ostream, as per writeKeys() with shortListLen=10
friend Ostream& operator<< <EnumType, nEnum>
(
Ostream& os,
const NamedEnum<EnumType, nEnum>& wrapped
);
};
......@@ -165,6 +184,8 @@ public:
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "NamedEnumI.H"
#ifdef NoRepository
#include "NamedEnum.C"
#endif
......