From 24d2081a731c07a9e22807b16c9975368bae409d Mon Sep 17 00:00:00 2001 From: Gennaro Prota Date: Wed, 10 Sep 2008 10:07:46 +0000 Subject: [PATCH] added specific tests for constructor dispatch and clarified the corresponding comments a bit; minor formatting consistency fixes; updated documentation and added license reference text to it [SVN r48695] --- bitset_test.hpp | 45 ++++++++++------- dyn_bitset_unit_tests1.cpp | 93 +++++++++++++++++++++++++++++----- dynamic_bitset.html | 101 +++++++++++++++++++++++++++++-------- 3 files changed, 186 insertions(+), 53 deletions(-) diff --git a/bitset_test.hpp b/bitset_test.hpp index 2484a3d..bca746e 100644 --- a/bitset_test.hpp +++ b/bitset_test.hpp @@ -1,6 +1,6 @@ // ----------------------------------------------------------- // Copyright (c) 2001 Jeremy Siek -// Copyright (c) 2003-2006 Gennaro Prota +// Copyright (c) 2003-2006, 2008 Gennaro Prota // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at @@ -108,32 +108,43 @@ bool has_flags(const Stream& s, std::ios::iostate flags) // constructors // default (can't do this generically) -// from unsigned long - template struct bitset_test { typedef typename Bitset::block_type Block; BOOST_STATIC_CONSTANT(int, bits_per_block = Bitset::bits_per_block); - - static void from_unsigned_long(std::size_t sz, unsigned long num) + // from unsigned long + // + // Note: this is templatized so that we check that the do-the-right-thing + // constructor dispatch is working correctly. + // + template + static void from_unsigned_long(NumBits num_bits, Value num) { - // An object of size N = sz is constructed: - // - the first M bit positions are initialized to the corresponding bit - // values in num (M being the smaller of N and the width of unsigned - // long) + // An object of size sz = num_bits is constructed: + // - the first m bit positions are initialized to the corresponding + // bit values in num (m being the smaller of sz and ulong_width) + // + // - any remaining bit positions are initialized to zero // - // - if M < N remaining bit positions are initialized to zero - Bitset b(sz, num); + Bitset b(num_bits, num); + + // OK, we can now cast to size_type + typedef typename Bitset::size_type size_type; + const size_type sz = static_cast(num_bits); + BOOST_CHECK(b.size() == sz); const std::size_t ulong_width = std::numeric_limits::digits; - std::size_t m = (std::min)(sz, ulong_width); - std::size_t i; - for (i = 0; i < m; ++i) - BOOST_CHECK(b.test(i) == nth_bit(num, i)); + size_type m = sz; + if (ulong_width < sz) + m = ulong_width; + + size_type i = 0; + for ( ; i < m; ++i) + BOOST_CHECK(b.test(i) == nth_bit(static_cast(num), i)); for ( ; i < sz; ++i) BOOST_CHECK(b.test(i) == 0); } @@ -978,7 +989,7 @@ struct bitset_test { //------------------------------------------------------------------------- // operator<<( [basic_]ostream, - template + template static void stream_inserter(const Bitset & b, Stream & s, const char * file_name @@ -1058,7 +1069,7 @@ struct bitset_test { } // operator>>( [basic_]istream - template + template static void stream_extractor(Bitset& b, Stream& is, String& str diff --git a/dyn_bitset_unit_tests1.cpp b/dyn_bitset_unit_tests1.cpp index 9f230ea..574c42a 100644 --- a/dyn_bitset_unit_tests1.cpp +++ b/dyn_bitset_unit_tests1.cpp @@ -15,7 +15,7 @@ #include "boost/detail/workaround.hpp" -#define BOOST_BITSET_TEST_COUNT_OF(x) (sizeof(x)/sizeof(x[0])) +#define BOOST_BITSET_TEST_COUNT(x) (sizeof(x)/sizeof(x[0])) // Codewarrior 8.3 for Win fails without this. @@ -54,6 +54,43 @@ void run_string_tests(const String& s } +// tests the do-the-right-thing constructor dispatch +template +void run_numeric_ctor_tests( BOOST_EXPLICIT_TEMPLATE_TYPE(Tests) + BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(T) ) +{ + + const int bits_per_block = Tests::bits_per_block; + const int width = std::numeric_limits::digits; + const T ma = (std::numeric_limits::max)(); + const T mi = (std::numeric_limits::min)(); + + int sizes[] = { + 0, 7*width/10, width, 13*width/10, 3*width, + 7*bits_per_block/10, bits_per_block, 13*bits_per_block/10, 3*bits_per_block + }; + + const T numbers[] = { + T(-1), T(-3), T(-8), T(-15), mi/2, mi, + 0, 1, 3, 8, 15, ma/2, ma + }; + + for (std::size_t s = 0; s < BOOST_BITSET_TEST_COUNT(sizes); ++s) { + for (std::size_t n = 0; n < BOOST_BITSET_TEST_COUNT(numbers); ++n ) { + + // can match ctor from ulong or templated one + Tests::from_unsigned_long(sizes[s], numbers[n]); + + // can match templated ctor only (so we test dispatching) + assert( sizes[s] < (std::numeric_limits::max)() ); + Tests::from_unsigned_long(static_cast(sizes[s]), numbers[n]); + + } + } + +} + + template void run_test_cases( BOOST_EXPLICIT_TEMPLATE_TYPE(Block) ) { @@ -67,24 +104,52 @@ void run_test_cases( BOOST_EXPLICIT_TEMPLATE_TYPE(Block) ) //===================================================================== // Test construction from unsigned long { - typedef unsigned long source_type; - const std::size_t source_width = std::numeric_limits::digits; - const source_type source_max =(std::numeric_limits::max)(); + typedef typename bitset_type::size_type size_type; - source_type numbers[] = { 0, 1, 40247, source_max >> 1, source_max }; - std::size_t sizes[] = - { 0, 7 * source_width / 10, source_width, 13 * source_width / 10, - 7 * bits_per_block / 10, bits_per_block, 13 * bits_per_block / 10, - 3 * bits_per_block }; - const std::size_t value_count = BOOST_BITSET_TEST_COUNT_OF(numbers); - const std::size_t size_count = BOOST_BITSET_TEST_COUNT_OF(sizes); + // NOTE: + // + // 1. keep this in sync with the numeric types supported + // for constructor dispatch (of course) + // 2. bool is tested separately; ugly and inelegant, but + // we don't have much time to think of a better solution + // which is likely to work on broken compilers + // + const int sizes[] = { + 0, 1, 3, + 7*bits_per_block/10, bits_per_block, 13*bits_per_block/10, 3*bits_per_block + }; + + const bool values[] = { false, true }; - for (std::size_t v = 0; v < value_count; ++v) { - for (std::size_t s = 0; s < size_count; ++s) { - Tests::from_unsigned_long(sizes[s], numbers[v]); + for (std::size_t s = 0; s < BOOST_BITSET_TEST_COUNT(sizes); ++s) { + for (std::size_t v = 0; v < BOOST_BITSET_TEST_COUNT(values); ++v) { + Tests::from_unsigned_long(sizes[s], values[v]); + Tests::from_unsigned_long(sizes[s] != 0, values[v]); } } + + run_numeric_ctor_tests(); + +#if !defined(BOOST_NO_INTRINSIC_WCHAR_T) + run_numeric_ctor_tests(); +#endif + + run_numeric_ctor_tests(); + run_numeric_ctor_tests(); + run_numeric_ctor_tests(); + run_numeric_ctor_tests(); + + run_numeric_ctor_tests(); + run_numeric_ctor_tests(); + run_numeric_ctor_tests(); + run_numeric_ctor_tests(); + +#if defined(BOOST_HAS_LONG_LONG) + run_numeric_ctor_tests(); + run_numeric_ctor_tests(); +#endif + } //===================================================================== // Test construction from a string diff --git a/dynamic_bitset.html b/dynamic_bitset.html index cf12a40..d01b6ea 100644 --- a/dynamic_bitset.html +++ b/dynamic_bitset.html @@ -574,11 +574,20 @@ Constructible.) Effects: Constructs a bitset from an integer. The first M bits are initialized to the corresponding bits in -val and all other bits, if any, to zero (where M = +value and all other bits, if any, to zero (where M = min(num_bits, std::numeric_limits<unsigned long>::digits)). A copy of the alloc object will be used in subsequent bitset -operations such as resize to allocate memory.
- Postconditions: +operations such as resize to allocate memory. Note that, e.g., the +following +

