////////////////////////////////////////////////////////////////////////
/// \class RAT::DS::BitMask
///
/// \brief A dynamic bit mask.
///
/// \author Phil G Jones
///
/// REVISION HISTORY:\n
/// 2014-04-04: P G Jones - New file
///
/// \details A dynamic bit mask made of multiple (by default 1) ULong64_t
/// types. Each ULong64_t is referred to as an element. Any operation on
/// the BitMask involving another BitMask (comparisons/bit operations)
/// includes padding the BitMask with 0x0 such that the number of elements
/// is equivalent in both. In practice instances of this object can be
/// used as one would with a integer bit mask.
///
////////////////////////////////////////////////////////////////////////
#ifndef __RAT_DS_BitMask__
#define __RAT_DS_BitMask__
#include
#include
#include
#include
#include
#include
namespace RAT
{
namespace DS
{
class BitMask : public TObject
{
public:
/// Generic constructor, start with 1 element in the flags
BitMask() : TObject() { flags.resize( 1, 0 ); }
/// Create a BitMask using a ULong64_t value i.e. a int
inline BitMask( const ULong64_t value );
/// Set a bit in the mask at index to value
///
/// @param[in] index of the bit to set
/// @param[in] value to set it to
inline void Set( size_t index, const Bool_t value = true );
/// Get the value of the bit at index in the mask
///
/// @param[in] index of the bit to get
/// @return the value of the bit
inline Bool_t Get( size_t index ) const;
/// Get the values of the bits at index to index + length
///
/// The result is shifted such that the index bit is at 0 in the result
///
/// @param[in] index of the bits to return
/// @param[in] length of the bits after index to return
/// @return the bits from index to index + length shifted s.t. index is at 0 in the result
inline ULong64_t GetBits( const size_t index, const size_t length ) const;
/// Get a ULong64_t from this BitMask
///
/// If the startIndex is such that this BitMask has no data in the bits
/// [index, index+64) then 0x0 is returned. Additionally any bits not defined
/// in this mask will be set to false/0.
///
/// @param[in] startIndex of the 64 bit word i.e. a value of 1 asks to return bits [64, 127]
/// @return a ULong64_t with filled with the relevant set bits in this mask
inline ULong64_t GetULong64_t( const size_t startIndex ) const;
/// Convert to a string for easy output
///
/// @return a string representation in hex
inline std::string ToString() const;
/// one's complement operator, switches every 1 bit to a 0 bit and vice versa
///
/// @return reference to this
inline BitMask& operator~();
/// Bitwise AND operator
///
/// this or rhs are padded with 0x0 elements till the number of elements match
///
/// @param[in] rhs to AND this with
/// @return the result of this & rhs
inline BitMask operator&( const BitMask& rhs ) const;
/// Bitwise AND operator, store result in this
///
/// this or rhs are padded with 0x0 elements till the number of elements match
///
/// @param[in] rhs to AND this with
/// @return reference to this
inline BitMask& operator&=( const BitMask& rhs );
/// Bitwise OR operator
///
/// this or rhs are padded with 0x0 elements till the number of elements match
///
/// @param[in] rhs to OR this with
/// @return the result of this | rhs
inline BitMask operator|( const BitMask& rhs ) const;
/// Bitwise OR operator, store result in this
///
/// this or rhs are padded with 0x0 elements till the number of elements match
///
/// @param[in] rhs to OR this with
/// @return reference to this
inline BitMask& operator|=( const BitMask& rhs );
/// Bitwise XOR/EOR operator
///
/// this or rhs are padded with 0x0 elements till the number of elements match
///
/// @param[in] rhs to XOR/EOR this with
/// @return the result of this ^ rhs
inline BitMask operator^( const BitMask& rhs ) const;
/// Bitwise XOR/EOR operator, store result in this
///
/// this or rhs are padded with 0x0 elements till the number of elements match
///
/// @param[in] rhs to XOR/EOR this with
/// @return reference to this
inline BitMask& operator^=( const BitMask& rhs );
/// Comparison operator
///
/// this or rhs are padded with 0x0 elements till the number of elements match
///
/// @param[in] rhs to compare this against
/// @return true if this and rhs have the same bits set
inline Bool_t operator==( const BitMask& rhs ) const;
/// Not comparison operator
///
/// this or rhs are padded with 0x0 elements till the number of elements match
///
/// @param[in] rhs to compare this against
/// @return true if this and rhs do not have the same bits set
inline Bool_t operator!=( const BitMask& rhs ) const;
/// Cast to bool operator
///
/// @return true if any element is not equal to 0x0, i.e. if any bit is set
inline operator Bool_t() const;
// This ROOT macro adds dictionary methods to this class.
// The number should be incremented whenever this class's members are changed.
// It assumes this class has no virtual methods, use ClassDef if change this.
ClassDefNV( BitMask, 1 );
protected:
std::vector flags;
};
BitMask::BitMask( const ULong64_t value )
: TObject()
{
flags.resize( 1, 0 );
flags[0] = value;
}
inline void
BitMask::Set( size_t index, const Bool_t value )
{
const size_t element = index / ( sizeof( ULong64_t ) * CHAR_BIT );
if( index >= flags.size() * sizeof( ULong64_t ) * CHAR_BIT )
flags.resize( element + 1, 0 );
index -= element * sizeof( ULong64_t ) * CHAR_BIT; // Index is now the bit in ULong64_t element
if( value )
flags[element] |= ( (ULong64_t)0x1 << index );
else
flags[element] &= ~( (ULong64_t)0x1 << index );
}
inline Bool_t
BitMask::Get( size_t index ) const
{
const size_t element = index / ( sizeof( ULong64_t ) * CHAR_BIT );
if( index >= flags.size() * sizeof( ULong64_t ) * CHAR_BIT )
return false;
index -= element * sizeof( ULong64_t ) * CHAR_BIT;// Index is now the bit in ULong64_t element
return static_cast( flags[element] & ( (ULong64_t)0x1 << index ) );
}
inline ULong64_t
BitMask::GetBits( const size_t start, const size_t length ) const
{
ULong64_t result = 0;
for( size_t index = start; index < start + length; index++ )
{
if( Get( index ) )
result |= ( (ULong64_t)0x1 << ( index - start ) );
}
return result;
}
inline ULong64_t
BitMask::GetULong64_t( const size_t startIndex ) const
{
ULong64_t result = 0x0;
for( size_t index = 0; index < sizeof( ULong64_t ) * CHAR_BIT; index++ )
if( Get( index + startIndex * sizeof( ULong64_t ) * CHAR_BIT ) )
result |= ((ULong64_t)0x1 << index);
return result;
}
inline std::string
BitMask::ToString() const
{
std::stringstream result;
result << "0x" << std::hex;
for( std::vector::const_reverse_iterator iTer = flags.rbegin(); iTer != flags.rend(); iTer++ )
result << *iTer;
return result.str();
}
inline BitMask &
BitMask::operator~()
{
for( size_t element = 0; element < flags.size(); element++ )
flags[element] = ~flags[element];
return *this;
}
inline BitMask
BitMask::operator&( const BitMask& rhs ) const
{
BitMask result;
for( size_t element = 0; element < std::max( flags.size(), rhs.flags.size() ); element++ )
{
const ULong64_t left = element < flags.size() ? flags.at( element ) : 0x0;
const ULong64_t right = element < rhs.flags.size() ? rhs.flags.at( element ) : 0x0;
result.flags.push_back( left & right );
}
return result;
}
inline BitMask&
BitMask::operator&=( const BitMask& rhs )
{
*this = *this & rhs;
return *this;
}
inline BitMask
BitMask::operator|( const BitMask& rhs ) const
{
BitMask result;
for( size_t element = 0; element < std::max( flags.size(), rhs.flags.size() ); element++ )
{
const ULong64_t left = element < flags.size() ? flags.at( element ) : 0x0;
const ULong64_t right = element < rhs.flags.size() ? rhs.flags.at( element ) : 0x0;
result.flags.push_back( left | right );
}
return result;
}
inline BitMask&
BitMask::operator|=( const BitMask& rhs )
{
*this = *this | rhs;
return *this;
}
inline BitMask
BitMask::operator^( const BitMask& rhs ) const
{
BitMask result;
for( size_t element = 0; element < std::max( flags.size(), rhs.flags.size() ); element++ )
{
const ULong64_t left = element < flags.size() ? flags.at( element ) : 0x0;
const ULong64_t right = element < rhs.flags.size() ? rhs.flags.at( element ) : 0x0;
result.flags.push_back( left ^ right );
}
return result;
}
inline BitMask&
BitMask::operator^=( const BitMask& rhs )
{
*this = *this ^ rhs;
return *this;
}
inline Bool_t
BitMask::operator==( const BitMask& rhs ) const
{
for( size_t element = 0; element < std::max( flags.size(), rhs.flags.size() ); element++ )
{
const ULong64_t left = element < flags.size() ? flags.at( element ) : 0x0;
const ULong64_t right = element < rhs.flags.size() ? rhs.flags.at( element ) : 0x0;
if( left != right )
return false;
}
return true;
}
inline Bool_t
BitMask::operator!=( const BitMask& rhs ) const
{
return !(*this == rhs);
}
inline
BitMask::operator Bool_t() const
{
for( size_t element = 0; element < flags.size(); element++ )
if( flags.at( element ) != 0 )
return true;
return false;
}
} // namespace DS
} // namespace RAT
#endif