// Author: Ali Cehreli // Started: August 13, 1999 /** \file Defines a bit field class that can be used as an alternative to C's bitfields */ #ifndef INCLUDED_BITFIELD_H #define INCLUDED_BITFIELD_H #include #include /// An alternative bit field array /** C and C++ compilers have too much freedom in constructing bitfields. They can allocate the bitfields in anyway they want. In order to match the hardware, we need to have the fields at exact positions in the IntegerType. The class is very memory-efficient. The only member is the underlying integral type. Also the fields, setter/getter functions are all templates. The constants used by these are known at compile time. This causes some code-bloat though. Every instantiation of the template function will have a separate function linked. One nice feature is ArrayField where one can define an array of bit fields. */ template class BitField { IntegerType impl_; // protected: public: /// Initialized with the implementation type BitField(const IntegerType & impl = IntegerType()) : impl_(impl) {} /// Sets the bits defined by 'bits' to the specified value template void setField(const FieldType & bits, const IntegerType & value) { // Not as inefficient as it seems: bits.mask() returns a reference impl_ &= bits.inverseMask(); impl_ |= ((value << bits.pos()) & bits.mask()); } /// Sets the bits of the specified index of the array template void setArrayField(const FieldType & bits, int idx, const IntegerType & value) { assert((idx >= 0) && (idx < bits.cnt())); int const offset = idx * bits.len(); IntegerType const mask = (bits.mask() << offset); impl_ &= ~mask; impl_ |= ((value << (bits.pos() + offset)) & mask); } /// Sets random bits /** The need for this function arose after the introduction of 'extremely free' pattern entries. I couldn't define the pattern entries statically. Pattern table class calculates the field positions at runtime. Giving access to random bits breaks the safety though. */ template void setBits(int length, int offset, ValueType const & value) { IntegerType mask(1); mask <<= length; --mask; mask <<= offset; impl_ &= ~mask; impl_ |= ((IntegerType(value) << offset) & mask); } /// Returns the value stored in the field template IntegerType getField(const FieldType & bits) const { return (impl_ & bits.mask()) >> bits.pos(); } /// Returns the value stored at the index position of the array template IntegerType getArrayField(const FieldType & bits, int idx) const { assert((idx >= 0) && (idx < bits.cnt())); int offset = idx * bits.len(); return (impl_ & (bits.mask() << offset)) >> (bits.pos() + offset); } /// Returns the size of the field /** It looks like only nextClassBeforeFunc needs this function. */ template size_t size(const FieldType & bits) const { return bits.len(); } public: /// An array of fields in the underlying implementation word /** Length is the length of the fields in the array. Position is the offset of the lowermost bit of the entire array. Count is the number of members of the array. */ template class ArrayField { friend class BitField; /// Builds the mask for the fields of this array static IntegerType makeMask() { // example: pos=3, len=2 IntegerType mask(1); // = 000001 mask <<= Length; // = 000100 --mask; // = 000011 mask <<= Position; // = 011000 return mask; } /// Efficiency comes from the static local variable: it is initialized only ones. static const IntegerType & mask() { static IntegerType const mask_ = makeMask(); return mask_; } static const IntegerType & inverseMask() { static IntegerType const inverseMask_ = ~mask(); return inverseMask_; } /** @name Trivial accessors */ //@{ static int len() { return Length; } static int pos() { return Position; } static int cnt() { return Count; } //@} }; /// Field is defined as being an array with one member. /** This could probably be made more efficient if defined separately. */ template class Field : public ArrayField {}; /// Classes inheriting from this can use value_type to refer to the implementation type. typedef IntegerType value_type; /// Returns the complete implementation word at once const IntegerType & value() const { return impl_; } /// Allows the class to be used at places where an IntegerType is expected operator IntegerType() const { return value(); } }; /// Output function template std::ostream & operator<< (std::ostream & os, const BitField & bf) { return os << bf.value(); } #endif // INCLUDED_BITFIELD_H