diff --git a/doc/integer_mask.html b/doc/integer_mask.html index 5bc7301..6dba489 100644 --- a/doc/integer_mask.html +++ b/doc/integer_mask.html @@ -8,7 +8,11 @@

boost.png (6897 bytes)Integer Bit Mask Templates

-

The class templates in <boost/integer/integer_mask.hpp> provide bit masks for a certain bit position or a contiguous-bit pack of a certain size. The types of the masking constants come from the integer type selection templates header.

+

The class templates in <boost/integer/integer_mask.hpp> +provide bit masks for a certain bit position or a contiguous-bit pack of a +certain size. The types of the masking constants come from the integer type selection templates header.

Contents

@@ -17,6 +21,7 @@ align="middle" width="277" height="86">Integer Bit Mask Templates
  • Synopsis
  • Single Bit-Mask Class Template
  • Group Bit-Mask Class Template
  • +
  • MPL-Compatible Variants
  • Example
  • Demonstration Program
  • Rationale
  • @@ -26,39 +31,68 @@ align="middle" width="277" height="86">Integer Bit Mask Templates

    Synopsis

    -#include <cstddef>  // for std::size_t
    +#include <boost/integer_fwd.hpp>  // forwarding header
    +#include <boost/integer.hpp>      // for boost::int_fast_t
    +#include <cstddef>                // for std::size_t
     
     namespace boost
     {
     
    -template < std::size_t Bit >
    -struct high_bit_mask_t
    +// MPL-compatible
    +template < int Offset >
    +struct integer_hi_mask
     {
    -    typedef implementation_supplied  least;
    -    typedef implementation_supplied   fast;
    +    static  bool const  is_specialized = implementation_supplied;
    +    static  int const   bit_offset = Offset;
     
    -    static const least  high_bit = implementation_defined;
    -    static const fast   high_bit_fast = implementation_defined;
    +    typedef implementation_supplied  type;
    +    typedef implementation_supplied  value_type;
    +    static  value_type const  value = implementation_supplied;
    +    // There are other (optional) operations....
    +};
    +
    +template < int Length >
    +struct integer_lo_mask
    +{
    +    static  bool const  is_specialized = implementation_supplied;
    +    static  int const   bit_count = Length;
    +
    +    typedef implementation_supplied  type;
    +    typedef implementation_supplied  value_type;
    +    static  value_type const  value = implementation_supplied;
    +    // There are other (optional) operations....
    +};
    +
    +// single
    +template < std::size_t Bit >
    +class high_bit_mask_t
    +{
    +public:
    +    typedef typename integer_hi_mask<Bit>::value_type  least;
    +    typedef int_fast_t<least>::fast                     fast;
    +
    +    static const least  high_bit = integer_hi_mask<Bit>::value;
    +    static const fast   high_bit_fast = high_bit;
     
         static const std::size_t  bit_position = Bit;
     
     };
     
    +// group
     template < std::size_t Bits >
    -struct low_bits_mask_t
    +class low_bits_mask_t
     {
    -    typedef implementation_supplied  least;
    -    typedef implementation_supplied   fast;
    +public:
    +    typedef typename integer_lo_mask<Bits>::value_type  least;
    +    typedef int_fast_t<least>::fast                      fast;
     
    -    static const least  sig_bits = implementation_defined;
    -    static const fast   sig_bits_fast = implementation_defined;
    +    static const least  sig_bits = integer_lo_mask<Bits>::value;
    +    static const fast   sig_bits_fast = sig_bits;
     
         static const std::size_t  bit_count = Bits;
     
     };
     
    -// Specializations for low_bits_mask_t exist for certain bit counts.
    -
     }  // namespace boost
     
    @@ -149,16 +183,149 @@ describes the members of an instantiation of -

    Implementation Note
    -When Bits is the exact size of a built-in unsigned type, -the implementation has to change to prevent undefined behavior. -Therefore, there are specializations of low_bits_mask_t at -those bit counts.

    +

    MPL-Compatible Variants

    + +

    The single and group bit-mask class templates have several drawbacks:

    + + + +

    The integer_hi_mask and integer_lo_mask class +templates provide MPL-compatible alternatives. These alternatives have the +form:

    + +
    +template< int Size >
    +struct name
    +{
    +    static  bool const  is_specialized = implementation_supplied;
    +    static  int const   switch_id = Size;
    +
    +    typedef implementation_supplied  type;
    +    typedef implementation_supplied  value_type;
    +    static  value_type const  value = implementation_supplied;
    +    // with other operations...
    +};
    +
    + +

    Only some of the members are always present. The presence of other members +and operations is flagged by the (always-present) is_specialized.

    + + + + + + + + + + + + + + + +
    Permanent Members of the MPL-Compatible Masking Class Template + Types
    Class Template MemberMeaning
    is_specializedFlag indicating when a particular template class instantiation is a + valid meta-function (true) or not (false).
    switch_id (Actual name is template-specific.)The value of the main control parameter, accessible even if the + template class instantiation is aliased.
    + +

    The optional members are based from inheriting from a MPL-style Integral +Constant type, but only if is_specialized is true.

    + + + + + + + + + + + + + + + + + + + +
    Optional Members of the MPL-Compatible Masking Types
    Class Template MemberMeaning
    valueThe actual bit mask.
    value_typeThe type of the bit mask value.
    typeThe Integral Constant implementation type, which should be + boost::mpl:: + integral_c< value_type, value + >.
    + +

    The Integral Constant prototype also adds the following operations:

    + + + + + + + + + + + + + + + + + + + +
    Optional Operations of the MPL-Compatible Masking Types
    Operation (with n as a masking type)Meaning
    boost::mpl::next< n >::typeboost::mpl::next< n::type >::type, i.e. + boost::mpl::integral_c< n::value_type, n::value + 1 + >.
    boost::mpl::prior< n >::typeboost::mpl::prior< n::type >::type, i.e. + boost::mpl::integral_c< n::value_type, n::value - 1 + >.
    n::value_type const c = n();c is set to n::value.
    + +

    The specifics for each masking class template are:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Criteria for the MPL-Compatible Masking Types
    + (Everything besides the parameter ID is in name-space + boost except where indicated.)
    Class TemplateParameter Member IDClassic EquivalentValue TypeValueValid Range
    integer_hi_maskbit_offsethigh_bit_mask_tsized_integral < bit_offset + 1, unsigned >2bit_offset0 <= bit_offset < std::numeric_limits< uintmax_t >::digits
    integer_lo_maskbit_countlow_bits_mask_tsized_integral < bit_count, unsigned >2bit_offset - 10 <= bit_count <= std::numeric_limits< uintmax_t >::digits

    Example

    -#include <boost/integer/integer_mask.hpp>
    +#include <boost/integer/integer_mask.hpp>
     
     //...
     
    @@ -200,7 +367,7 @@ href="http://www.boost.org/people/daryle_walker.html">Daryle Walker.


    -

    Revised September 23, 2001

    +

    Revised July 29, 2008

    © Copyright Daryle Walker 2001. Use, modification, and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file // self include -#include // for BOOST_STATIC_CONSTANT -#include // for boost::uint_t +#include // for BOOST_STATIC_CONSTANT +#include // for boost::uintmax_t +#include // for boost::sized_integral +#include // for std::numeric_limits +#include // for boost::mpl::and_ +#include // for boost::mpl::bitor_, shift_left +#include // for boost::mpl::true_ +#include // for boost::mpl::greater_equal, etc. +#include // for boost::mpl::empty_base +#include // for boost::mpl::if_ +#include // for boost::mpl::int_ +#include // for boost::integral_c +#include // for boost::mpl::next, prior +#include // for boost::enable_if -#include // for BOOST_HAS_XINT, etc. - -#include // for UCHAR_MAX, etc. #include // for std::size_t -#include // for std::numeric_limits - namespace boost { +namespace detail +{ + +// Helper templates --------------------------------------------------------// + +template < int Bits > +struct hi_integer_mask_builder1 +{ + typedef boost::mpl::int_ bit_count_type; + + typedef typename boost::mpl::next::type + mask_length_type; + typedef boost::sized_integral + mask_type; + + typedef boost::mpl::integral_c one_type; + typedef boost::mpl::shift_left result_type; +}; + +template < int Bits > +struct hi_integer_mask_builder2 +{ + typedef boost::mpl::int_ bit_count_type; + + typedef boost::mpl::greater_equal< bit_count_type, boost::mpl::int_<0> > + lo_bound_type; + typedef boost::mpl::less< bit_count_type, + boost::mpl::int_::digits> > + hi_bound_type; + typedef boost::mpl::and_ count_valid_type; +}; + +template < int Bits, class Enable = void > +struct hi_integer_mask_builder3 +{ + BOOST_STATIC_CONSTANT( bool, is_specialized = false ); +}; + +template < int Bits > +struct hi_integer_mask_builder3< Bits, typename boost::enable_if::count_valid_type>::type > + : hi_integer_mask_builder1::result_type +{ + BOOST_STATIC_CONSTANT( bool, is_specialized = true ); +}; + +template < int Bits > +struct lo_integer_mask_builder1 +{ + typedef boost::mpl::int_ bit_count_type; + + typedef typename boost::mpl::prior::type + shift_length_type; + typedef boost::sized_integral + mask_type; + + typedef boost::mpl::integral_c one_type; + typedef boost::mpl::shift_left + high_bit_type; + typedef typename boost::mpl::prior::type low_bits_type; + typedef boost::mpl::bitor_ result_type; +}; + +template < > +struct lo_integer_mask_builder1< 0 > +{ + // Let's not deal with negative interim values.... + typedef boost::mpl::integral_c result_type; +}; + +template < int Bits > +struct lo_integer_mask_builder2 +{ + typedef boost::mpl::int_ bit_count_type; + + typedef boost::mpl::greater_equal< bit_count_type, boost::mpl::int_<0> > + lo_bound_type; + typedef boost::mpl::less_equal< bit_count_type, + boost::mpl::int_::digits> > + hi_bound_type; + typedef boost::mpl::and_ count_valid_type; +}; + +template < > +struct lo_integer_mask_builder2< 0 > +{ + typedef boost::mpl::true_ count_valid_type; +}; + +template < int Bits, class Enable = void > +struct lo_integer_mask_builder3 +{ + BOOST_STATIC_CONSTANT( bool, is_specialized = false ); + // No MPL Integral Constant to inherit from +}; + +template < int Bits > +struct lo_integer_mask_builder3< Bits, typename enable_if::count_valid_type>::type > + : lo_integer_mask_builder1::result_type +{ + BOOST_STATIC_CONSTANT( bool, is_specialized = true ); +}; + +} // namespace detail + + +// MPL-compatible integer mask class templates -----------------------------// + +// Displaced single-bit mask, 1 << Offset, 0 <= Offset < BitLengthOf(uintmax_t) +template < int Offset > +struct integer_hi_mask + : detail::hi_integer_mask_builder3 +{ + BOOST_STATIC_CONSTANT( int, bit_offset = Offset ); +}; + +// Lowest bit-group mask, 2**Length - 1, 0 <= Length <= BitLengthOf(uintmax_t) +template < int Length > +struct integer_lo_mask + : detail::lo_integer_mask_builder3 +{ + BOOST_STATIC_CONSTANT( int, bit_count = Length ); +}; // Specified single-bit mask class declaration -----------------------------// // (Lowest bit starts counting at 0.) template < std::size_t Bit > -struct high_bit_mask_t +class high_bit_mask_t { - typedef typename uint_t<(Bit + 1)>::least least; - typedef typename uint_t<(Bit + 1)>::fast fast; + typedef integer_hi_mask impl_type; - BOOST_STATIC_CONSTANT( least, high_bit = (least( 1u ) << Bit) ); - BOOST_STATIC_CONSTANT( fast, high_bit_fast = (fast( 1u ) << Bit) ); +public: + typedef typename impl_type::value_type least; + typedef typename int_fast_t::fast fast; - BOOST_STATIC_CONSTANT( std::size_t, bit_position = Bit ); + BOOST_STATIC_CONSTANT( least, high_bit = impl_type::value ); + BOOST_STATIC_CONSTANT( fast, high_bit_fast = impl_type::value ); + + BOOST_STATIC_CONSTANT( std::size_t, bit_position = impl_type::bit_offset ); }; // boost::high_bit_mask_t // Specified bit-block mask class declaration ------------------------------// // Makes masks for the lowest N bits -// (Specializations are needed when N fills up a type.) template < std::size_t Bits > -struct low_bits_mask_t +class low_bits_mask_t { - typedef typename uint_t::least least; - typedef typename uint_t::fast fast; + typedef integer_lo_mask impl_type; - BOOST_STATIC_CONSTANT( least, sig_bits = (~( ~(least( 0u )) << Bits )) ); - BOOST_STATIC_CONSTANT( fast, sig_bits_fast = fast(sig_bits) ); +public: + typedef typename impl_type::value_type least; + typedef typename int_fast_t::fast fast; - BOOST_STATIC_CONSTANT( std::size_t, bit_count = Bits ); + BOOST_STATIC_CONSTANT( least, sig_bits = impl_type::value ); + BOOST_STATIC_CONSTANT( fast, sig_bits_fast = impl_type::value ); + + BOOST_STATIC_CONSTANT( std::size_t, bit_count = impl_type::bit_count ); }; // boost::low_bits_mask_t -#define BOOST_LOW_BITS_MASK_SPECIALIZE( Type ) \ - template < > struct low_bits_mask_t< std::numeric_limits::digits > { \ - typedef std::numeric_limits limits_type; \ - typedef uint_t::least least; \ - typedef uint_t::fast fast; \ - BOOST_STATIC_CONSTANT( least, sig_bits = (~( least(0u) )) ); \ - BOOST_STATIC_CONSTANT( fast, sig_bits_fast = fast(sig_bits) ); \ - BOOST_STATIC_CONSTANT( std::size_t, bit_count = limits_type::digits ); \ - } - -BOOST_LOW_BITS_MASK_SPECIALIZE( unsigned char ); - -#if USHRT_MAX > UCHAR_MAX -BOOST_LOW_BITS_MASK_SPECIALIZE( unsigned short ); -#endif - -#if UINT_MAX > USHRT_MAX -BOOST_LOW_BITS_MASK_SPECIALIZE( unsigned int ); -#endif - -#if ULONG_MAX > UINT_MAX -BOOST_LOW_BITS_MASK_SPECIALIZE( unsigned long ); -#endif - -#if BOOST_HAS_XINT && (BOOST_UXINT_MAX > ULONG_MAX) -BOOST_LOW_BITS_MASK_SPECIALIZE( ::boost::detail::uxint_t ); -#endif - -#undef BOOST_LOW_BITS_MASK_SPECIALIZE - - } // namespace boost diff --git a/include/boost/integer_fwd.hpp b/include/boost/integer_fwd.hpp index e15385a..3ece2e3 100644 --- a/include/boost/integer_fwd.hpp +++ b/include/boost/integer_fwd.hpp @@ -9,12 +9,10 @@ #ifndef BOOST_INTEGER_FWD_HPP #define BOOST_INTEGER_FWD_HPP -#include // for UCHAR_MAX, etc. #include // for std::size_t -#include // for BOOST_NO_INTRINSIC_WCHAR_T +#include // for BOOST_NO_INTRINSIC_WCHAR_T, etc. #include // for boost::uintmax_t, intmax_t -#include // for std::numeric_limits #include // for BOOST_HAS_XINT, etc. @@ -131,35 +129,17 @@ template< uintmax_t Value > // From -----------------------------------// +template < int Offset > + struct integer_hi_mask; + +template < int Length > + struct integer_lo_mask; + template < std::size_t Bit > - struct high_bit_mask_t; + class high_bit_mask_t; template < std::size_t Bits > - struct low_bits_mask_t; - -template < > - struct low_bits_mask_t< ::std::numeric_limits::digits >; - -#if USHRT_MAX > UCHAR_MAX -template < > - struct low_bits_mask_t< ::std::numeric_limits::digits >; -#endif - -#if UINT_MAX > USHRT_MAX -template < > - struct low_bits_mask_t< ::std::numeric_limits::digits >; -#endif - -#if ULONG_MAX > UINT_MAX -template < > - struct low_bits_mask_t< ::std::numeric_limits::digits >; -#endif - -#if BOOST_HAS_XINT && (BOOST_UXINT_MAX > ULONG_MAX) -template < > - struct low_bits_mask_t< ::std::numeric_limits< ::boost::detail::uxint_t - >::digits >; -#endif + class low_bits_mask_t; // From ------------------------------------// diff --git a/test/integer_mask_test.cpp b/test/integer_mask_test.cpp index 99a22b0..65b6fc2 100644 --- a/test/integer_mask_test.cpp +++ b/test/integer_mask_test.cpp @@ -8,6 +8,8 @@ // See http://www.boost.org for most recent version including documentation. // Revision History +// 29 Jul 2008 Added MPL-compatible variants of the integer-mask templates. +// (Daryle Walker) // 27 Jul 2008 Changed tests to use the unit-test system; added // extended-integer support. (Daryle Walker) // 23 Sep 2001 Initial version (Daryle Walker) @@ -18,24 +20,72 @@ #include // for boost::uintmax_t #include // for boost::high_bit_mask_t, etc. #include // for std::numeric_limits -#include // for BOOST_MPL_ASSERT_RELATION +#include // for BOOST_MPL_ASSERT_RELATION,etc. +#include // for boost::mpl::bool_ +#include // for boost::mpl::bitor_, shift_left +#include // for boost::mpl::equal_to +#include // for boost::mpl::int_ +#include // for boost::mpl::integral_c +#include // for boost::mpl::prior #include // for boost::mpl::range_c #include // for std::size_t +#include // for std::hex +#include // for std::cout +#include // for std::endl + + +// Control if events will be printed conventionally, or just logged. +#ifndef CONTROL_SHOW_TYPES +#define CONTROL_SHOW_TYPES 0 +#endif + +// Logging +#if CONTROL_SHOW_TYPES +#define PRIVATE_SHOW_MESSAGE( m ) std::cout << m << std::endl +#else +#define PRIVATE_SHOW_MESSAGE( m ) BOOST_TEST_MESSAGE( m ) +#endif // Custom types/templates, helper functions, and objects namespace { -// A big one -boost::uintmax_t const one = 1u; - // List the ranges of template parameters tests (ranges are half-open) int const max_offset = std::numeric_limits::digits; -typedef boost::mpl::range_c high_bit_offsets; -typedef boost::mpl::range_c low_bit_lengths; +typedef boost::mpl::range_c high_bit_offsets; +typedef boost::mpl::range_c low_bit_lengths; +typedef boost::mpl::range_c special_low_bit_lengths; + +// List a range with out-of-service values +typedef boost::mpl::range_c wild_bit_lengths; + +// Use SFINAE to check if a particular parameter is supported +template < typename ValueT, template class Tmpl, ValueT Value > +bool +print_out_template( Tmpl const &, ValueT setting, char const + *template_name, typename Tmpl::type *unused = 0 ) +{ + // Too bad the type-id expression couldn't use the compact form "*unused", + // but type-ids of dereferenced null pointers throw by order of C++ 2003, + // sect. 5.2.8, para. 2 (although the result is not conceptually needed). + PRIVATE_SHOW_MESSAGE( "There is an " << template_name << "<" << setting << + "> specialization with type '" << typeid(typename + Tmpl::value_type).name() << "' and value '" << std::hex << + Tmpl::value << "'." ); + return true; +} + +template < typename ValueT, typename T > +bool +print_out_template( T const &, ValueT setting, char const *template_name ) +{ + PRIVATE_SHOW_MESSAGE( "There is no " << template_name << "<" << setting << + "> specialization." ); + return false; +} } // unnamed namespace @@ -46,14 +96,18 @@ BOOST_AUTO_TEST_SUITE( integer_mask_tests ) // Check the bit-masks of one offset bit BOOST_AUTO_TEST_CASE_TEMPLATE( high_bit_mask_test, T, high_bit_offsets ) { + typedef boost::mpl::integral_c::least, 1u> one_type; + typedef boost::mpl::shift_left result_type; + BOOST_MPL_ASSERT_RELATION( boost::high_bit_mask_t::high_bit, ==, - (one << T::value) ); + result_type::value ); BOOST_MPL_ASSERT_RELATION( boost::high_bit_mask_t::high_bit_fast, - ==, (one << T::value) ); + ==, result_type::value ); } -// Check the bit-masks of a block of low-valued bits -BOOST_AUTO_TEST_CASE_TEMPLATE( low_bits_mask_test, T, low_bit_lengths ) +// Check the bit-masks of a block of low-valued bits, non-zero block-lengths +BOOST_AUTO_TEST_CASE_TEMPLATE( low_bits_mask_test, T, special_low_bit_lengths ) { // One can express (2^x - 1) in two ways // 1. (1 << x) - 1 @@ -62,10 +116,51 @@ BOOST_AUTO_TEST_CASE_TEMPLATE( low_bits_mask_test, T, low_bit_lengths ) // when x is the number of bits in the register. However, that last case // gives warnings about the sole bit flowing past the register. Applying // distributive property backwards gives [2], which works without overflow. + typedef typename boost::mpl::prior::type shift_type; + typedef boost::mpl::integral_c::least, 1u> one_type; + typedef boost::mpl::shift_left high_bit_type; + typedef typename boost::mpl::prior::type low_bits_type; + typedef boost::mpl::bitor_ result_type; + BOOST_MPL_ASSERT_RELATION( boost::low_bits_mask_t::sig_bits, ==, - (one << ( T::value - 1u )) | (( one << (T::value - 1u) ) - 1u) ); + result_type::value ); BOOST_MPL_ASSERT_RELATION( boost::low_bits_mask_t::sig_bits_fast, - ==, (one << ( T::value - 1u )) | (( one << (T::value - 1u) ) - 1u) ); + ==, result_type::value ); +} + +// Check the bit-masks of a block of low-valued bits, zero block-length +BOOST_AUTO_TEST_CASE( special_low_bits_mask_test ) +{ + // Just like "low_bits_mask_test" above, except that the shifts are negative + // when the bit-count is zero. That causes a lot of warnings and errors, so + // special-case that bit-count. + BOOST_MPL_ASSERT_RELATION( boost::low_bits_mask_t<0u>::sig_bits, ==, 0 ); + BOOST_MPL_ASSERT_RELATION(boost::low_bits_mask_t<0u>::sig_bits_fast, ==, 0); +} + +// Check the specialization type status of given bit-offsets/lengths +BOOST_AUTO_TEST_CASE_TEMPLATE( confirm_bounds_test, T, wild_bit_lengths ) +{ + typedef boost::integer_hi_mask hi_type; + typedef boost::mpl::int_ hi_offset_type; + typedef boost::mpl::bool_ special_hi_type; + + BOOST_MPL_ASSERT( (boost::mpl::equal_to< hi_offset_type, T >) ); + BOOST_MPL_ASSERT( (boost::mpl::equal_to< special_hi_type, + boost::mpl::bool_<(T::value >= 0) && (T::value < max_offset)> >) ); + BOOST_CHECK_EQUAL( print_out_template(hi_type(), hi_offset_type::value, + "integer_hi_mask"), special_hi_type::value ); + + typedef boost::integer_lo_mask lo_type; + typedef boost::mpl::int_ lo_length_type; + typedef boost::mpl::bool_ special_lo_type; + + BOOST_MPL_ASSERT( (boost::mpl::equal_to< lo_length_type, T >) ); + BOOST_MPL_ASSERT( (boost::mpl::equal_to< special_lo_type, + boost::mpl::bool_<(T::value >= 0) && (T::value <= max_offset)> >) ); + BOOST_CHECK_EQUAL( print_out_template(lo_type(), lo_length_type::value, + "integer_lo_mask"), special_lo_type::value ); } BOOST_AUTO_TEST_SUITE_END()