EnumBase.h
// EnumBase.h
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2007
#include "Ceda/cxUtils/BasicTypes.h"
#include "Ceda/cxUtils/CedaAssert.h"
#include "Ceda/cxUtils/xchar.h"
namespace ceda
{
class xostream;
/*
Helps to allow xcpp to generate a version of an enum using a class
- allowing the labels to be inside the enum type, rather than polluting the containing
namespace.
- supporting forwards and reverse iterators
- allowing for validation when converted from an int value.
- providing conversion to a string representation, and writing to an ostream
- serialisation to an archive as an int32.
For example
$enum+ Colour
{
R, G, B, M, C, Y
};
expands into
class Colour : public ceda::EnumBase<Colour>
{
public:
enum Enum
{
R,G,B,M,C,Y
};
Colour(Enum v) : EnumBase(v) {}
explicit Colour(int v = 0) : EnumBase(v) {}
enum { LEN = 6 };
static ConstStringZ const* strings()
{
static ConstStringZ s[] = {"R","G","B","M","C","Y"};
return s;
}
};
*/
template <typename E>
class EnumBase
{
protected:
explicit EnumBase(int v)
{
cxAssert(E::IsValidValue(v));
value = v;
}
public:
operator int() const { return value; }
// Index values are always in the range [0,LEN), even when the enum values are not 0,1,2,...
static bool IsValidIndex(int i) { return 0 <= i && i <= E::LEN-1; }
class iterator
{
public:
iterator(typename E::Enum e) : index(E::ValueToIndex(e)) {}
iterator(E v) : index(E::ValueToIndex(v.value)) {}
explicit iterator(int i) : index(i) {}
ConstStringZ c_str() const { return E::stringArray()[index]; }
int Index() const { return index; }
E operator*() const { return E(E::IndexToValue(index)); }
iterator& operator++() { ++index; return *this; }
const iterator operator++(int) { iterator it = *this; ++(*this); return it; }
iterator& operator--() { --index; return *this; }
const iterator operator--(int) { iterator it = *this; --(*this); return it; }
bool operator==(const iterator& rhs) const { return index == rhs.index; }
bool operator!=(const iterator& rhs) const { return index != rhs.index; }
private:
int32 index;
};
static iterator begin() { return iterator(0); }
static iterator end() { return iterator(E::LEN); }
class reverse_iterator
{
public:
reverse_iterator(typename E::Enum e) : index(E::ValueToIndex(e)) {}
reverse_iterator(E v) : index(E::ValueToIndex(v.value)) {}
explicit reverse_iterator(int i) : index(i) {}
ConstStringZ c_str() const { return E::stringArray()[index]; }
int Index() const { return index; }
E operator*() const { return E(E::IndexToValue(index)); }
reverse_iterator& operator++() { --index; return *this; }
const reverse_iterator operator++(int) { reverse_iterator it = *this; ++(*this); return it; }
reverse_iterator& operator--() { ++index; return *this; }
const reverse_iterator operator--(int) { reverse_iterator it = *this; --(*this); return it; }
bool operator==(const reverse_iterator& rhs) const { return index == rhs.index; }
bool operator!=(const reverse_iterator& rhs) const { return index != rhs.index; }
private:
int32 index;
};
static reverse_iterator rbegin() { return reverse_iterator(E::LEN-1); }
static reverse_iterator rend() { return reverse_iterator(-1); }
ConstStringZ c_str() const
{
return E::stringArray()[E::ValueToIndex(value)];
}
////////////// By default we assume value == index. Derived classes must override these where required
static int IndexToValue(int i) { return i; }
static int ValueToIndex(int v)
{
cxAssert(0 <= v && v < E::LEN);
return v;
}
static bool IsValidValue(int v) { return 0 <= v && v < E::LEN; }
//////////////
int32 value;
};
template <typename E>
inline xostream& operator<<(xostream& os,EnumBase<E> x) { os << x.c_str(); return os; }
template <typename Archive, typename E>
inline void Serialise(Archive& ar, EnumBase<E> x)
{
ar << x.value;
}
template <typename Archive, typename E>
inline void Deserialise(Archive& ar, EnumBase<E>& x)
{
ar >> x.value;
}
// To be used when E defines the valueArray() - a mapping from index to value
template <typename E>
class EnumBaseForRefinedLabels : public EnumBase<E>
{
protected:
explicit EnumBaseForRefinedLabels(int v) : EnumBase<E>(v) {}
public:
static int IndexToValue(int i)
{
cxAssert(EnumBase<E>::IsValidIndex(i));
return E::valueArray()[i];
}
static int ValueToIndex(int v)
{
for (int i=0 ; i < E::LEN ; ++i)
{
if (E::valueArray()[i] == v) return i;
}
cxAssert(0);
return -1;
}
static bool IsValidValue(int v)
{
for (int i=0 ; i < E::LEN ; ++i)
{
if (E::valueArray()[i] == v) return true;
}
return false;
}
};
} // namespace ceda