Boost logo

Boost :

From: Frank Laub (frank.laub_at_[hidden])
Date: 2005-12-13 01:37:34


I've updated the BOOST_ENUM stuff in the file vault:
*http://tinyurl.com/cznqu
*
Currently, there are three flavors of enumerated types available.

1. BOOST_ENUM
This type of enum provides the user with a simple way to express an enum.

example usage:
BOOST_ENUM(boolean,
    (False)
    (True)
)

This flavor does not allow each element of the enum to be defined. It is
assumed that the first element will begin with the value 0 and the last
element will be equal to the count of elements - 1. The following methods
are available with this type:

static const_iterator begin()
static const_iterator end()
static boost::optional<const T> get(size_t index)
static boost::optional<const T> parse(const char* str)
const char* str() const
bool operator == (const T& rhs) const
bool operator != (const T& rhs) const
ostream& operator << (ostream& os, const T& rhs)

2. BOOST_ENUM_VALUES
This flavor of enum is the same as the basic enum flavor but it allows the
user to specify values for each element.

example usage:
BOOST_ENUM_VALUES(VirtualKey,
    (Space)(0x20)
    (Prior)(0x21)
    (Next)(0x22)
    (End)(0x23)
    (Home)(0x24)
)

In addition to the methods described above with the basic flavor, these are
also available:

static boost::optional<const T> make(size_t value)
size_t value() const

3. BOOST_BITFIELD
A bitfield is much like a BOOST_ENUM_VALUES except that each value is
interpreted as a bitmask. This allows many common bitmask operations to be
done in a more elegant way; forcing the user to only use bitmasks that are
in the domain of the defined bitfield.

example usage:
BOOST_BITFIELD(MouseKey,
    (LeftButton)(0x0001)
    (RightButton)(0x0002)
    (Shift)(0x0004)
    (Control)(0x0008)
    (MiddleButton)(0x0010)
)

This type has all of the methods defined for a BOOST_ENUM_VALUES along with
these:

static T all_mask()
std::string str() const
void operator |= (const T& rhs)
T operator | (const T& rhs) const
size_t operator & (const T& rhs) const
// TODO: add some more of these like &=, ~, etc.

str() for this type returns a string instead of a const char* because it has
to generate the string on the fly for each instance. Perhaps there is a more
compile-time approach, but I think this would involve lots of tagged type
lists and such. Taking the MouseKey as an example, one can do this:
MouseKey mkLeft = MouseKey::LeftButton;
MouseKey mkShift = MouseKey::Shift;
MouseKey mk = mkLeft | mkShift;
cout << mk << endl;

The output will be:
LeftButton | Shift

Implementation notes:
Instead of needing an 'Invalid' element, I just use Boost.Optional now.
Thanks a ton for that suggestion Yuval!

Using a switch/case instead of an array for storage of the strings and
values of the enum turned out to be pretty straight-forward. With this
approach, as was noted earlier, there should be no thread safety issues.
I've looked at the disassembly of an optimized example with VC8 and it looks
like the compiler just gets rid of all the overhead anyway. I also found
that using a switch/case made it possible to be re-used across the many
flavors.

These types are now instanciable, and I think it is much easier/cleaner to
use. Instances of BOOST_ENUM and BOOST_ENUM_VALUES store not the value of
the enum element, but the index that it appears in the defining sequence.
BOOST_ENUM is actually special because its index always matches its value.
Because of this, BOOST_ENUM_VALUES takes a small hit for the make() method
because it needs to walk through all of the available values and find one
that matches. The tricky thing for the user is that make() will return the
first element that matches. So if a user defines A and B to both be equal to
10, and the user calls make(10), it will return A. However if the user
defines B before A, make(10) will return B. BOOST_BITFIELD stores the actual
raw value so that all of the bitwise operators will be fast and efficient.
In a previous attempt to write this flavor, I used a std::set<size_t> of
indicies. This is expensive both for the bitwise operators and the storage
requirements for each instance of this type. The consequence of storing the
raw value is that the str() method has a bit of overhead since it has to
mask off each element and check to see if the remaining bits match any
values defined in the sequence. It also means that, like BOOST_ENUM_VALUES,
the order in which the user defines each bitfield element can change the
resulting string representation.

As always, any comments are much appreciated.

-Frank


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk