2009-01-20 07:15:18 +00:00
////////////////////////////////////////////////////////////////////////////////
// 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.
//
2011-09-23 00:46:21 +00:00
// Code covered by the MIT License
2009-01-20 07:15:18 +00:00
//
2011-09-23 00:46:21 +00:00
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
2009-01-20 07:15:18 +00:00
////////////////////////////////////////////////////////////////////////////////
// $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
{
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
2009-01-29 08:27:39 +00:00
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
2009-01-20 07:15:18 +00:00
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
2009-01-29 08:27:39 +00:00
SafeBitField is a drop - in replacement which generates a unique type for each bit field . Bit fields of different types cannot be applied
2009-01-20 07:15:18 +00:00
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
2009-01-29 08:27:39 +00:00
> class SafeBitField ;
2009-01-20 07:15:18 +00:00
////////////////////////////////////////////////////////////////////////////////
2009-01-29 08:27:39 +00:00
/// \class SafeBitConst Bit constants.
2009-01-20 07:15:18 +00:00
/// 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
2009-01-29 08:27:39 +00:00
/// bit-field. It shares the unique_index with a similar SafeBitField.
2009-01-20 07:15:18 +00:00
/// - 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
>
2009-01-29 08:27:39 +00:00
class SafeBitConst
2009-01-20 07:15:18 +00:00
{
public :
/// Type of the bit field is available if needed.
typedef word_t bit_word_t ;
/// Corresponding field type.
2009-01-29 08:27:39 +00:00
typedef SafeBitField < unique_index , word_t > field_t ;
2009-01-20 07:15:18 +00:00
/// Typedef is not allowed in friendship declaration.
2009-01-29 08:27:39 +00:00
friend class SafeBitField < unique_index , word_t > ;
2009-01-20 07:15:18 +00:00
// 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.
2009-01-29 08:27:39 +00:00
// This assert could go into the constructor, but aCC does not seem to understand sizeof(SafeBitConst) in the constructor.
2009-01-20 07:15:18 +00:00
//
# ifndef LOKI_BIT_FIELD_NONTEMPLATE_INIT
2009-01-29 08:27:39 +00:00
template < unsigned int i > static SafeBitConst make_bit_const ( )
2009-01-20 07:15:18 +00:00
{
2009-01-29 08:27:39 +00:00
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 ) ;
2009-01-20 07:15:18 +00:00
// 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.
2009-01-29 08:27:39 +00:00
return SafeBitConst ( ( i > 0 ) ? ( word_t ( 1 ) < < ( ( i > 0 ) ? ( i - 1 ) : 0 ) ) : 0 ) ;
2009-01-20 07:15:18 +00:00
}
# else
2009-01-29 08:27:39 +00:00
static SafeBitConst make_bit_const ( unsigned int i )
2009-01-20 07:15:18 +00:00
{
2009-01-29 08:27:39 +00:00
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.
2009-01-20 07:15:18 +00:00
// 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.
2009-01-29 08:27:39 +00:00
return SafeBitConst ( ( i > 0 ) ? ( word_t ( 1 ) < < ( ( i > 0 ) ? ( i - 1 ) : 0 ) ) : 0 ) ;
2009-01-20 07:15:18 +00:00
}
# endif
/// Default constructor allows client code to construct bit fields on the stack.
2009-01-29 08:27:39 +00:00
SafeBitConst ( ) : word ( 0 ) { }
2009-01-20 07:15:18 +00:00
/// Copy constructor.
2009-01-29 08:27:39 +00:00
SafeBitConst ( const SafeBitConst & rhs ) : word ( rhs . word ) { }
2009-01-20 07:15:18 +00:00
/// Comparison operators which take a constant bit value.
2009-01-29 08:27:39 +00:00
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 ; }
2009-01-20 07:15:18 +00:00
/// 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.
2009-01-29 08:27:39 +00:00
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 ) ; }
2009-01-20 07:15:18 +00:00
/// 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.
2009-01-29 08:27:39 +00:00
const SafeBitConst operator < < ( unsigned int s ) const { return SafeBitConst ( word < < s ) ; }
const SafeBitConst operator > > ( unsigned int s ) const { return SafeBitConst ( word > > s ) ; }
2009-01-20 07:15:18 +00:00
/// Word size is also the maximum number of different bit fields for a given word type.
2009-01-29 08:27:39 +00:00
static size_t size ( ) { return ( 8 * sizeof ( word_t ) ) ; }
2009-01-20 07:15:18 +00:00
private :
/// Copy-assignment operator is not implemented since it does not make sense
/// for a constant object.
2009-01-29 08:27:39 +00:00
SafeBitConst operator = ( const SafeBitConst & rhs ) ;
2009-01-20 07:15:18 +00:00
// Private constructor from an integer type.
2009-01-29 08:27:39 +00:00
explicit SafeBitConst ( word_t init ) : word ( init ) { }
2009-01-20 07:15:18 +00:00
/// 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:
2009-01-29 08:27:39 +00:00
// SafeBitField<1> label1;
// SafeBitField<2> label2;
2009-01-20 07:15:18 +00:00
// if ( label1 & label2 ) { ... }
// These operators are private, and will not instantiate in any
// event because of the incomplete Forbidden_conversion struct.
2011-09-07 20:04:38 +00:00
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 ; }
2009-01-20 07:15:18 +00:00
// 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 ; }
} ;
////////////////////////////////////////////////////////////////////////////////
2009-01-29 08:27:39 +00:00
/// \class SafeBitConst Bit constants.
2009-01-20 07:15:18 +00:00
/// 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
2009-01-29 08:27:39 +00:00
/// bit-field. It shares the unique_index with a similar SafeBitConst.
2009-01-20 07:15:18 +00:00
/// - Its operations only allow comparisons to other bit-constants and
/// bit-fields of the same type.
////////////////////////////////////////////////////////////////////////////////
template
<
unsigned int unique_index ,
typename word_t
>
2009-01-29 08:27:39 +00:00
class SafeBitField
2009-01-20 07:15:18 +00:00
{
public :
/// Type of the bit field is available if needed.
typedef word_t bit_word_t ;
/// Corresponding field type.
2009-01-29 08:27:39 +00:00
typedef SafeBitConst < unique_index , word_t > const_t ;
2009-01-20 07:15:18 +00:00
/// Typedef is not allowed in friendship declaration.
2009-01-29 08:27:39 +00:00
friend class SafeBitConst < unique_index , word_t > ;
2009-01-20 07:15:18 +00:00
/// Default constructor allows client code to construct bit fields on the stack.
2009-01-29 08:27:39 +00:00
SafeBitField ( ) : word ( 0 ) { }
2009-01-20 07:15:18 +00:00
/// Copy constructor and assignment operators.
2009-01-29 08:27:39 +00:00
SafeBitField ( const SafeBitField & rhs ) : word ( rhs . word ) { }
SafeBitField & operator = ( const SafeBitField & rhs ) { word = rhs . word ; return * this ; }
2009-01-20 07:15:18 +00:00
/// Copy constructor and assignment operators from constant bit fields.
2009-01-29 08:27:39 +00:00
SafeBitField ( const const_t & rhs ) : word ( rhs . word ) { }
SafeBitField & operator = ( const const_t & rhs ) { word = rhs . word ; return * this ; }
2009-01-20 07:15:18 +00:00
/// These comparison operators act on bit-fields of the same type.
2009-01-29 08:27:39 +00:00
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 ; }
2009-01-20 07:15:18 +00:00
/// 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.
2009-01-29 08:27:39 +00:00
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 ) ; }
2011-09-07 20:04:38 +00:00
SafeBitField & operator | = ( const SafeBitField & rhs ) { word | = rhs . word ; return * this ; }
SafeBitField & operator & = ( const SafeBitField & rhs ) { word & = rhs . word ; return * this ; }
SafeBitField & operator ^ = ( const SafeBitField & rhs ) { word ^ = rhs . word ; return * this ; }
2009-01-20 07:15:18 +00:00
/// Bitwise operators that use bit-constants.
2009-01-29 08:27:39 +00:00
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 ) ; }
2011-09-07 20:04:38 +00:00
SafeBitField & operator | = ( const_t rhs ) { word | = rhs . word ; return * this ; }
SafeBitField & operator & = ( const_t rhs ) { word & = rhs . word ; return * this ; }
SafeBitField & operator ^ = ( const_t rhs ) { word ^ = rhs . word ; return * this ; }
2009-01-20 07:15:18 +00:00
// Conversion to bool.
// This is a major source of headaches, but it's required to support code like this:
2009-01-29 08:27:39 +00:00
// const static SafeBitConst<1> Label_value = SafeBitConst<1>::make_bit_const<1>();
// SafeBitField<1> label;
2009-01-20 07:15:18 +00:00
// 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:
2009-01-29 08:27:39 +00:00
// SafeBitField<1> label1;
// SafeBitField<2> label2;
2009-01-20 07:15:18 +00:00
// 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.
//
2011-09-07 20:04:38 +00:00
operator bool ( ) const { return ( 0 ! = word ) ; }
2009-01-20 07:15:18 +00:00
// 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.
2009-01-29 08:27:39 +00:00
SafeBitField operator < < ( unsigned int s ) { return SafeBitField ( word < < s ) ; }
SafeBitField operator > > ( unsigned int s ) { return SafeBitField ( word > > s ) ; }
2011-09-07 20:04:38 +00:00
SafeBitField & operator < < = ( unsigned int s ) { word < < = s ; return * this ; }
SafeBitField & operator > > = ( unsigned int s ) { word > > = s ; return * this ; }
2009-01-20 07:15:18 +00:00
// Word size is also the maximum number of different bit fields for
// a given word type.
2009-01-29 08:27:39 +00:00
static size_t size ( void ) { return ( 8 * sizeof ( word_t ) ) ; }
2009-01-20 07:15:18 +00:00
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
2009-01-29 08:27:39 +00:00
/// problems with undesired conversions because SafeBitField coverts to bool.
explicit SafeBitField ( word_t init ) : word ( init ) { }
2009-01-20 07:15:18 +00:00
/// 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:
2009-01-29 08:27:39 +00:00
// SafeBitField<1> label1;
// SafeBitField<2> label2;
2009-01-20 07:15:18 +00:00
// if ( label1 & label2 ) { ... }
// These operators are private, and will not instantiate in any
// event because of the incomplete Forbidden_conversion struct.
2011-09-07 20:04:38 +00:00
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 ; }
2009-01-20 07:15:18 +00:00
// 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:
2009-01-29 08:27:39 +00:00
// SafeBitField<1> label1;
// SafeBitField<2> label2;
2009-01-20 07:15:18 +00:00
// if ( !label1 & label2 ) { ... }
// where the first label is converted to bool (these errors cannot be
2009-01-29 08:27:39 +00:00
// caught by member operators of SafeBitField class because the first
// argument is not SafeBitField but bool.
2009-01-20 07:15:18 +00:00
//
// If used, these operators will not instantiate because of the
// incomplete Forbidden_conversion struct.
template < unsigned int unique_index , typename word_t >
2009-01-29 08:27:39 +00:00
inline SafeBitField < unique_index , word_t > operator & ( bool , SafeBitField < unique_index , word_t > rhs )
2009-01-20 07:15:18 +00:00
{
Forbidden_conversion < word_t > wrong ;
return rhs ;
}
template < unsigned int unique_index , typename word_t >
2009-01-29 08:27:39 +00:00
inline SafeBitField < unique_index , word_t > operator | ( bool , SafeBitField < unique_index , word_t > rhs )
2009-01-20 07:15:18 +00:00
{
Forbidden_conversion < word_t > wrong ;
return rhs ;
}
template < unsigned int unique_index , typename word_t >
2009-01-29 08:27:39 +00:00
inline SafeBitField < unique_index , word_t > operator ^ ( bool , SafeBitField < unique_index , word_t > rhs )
2009-01-20 07:15:18 +00:00
{
Forbidden_conversion < word_t > wrong ;
return rhs ;
}
template < unsigned int unique_index , typename word_t >
2009-01-29 08:27:39 +00:00
inline SafeBitField < unique_index , word_t > operator = = ( bool , SafeBitField < unique_index , word_t > rhs )
2009-01-20 07:15:18 +00:00
{
Forbidden_conversion < word_t > wrong ;
return rhs ;
}
template < unsigned int unique_index , typename word_t >
2009-01-29 08:27:39 +00:00
inline SafeBitField < unique_index , word_t > operator ! = ( bool , SafeBitField < unique_index , word_t > rhs )
2009-01-20 07:15:18 +00:00
{
Forbidden_conversion < word_t > wrong ;
return rhs ;
}
2009-01-29 08:27:39 +00:00
// Finally, few macros. All macros are conditionally defined to use the SafeBitField classes if LOKI_SAFE_BIT_FIELD is defined. Otherwise,
2009-01-20 07:15:18 +00:00
// 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;
2009-01-29 08:27:39 +00:00
// This creates a typedef field_t for SafeBitField<unique_index, ulong> where index is the current line number. Since line numbers __LINE__ are counted
2009-01-20 07:15:18 +00:00
// 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
2011-09-06 23:56:29 +00:00
# ifdef __COUNTER__
# define LOKI_BIT_FIELD( word_t ) typedef ::Loki::SafeBitField<__COUNTER__, word_t>
# else
# define LOKI_BIT_FIELD( word_t ) typedef ::Loki::SafeBitField<__LINE__, word_t>
# endif
2009-01-20 07:15:18 +00:00
# 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