diff options
Diffstat (limited to 'shared/loki/SafeBits.h')
-rw-r--r-- | shared/loki/SafeBits.h | 514 |
1 files changed, 514 insertions, 0 deletions
diff --git a/shared/loki/SafeBits.h b/shared/loki/SafeBits.h new file mode 100644 index 00000000..f45065ed --- /dev/null +++ b/shared/loki/SafeBits.h @@ -0,0 +1,514 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2009 by Fedor Pikus & Rich Sposato +// The copyright on this file is protected under the terms of the MIT license. +// +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// +// The author makes no claims about the suitability of this software for any +// purpose. It is provided "as is" without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// + +// $Id$ + + +#ifndef LOKI_INCLUDED_SAFE_BIT_FIELDS_H +#define LOKI_INCLUDED_SAFE_BIT_FIELDS_H + +#include <cstdlib> +#include <assert.h> +#include <loki/static_check.h> + + +namespace Loki +{ + +/* + ========================================================================================================================================== + SafeBitField - type-safe class for bit fields. + SafeBitConst - type-safe class for bit constants. + SafeBitField is designed to be a [almost] drop-in replacement for integer flags and bit fields where individual bits are set and checked + using symbolic names for flags: + + typedef unsigned long Labels_t; + Labels_t labels; + const Labels_t Label_A = 0x00000001; + const Labels_t Label_B = 0x00000002; + ... + labels |= Label_B; + if ( labels & Label_A ) { ... } + + Such code offers no protection against mismatching bit constants and bit fields: + + typedef unsigned long Kinds_t; + Kinds_t kinds; + const Kinds_t Kind_A = 0x00000004; + ... + if ( kinds & Label_A ) { ... } // Error but compiles + + SafeBitField is a drop-in replacement which generates a unique type for each bit field. Bit fields of different types cannot be applied + to each other: + + LOKI_BIT_FIELD( unsigned long ) Labels_t; + Labels_t labels; + LOKI_BIT_CONST( Labels_t, Label_A, 1 ); // 0x0001 - 1st bit is set + LOKI_BIT_CONST( Labels_t, Label_B, 2 ); // 0x0002 - 1st bit is set + ... + LOKI_BIT_FIELD( unsigned long ) Kinds_t; + Kinds_t kinds; + LOKI_BIT_CONST( Kinds_t, Kind_A, 3 ); // 0x0004 - 1st bit is set + ... + if ( kinds & Label_A ) { ... } // Does not compile + + Several other kinds of bit field misuse are caught by safe bit fields: + + if ( kinds & Kind_A == 0 ) { ... } + if ( kinds && Kind_A ) { ... } + + There are few cases where drop-in replacement does not work: + + 1. Operations involving bit fields and unnamed integers. Usually the integer in question is 0: + + Labels_t labels = 0; // No longer compiles + if ( ( labels & Label_A ) == 0 ) { ... } // Also does not compile + + The solution is to use named bit constants, including the one for 0: + + LOKI_BIT_CONST( Labels_t, Label_None, 0 ); // 0x0000 - No bit is set + Labels_t labels = Label_None; // Or just Labels_t labels; - constructor initializes to 0 + if ( ( labels & Label_A ) == Label_None ) { ... } // // Or just if ( labels & Label_A ) { ... } + + 2. I/O and other operations which require integer variables and cannot be modified: + + void write_to_db( unsigned int word ); + Labels_t labels; + write_to_db( labels ); // No longer compiles + + This problem is solved by reinterpreting the bit fields as an integer, the user is responsible for using the right + type of integer: + + write_to_db( *((Labels_t::bit_word_t*)(&labels)) ); + + ========================================================================================================================================== +*/ + +/// @par Non-Templated Initialization. +/// Not all compilers support template member functions where the template +/// arguments are not deduced but explicitly specified. For these broken +/// compilers, a non-template make_bit_const() function is provided instead of +/// the template one. The only downside is that instead of compile-time checking +/// of the index argument, it does runtime checking. +#if defined(__SUNPRO_CC) || ( defined(__GNUC__) && (__GNUC__ < 3) ) + #define LOKI_BIT_FIELD_NONTEMPLATE_INIT +#endif + +/// @par Forbidding Conversions. +/// This incomplete type prevents compilers from instantiating templates for +/// type conversions which should not happen. This incomplete type must be a +/// template: if the type is incomplete at the point of template definition, +/// the template is illegal (although the standard allows compilers to accept +/// or reject such code, ยง14.6/, so some compilers will not issue diagnostics +/// unless template is instantiated). The standard-compliant way is to defer +/// binding to the point of instantiation by making the incomplete type itself +/// a template. +template < typename > struct Forbidden_conversion; // This struct must not be defined! + +/// Forward declaration of the field type. +template < + unsigned int unique_index, + typename word_t = unsigned long +> class SafeBitField; + +//////////////////////////////////////////////////////////////////////////////// +/// \class SafeBitConst Bit constants. +/// This class defines a bit-field constant - a collection of unchanging bits +/// used to compare to bit-fields. Instances of this class are intended to act +/// as labels for bit-fields. +/// +/// \par Safety +/// - This class provides operations used for comparisons and conversions, but +/// no operations which may modify the value. +/// - As a templated class, it provides type-safety so bit values and constants +/// used for different reasons may not be unknowingly compared to each other. +/// - The unique_index template parameter insures the unique type of each bit +/// bit-field. It shares the unique_index with a similar SafeBitField. +/// - Its operations only allow comparisons to other bit-constants and +/// bit-fields of the same type. +//////////////////////////////////////////////////////////////////////////////// + +template +< + unsigned int unique_index, + typename word_t = unsigned long +> +class SafeBitConst +{ +public: + + /// Type of the bit field is available if needed. + typedef word_t bit_word_t; + /// Corresponding field type. + typedef SafeBitField< unique_index, word_t > field_t; + /// Typedef is not allowed in friendship declaration. + friend class SafeBitField< unique_index, word_t >; + + // Static factory constructor, creates a bit constant with one bit set. The position of the bit is given by the template parameter, + // bit 1 is the junior bit, i.e. make_bit_const<1>() returns 1. Bit index 0 is a special case and returns 0. + // This function should be used only to initialize the static bit constant objects. + // This function will not compile if the bit index is outside the vaild range. + // There is also a compile-time assert to make sure the size of the class is the same as the size of the underlaying integer type. + // This assert could go into the constructor, but aCC does not seem to understand sizeof(SafeBitConst) in the constructor. + // +#ifndef LOKI_BIT_FIELD_NONTEMPLATE_INIT + template < unsigned int i > static SafeBitConst make_bit_const() + { + LOKI_STATIC_CHECK( i <= ( 8 * sizeof(word_t) ), Index_is_beyond_size_of_data ); + LOKI_STATIC_CHECK( sizeof(SafeBitConst) == sizeof(word_t), Object_size_does_not_match_data_size ); + // Why check for ( i > 0 ) again inside the shift if the shift + // can never be evaluated for i == 0? Some compilers see shift by ( i - 1 ) + // and complain that for i == 0 the number is invalid, without + // checking that shift needs evaluating. + return SafeBitConst( ( i > 0 ) ? ( word_t(1) << ( ( i > 0 ) ? ( i - 1 ) : 0 ) ) : 0 ); + } +#else + static SafeBitConst make_bit_const( unsigned int i ) + { + LOKI_STATIC_CHECK( sizeof(SafeBitConst) == sizeof(word_t), Object_size_does_not_match_data_size ); + assert( i <= ( 8 * sizeof(word_t) ) ); // Index is beyond size of data. + // Why check for ( i > 0 ) again inside the shift if the shift + // can never be evaluated for i == 0? Some compilers see shift by ( i - 1 ) + // and complain that for i == 0 the number is invalid, without + // checking that shift needs evaluating. + return SafeBitConst( ( i > 0 ) ? ( word_t(1) << ( ( i > 0 ) ? ( i - 1 ) : 0 ) ) : 0 ); + } +#endif + + /// Default constructor allows client code to construct bit fields on the stack. + SafeBitConst() : word( 0 ) {} + + /// Copy constructor. + SafeBitConst( const SafeBitConst& rhs ) : word( rhs.word ) {} + + /// Comparison operators which take a constant bit value. + bool operator == ( const SafeBitConst & rhs ) const { return word == rhs.word; } + bool operator != ( const SafeBitConst & rhs ) const { return word != rhs.word; } + bool operator < ( const SafeBitConst & rhs ) const { return word < rhs.word; } + bool operator > ( const SafeBitConst & rhs ) const { return word > rhs.word; } + bool operator <= ( const SafeBitConst & rhs ) const { return word <= rhs.word; } + bool operator >= ( const SafeBitConst & rhs ) const { return word >= rhs.word; } + + /// Comparision operators for mutable bit fields. + bool operator == ( const field_t & rhs ) const { return word == rhs.word; } + bool operator != ( const field_t & rhs ) const { return word != rhs.word; } + bool operator < ( const field_t & rhs ) const { return word < rhs.word; } + bool operator > ( const field_t & rhs ) const { return word > rhs.word; } + bool operator <= ( const field_t & rhs ) const { return word <= rhs.word; } + bool operator >= ( const field_t & rhs ) const { return word >= rhs.word; } + + /// Bitwise operations. Operation-assignment operators are not needed, + /// since bit constants cannot be changed after they are initialized. + const SafeBitConst operator | ( const SafeBitConst & rhs ) const { return SafeBitConst( word | rhs.word ); } + const SafeBitConst operator & ( const SafeBitConst & rhs ) const { return SafeBitConst( word & rhs.word ); } + const SafeBitConst operator ^ ( const SafeBitConst & rhs ) const { return SafeBitConst( word ^ rhs.word ); } + const SafeBitConst operator ~ ( void ) const { return SafeBitConst( ~word ); } + + /// These bitwise operators return a bit-field instead of a bit-const. + field_t operator | ( const field_t & rhs ) const { return field_t( word | rhs.word ); } + field_t operator & ( const field_t & rhs ) const { return field_t( word & rhs.word ); } + field_t operator ^ ( const field_t & rhs ) const { return field_t( word ^ rhs.word ); } + + /// The shift operators move bits inside the bit field. These are useful in + /// loops which act over bit fields and increment them. + const SafeBitConst operator << ( unsigned int s ) const { return SafeBitConst( word << s ); } + const SafeBitConst operator >> ( unsigned int s ) const { return SafeBitConst( word >> s ); } + + /// Word size is also the maximum number of different bit fields for a given word type. + static size_t size() { return ( 8 * sizeof( word_t ) ); } + +private: + + /// Copy-assignment operator is not implemented since it does not make sense + /// for a constant object. + SafeBitConst operator = ( const SafeBitConst & rhs ); + + // Private constructor from an integer type. + explicit SafeBitConst( word_t init ) : word( init ) {} + + /// This data stores a single bit value. It is declared const to enforce + // constness for all functions of this class. + const word_t word; + + // Here comes the interesting stuff: all the operators designed to + // trap unintended conversions and make them not compile. + // Operators below handle code like this: + // SafeBitField<1> label1; + // SafeBitField<2> label2; + // if ( label1 & label2 ) { ... } + + // These operators are private, and will not instantiate in any + // event because of the incomplete Forbidden_conversion struct. + template < typename T > SafeBitConst operator|( T ) const { Forbidden_conversion< T > wrong; return *this; } + template < typename T > SafeBitConst operator&( T ) const { Forbidden_conversion< T > wrong; return *this; } + template < typename T > SafeBitConst operator^( T ) const { Forbidden_conversion< T > wrong; return *this; } + template < typename T > SafeBitConst operator|=( T ) const { Forbidden_conversion< T > wrong; return *this; } + template < typename T > SafeBitConst operator&=( T ) const { Forbidden_conversion< T > wrong; return *this; } + template < typename T > SafeBitConst operator^=( T ) const { Forbidden_conversion< T > wrong; return *this; } + + // And the same thing for comparisons: private and unusable. + // if ( label1 == label2 ) { ... } + template < typename T > bool operator==( const T ) const { Forbidden_conversion< T > wrong; return true; } + template < typename T > bool operator!=( const T ) const { Forbidden_conversion< T > wrong; return true; } + template < typename T > bool operator<( const T ) const { Forbidden_conversion< T > wrong; return true; } + template < typename T > bool operator>( const T ) const { Forbidden_conversion< T > wrong; return true; } + template < typename T > bool operator<=( const T ) const { Forbidden_conversion< T > wrong; return true; } + template < typename T > bool operator>=( const T ) const { Forbidden_conversion< T > wrong; return true; } +}; + + +//////////////////////////////////////////////////////////////////////////////// +/// \class SafeBitConst Bit constants. +/// This class defines a bit-field constant - a collection of unchanging bits +/// used to compare to bit-fields. Instances of this class are intended to +/// store bit values. +/// +/// \par Safety +/// - This class provides operations used for comparisons and conversions, and +/// also operations which may safely modify the value. +/// - As a templated class, it provides type-safety so bit values and constants +/// used for different reasons may not be unknowingly compared to each other. +/// - The unique_index template parameter insures the unique type of each bit +/// bit-field. It shares the unique_index with a similar SafeBitConst. +/// - Its operations only allow comparisons to other bit-constants and +/// bit-fields of the same type. +//////////////////////////////////////////////////////////////////////////////// + +template +< + unsigned int unique_index, + typename word_t +> +class SafeBitField +{ +public: + + /// Type of the bit field is available if needed. + typedef word_t bit_word_t; + /// Corresponding field type. + typedef SafeBitConst< unique_index, word_t > const_t; + /// Typedef is not allowed in friendship declaration. + friend class SafeBitConst<unique_index, word_t>; + + /// Default constructor allows client code to construct bit fields on the stack. + SafeBitField() : word( 0 ) {} + + /// Copy constructor and assignment operators. + SafeBitField( const SafeBitField & rhs ) : word( rhs.word ) {} + SafeBitField & operator = ( const SafeBitField & rhs ) { word = rhs.word; return *this; } + + /// Copy constructor and assignment operators from constant bit fields. + SafeBitField( const const_t & rhs ) : word( rhs.word ) {} + SafeBitField & operator = ( const const_t & rhs ) { word = rhs.word; return *this; } + + /// These comparison operators act on bit-fields of the same type. + bool operator == ( const SafeBitField & rhs ) const { return word == rhs.word; } + bool operator != ( const SafeBitField & rhs ) const { return word != rhs.word; } + bool operator < ( const SafeBitField & rhs ) const { return word < rhs.word; } + bool operator > ( const SafeBitField & rhs ) const { return word > rhs.word; } + bool operator <= ( const SafeBitField & rhs ) const { return word <= rhs.word; } + bool operator >= ( const SafeBitField & rhs ) const { return word >= rhs.word; } + + /// These comparison operators act on bit-constants of a similar type. + bool operator == ( const const_t & rhs ) const { return word == rhs.word; } + bool operator != ( const const_t & rhs ) const { return word != rhs.word; } + bool operator < ( const const_t & rhs ) const { return word < rhs.word; } + bool operator > ( const const_t & rhs ) const { return word > rhs.word; } + bool operator <= ( const const_t & rhs ) const { return word <= rhs.word; } + bool operator >= ( const const_t & rhs ) const { return word >= rhs.word; } + + /// Bitwise operations that use bit-fields. + SafeBitField operator | ( const SafeBitField & rhs ) const { return SafeBitField( word | rhs.word ); } + SafeBitField operator & ( const SafeBitField & rhs ) const { return SafeBitField( word & rhs.word ); } + SafeBitField operator ^ ( const SafeBitField & rhs ) const { return SafeBitField( word ^ rhs.word ); } + SafeBitField operator ~ ( void ) const { return SafeBitField( ~word ); } + SafeBitField operator |= ( const SafeBitField & rhs ) { word |= rhs.word; return SafeBitField( *this ); } + SafeBitField operator &= ( const SafeBitField & rhs ) { word &= rhs.word; return SafeBitField( *this ); } + SafeBitField operator ^= ( const SafeBitField & rhs ) { word ^= rhs.word; return SafeBitField( *this ); } + + /// Bitwise operators that use bit-constants. + SafeBitField operator | ( const_t rhs ) const { return SafeBitField( word | rhs.word ); } + SafeBitField operator & ( const_t rhs ) const { return SafeBitField( word & rhs.word ); } + SafeBitField operator ^ ( const_t rhs ) const { return SafeBitField( word ^ rhs.word ); } + SafeBitField operator |= ( const_t rhs ) { word |= rhs.word; return SafeBitField( *this ); } + SafeBitField operator &= ( const_t rhs ) { word &= rhs.word; return SafeBitField( *this ); } + SafeBitField operator ^= ( const_t rhs ) { word ^= rhs.word; return SafeBitField( *this ); } + + // Conversion to bool. + // This is a major source of headaches, but it's required to support code like this: + // const static SafeBitConst<1> Label_value = SafeBitConst<1>::make_bit_const<1>(); + // SafeBitField<1> label; + // if ( label & Label_value ) { ... } // Nice... + // + // The downside is that this allows all sorts of nasty conversions. Without additional precautions, bit fields of different types + // can be converted to bool and then compared or operated on: + // SafeBitField<1> label1; + // SafeBitField<2> label2; + // if ( label1 == label2 ) { ... } // Yuck! + // if ( label1 & label2 ) { ... } // Blech! + // + // It is somewhat safer to convert to a pointer, at least pointers to different types cannot be readilly compared, and there are no + // bitwise operations on pointers, but the conversion from word_t to a pointer can have run-time cost if they are of different size. + // + operator const bool() const { return ( 0 != word ); } + + // Shift operators shift bits inside the bit field. Does not make + // sense, most of the time, except perhaps to loop over labels and + // increment them. + SafeBitField operator << ( unsigned int s ) { return SafeBitField( word << s ); } + SafeBitField operator >> ( unsigned int s ) { return SafeBitField( word >> s ); } + SafeBitField operator <<= ( unsigned int s ) { word <<= s; return *this; } + SafeBitField operator >>= ( unsigned int s ) { word >>= s; return *this; } + + // Word size is also the maximum number of different bit fields for + // a given word type. + static size_t size( void ) { return ( 8 * sizeof( word_t ) ); } + +private: + + /// Private constructor from an integer type. Don't put too much stock into + /// explicit declaration, it's better than nothing but does not solve all + /// problems with undesired conversions because SafeBitField coverts to bool. + explicit SafeBitField( word_t init ) : word( init ) {} + + /// This stores the bits. + word_t word; + + // Here comes the interesting stuff: all the operators designed to + // trap unintended conversions and make them not compile. + // Operators below handle code like this: + // SafeBitField<1> label1; + // SafeBitField<2> label2; + // if ( label1 & label2 ) { ... } + + // These operators are private, and will not instantiate in any + // event because of the incomplete Forbidden_conversion struct. + template < typename T > SafeBitField operator | ( T ) const { Forbidden_conversion< T > wrong; return *this; } + template < typename T > SafeBitField operator & ( T ) const { Forbidden_conversion< T > wrong; return *this; } + template < typename T > SafeBitField operator ^ ( T ) const { Forbidden_conversion< T > wrong; return *this; } + template < typename T > SafeBitField operator |= ( T ) const { Forbidden_conversion< T > wrong; return *this; } + template < typename T > SafeBitField operator &= ( T ) const { Forbidden_conversion< T > wrong; return *this; } + template < typename T > SafeBitField operator ^= ( T ) const { Forbidden_conversion< T > wrong; return *this; } + + // And the same thing for comparisons: + // if ( label1 == label2 ) { ... } + template < typename T > bool operator == ( const T ) const { Forbidden_conversion< T > wrong; return true; } + template < typename T > bool operator != ( const T ) const { Forbidden_conversion< T > wrong; return true; } + template < typename T > bool operator < ( const T ) const { Forbidden_conversion< T > wrong; return true; } + template < typename T > bool operator > ( const T ) const { Forbidden_conversion< T > wrong; return true; } + template < typename T > bool operator <= ( const T ) const { Forbidden_conversion< T > wrong; return true; } + template < typename T > bool operator >= ( const T ) const { Forbidden_conversion< T > wrong; return true; } +}; + +// The above template member operators catch errors when the first +// argument to a binary operator is a label, but they don't work when +// the first argument is an integer and the second one is a label: the +// label converts to bool and the operator is performed on two integers. +// These operators catch errors like this: +// SafeBitField<1> label1; +// SafeBitField<2> label2; +// if ( !label1 & label2 ) { ... } +// where the first label is converted to bool (these errors cannot be +// caught by member operators of SafeBitField class because the first +// argument is not SafeBitField but bool. +// +// If used, these operators will not instantiate because of the +// incomplete Forbidden_conversion struct. + +template < unsigned int unique_index, typename word_t > +inline SafeBitField< unique_index, word_t > operator & ( bool, SafeBitField< unique_index, word_t > rhs ) +{ + Forbidden_conversion<word_t> wrong; + return rhs; +} + +template < unsigned int unique_index, typename word_t > +inline SafeBitField< unique_index, word_t > operator | ( bool, SafeBitField< unique_index, word_t > rhs ) +{ + Forbidden_conversion< word_t > wrong; + return rhs; +} + +template < unsigned int unique_index, typename word_t > +inline SafeBitField< unique_index, word_t > operator ^ ( bool, SafeBitField< unique_index, word_t > rhs ) +{ + Forbidden_conversion< word_t > wrong; + return rhs; +} + +template < unsigned int unique_index, typename word_t > +inline SafeBitField< unique_index, word_t > operator == ( bool, SafeBitField< unique_index, word_t > rhs ) +{ + Forbidden_conversion< word_t > wrong; + return rhs; +} + +template < unsigned int unique_index, typename word_t > +inline SafeBitField< unique_index, word_t > operator != ( bool, SafeBitField< unique_index, word_t > rhs ) +{ + Forbidden_conversion< word_t > wrong; + return rhs; +} + +// Finally, few macros. All macros are conditionally defined to use the SafeBitField classes if LOKI_SAFE_BIT_FIELD is defined. Otherwise, +// the macros fall back on the use of typedefs and integer constants. This provides no addititonal safety but allows the code to support the +// mixture of compilers which are broken to different degrees. +#define LOKI_SAFE_BIT_FIELD + +// The first macro helps to declare new bit field types: +// LOKI_BIT_FIELD( ulong ) field_t; +// This creates a typedef field_t for SafeBitField<unique_index, ulong> where index is the current line number. Since line numbers __LINE__ are counted +// separately for all header files, this ends up being the same type in all files using the header which defines field_t. +#ifdef LOKI_SAFE_BIT_FIELD + #define LOKI_BIT_FIELD( word_t ) typedef SafeBitField<__LINE__, word_t> +#else + #define LOKI_BIT_FIELD( word_t ) typedef word_t +#endif // LOKI_SAFE_BIT_FIELD + +// The second macro helps to declare static bit constants: +// LOKI_BIT_CONST( field_t, Label_1, 1 ); +// creates new bit field object named Label_1 of type field_t which represents the field with the 1st (junior) bit set. +#ifdef LOKI_SAFE_BIT_FIELD + #ifndef LOKI_BIT_FIELD_NONTEMPLATE_INIT + #define LOKI_BIT_CONST( field_t, label, bit_index ) \ + static const field_t::const_t label = field_t::const_t::make_bit_const<bit_index>() + #else + #define LOKI_BIT_CONST( field_t, label, bit_index ) \ + static const field_t::const_t label = field_t::const_t::make_bit_const( bit_index ) + #endif // LOKI_BIT_FIELD_NONTEMPLATE_INIT +#else + inline size_t make_bit_const( size_t i ) { return ( i > 0 ) ? ( size_t(1) << ( ( i > 0 ) ? ( i - 1 ) : 0 ) ) : 0; } + #define LOKI_BIT_CONST( field_t, label, bit_index ) static const field_t label = make_bit_const( bit_index ) +#endif // LOKI_SAFE_BIT_FIELD + +// The third macro helps to declare complex bit constants which are combination of several bits: +// LOKI_BIT_CONSTS( field_t, Label12 ) = Label_1 | Label_2; +#ifdef LOKI_SAFE_BIT_FIELD + #define LOKI_BIT_CONSTS( field_t, label ) static const field_t::const_t label +#else + #define LOKI_BIT_CONSTS( field_t, label ) static const field_t label +#endif // LOKI_SAFE_BIT_FIELD + +// The fourth macro helps to declare the maximum number of bit constants for a given type: +// static const size_t count = LOKI_BIT_FIELD_COUNT( field_t ); +// declared a variable "count" initialized to field_t::size() +#ifdef LOKI_SAFE_BIT_FIELD + #define LOKI_BIT_FIELD_COUNT( field_t ) field_t::size() +#else + #define LOKI_BIT_FIELD_COUNT( field_t ) ( 8 * sizeof(field_t) ) +#endif // LOKI_SAFE_BIT_FIELD + +} // namespace Loki + +#endif // LOKI_INCLUDED_SAFE_BIT_FIELDS_H |