+ +dynamic_bitset b<>( 16, 7 ); +

+will match the constructor from an iterator range (not this +one), but the underlying implementation will still "do the right thing" and +construct a bitset of 16 bits, from the value 7. +
+Postconditions:
  • this->size() == num_bits
  • @@ -620,24 +629,56 @@ explicit const Allocator& alloc = Allocator()); -Effects: Constructs a bitset based on a range of blocks. -Let *first be block number 0, *++first block -number 1, etc. Block number b is used to initialize the -bits of the dynamic_bitset in the position range -[b*bits_per_block, (b+1)*bits_per_block). For each block -number b with value bval, the bit (bval ->> i) & 1 corresponds to the bit at position -(b * bits_per_block + i) in the bitset (where i -goes through the range [0, bits_per_block)).
    - Requires: The type BlockInputIterator must be a -model of Input -Iterator and its value_type must be the same type as -Block.
    - Throws: An allocation error if memory is exhausted -(std::bad_alloc if -Allocator=std::allocator).
    +Effects: +
      +
    • +If this constructor is called with a type BlockInputIterator which +is actually an integral type, the library behaves as if the constructor +from unsigned long had been called, with arguments +static_cast<size_type>(first), last and alloc, in that order. +Example: +
      +// b is constructed as if by calling the constructor
      +//
      +//   dynamic_bitset(size_type num_bits,
      +//                  unsigned long value = 0,
      +//                  const Allocator& alloc = Allocator())
      +//
      +// with arguments
      +//
      +//   static_cast<dynamic_bitset<unsigned short>::size_type>(8),
      +//   7,
      +//   Allocator()
      +//
      +dynamic_bitset<unsigned short> b(8, 7);
      +

      +Note:
      +This is analogous to what the standard mandates for sequence containers (namely, +that if the type on which the template constructor is intantiated "does not +qualify as an input iterator" then the other constructor is called; "the extent +to which an implementation determines that a type cannot be an input iterator is +unspecified, except that as a minimum integral types shall not qualify as input +iterators").

      +
    • +
    • +Otherwise (i.e. if the template argument is not an integral +type), constructs—under the condition in the requires +clause—a bitset based on a range of blocks. Let *first be block +number 0, *++first block number 1, etc. Block number b is used +to initialize the bits of the dynamic_bitset in the position range +[b*bits_per_block, (b+1)*bits_per_block). For each block number +b with value bval, the bit (bval >> i) & 1 +corresponds to the bit at position (b * bits_per_block + i) in the +bitset (where i goes through the range [0, bits_per_block)). +
    • +
    +
    +Requires: BlockInputIterator must be either an integral type or +a model of Input + Iterator whose value_type is the same type as +Block.
    Throws: An allocation error if memory is exhausted +(std::bad_alloc if Allocator=std::allocator).

    @@ -1436,11 +1477,17 @@ from the stream.
     

    Exception guarantees

    All of dynamic_bitset functions offer at least the basic -exception guarantee. +exception guarantee.

    Changes from previous version(s)

    +

    Changes in Boost 1.37.0

    +
      +
    • The constructor from a block-range implements a do-the-right-thing +behavior, a la standard sequences.
    • +
    +

    Changes from Boost 1.31.0