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]
This commit is contained in:
Gennaro Prota
2008-09-10 10:07:46 +00:00
parent f6ce97de67
commit 24d2081a73
3 changed files with 186 additions and 53 deletions

View File

@@ -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 <typename Bitset>
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 <typename NumBits, typename Value>
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<size_type>(num_bits);
BOOST_CHECK(b.size() == sz);
const std::size_t ulong_width = std::numeric_limits<unsigned long>::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<unsigned long>(num), i));
for ( ; i < sz; ++i)
BOOST_CHECK(b.test(i) == 0);
}
@@ -978,7 +989,7 @@ struct bitset_test {
//-------------------------------------------------------------------------
// operator<<( [basic_]ostream,
template<typename Stream>
template <typename Stream>
static void stream_inserter(const Bitset & b,
Stream & s,
const char * file_name
@@ -1058,7 +1069,7 @@ struct bitset_test {
}
// operator>>( [basic_]istream
template<typename Stream, typename String>
template <typename Stream, typename String>
static void stream_extractor(Bitset& b,
Stream& is,
String& str

View File

@@ -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 <typename Tests, typename T>
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<T>::digits;
const T ma = (std::numeric_limits<T>::max)();
const T mi = (std::numeric_limits<T>::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<char>::max)() );
Tests::from_unsigned_long(static_cast<T>(sizes[s]), numbers[n]);
}
}
}
template <typename Block>
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<source_type>::digits;
const source_type source_max =(std::numeric_limits<source_type>::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<Tests, char>();
#if !defined(BOOST_NO_INTRINSIC_WCHAR_T)
run_numeric_ctor_tests<Tests, wchar_t>();
#endif
run_numeric_ctor_tests<Tests, signed char>();
run_numeric_ctor_tests<Tests, short int>();
run_numeric_ctor_tests<Tests, int>();
run_numeric_ctor_tests<Tests, long int>();
run_numeric_ctor_tests<Tests, unsigned char>();
run_numeric_ctor_tests<Tests, unsigned short>();
run_numeric_ctor_tests<Tests, unsigned int>();
run_numeric_ctor_tests<Tests, unsigned long>();
#if defined(BOOST_HAS_LONG_LONG)
run_numeric_ctor_tests<Tests, ::boost::long_long_type>();
run_numeric_ctor_tests<Tests, ::boost::ulong_long_type>();
#endif
}
//=====================================================================
// Test construction from a string

View File

@@ -574,11 +574,20 @@ Constructible</a>.)
<b>Effects:</b> Constructs a bitset from an integer. The first
<tt>M</tt> bits are initialized to the corresponding bits in
<tt>val</tt> and all other bits, if any, to zero (where <tt>M =
<tt>value</tt> and all other bits, if any, to zero (where <tt>M =
min(num_bits, std::numeric_limits&lt;unsigned long&gt;::digits)</tt>). A copy of
the <tt>alloc</tt> object will be used in subsequent bitset
operations such as <tt>resize</tt> to allocate memory.<br />
<b>Postconditions:</b>
operations such as <tt>resize</tt> to allocate memory. Note that, e.g., the
following
<br /><br />
<tt>
dynamic_bitset b<>( 16, 7 );
</tt><br /><br />
will match the <a href="#cons4">constructor from an iterator range</a> (not this
one), but the underlying implementation will still "do the right thing" and
construct a bitset of 16 bits, from the value 7.
<br />
<b>Postconditions:</b>
<ul>
<li><tt>this-&gt;size() == num_bits</tt></li>
@@ -620,24 +629,56 @@ explicit
const Allocator&amp; alloc = Allocator());
</pre>
<b>Effects:</b> Constructs a bitset based on a range of blocks.
Let <tt>*first</tt> be block number 0, <tt>*++first</tt> block
number 1, etc. Block number <tt>b</tt> is used to initialize the
bits of the dynamic_bitset in the position range
<tt>[b*bits_per_block, (b+1)*bits_per_block)</tt>. For each block
number <tt>b</tt> with value <tt>bval</tt>, the bit <tt>(bval
&gt;&gt; i) &amp; 1</tt> corresponds to the bit at position
<tt>(b * bits_per_block + i)</tt> in the bitset (where <tt>i</tt>
goes through the range <tt>[0, bits_per_block)</tt>).<br />
<b>Requires:</b> The type <tt>BlockInputIterator</tt> must be a
model of <a href=
"http://www.sgi.com/tech/stl/InputIterator.html">Input
Iterator</a> and its <tt>value_type</tt> must be the same type as
<tt>Block</tt>.<br />
<b>Throws:</b> An allocation error if memory is exhausted
(<tt>std::bad_alloc</tt> if
<tt>Allocator=std::allocator</tt>).<br />
<b>Effects:</b>
<ul>
<li>
If this constructor is called with a type <tt>BlockInputIterator</tt> which
<i>is actually an integral type</i>, the library behaves as if the constructor
from <tt>unsigned long</tt> had been called, with arguments
<tt>static_cast&lt;size_type&gt;(first), last and alloc</tt>, in that order.
Example:
<pre>
// b is constructed as if by calling the constructor
//
// dynamic_bitset(size_type num_bits,
// unsigned long value = 0,
// const Allocator&amp; alloc = Allocator())
//
// with arguments
//
// static_cast&lt;dynamic_bitset&lt;unsigned short&gt;::size_type&gt;(8),
// 7,
// Allocator()
//
dynamic_bitset&lt;unsigned short&gt; b(8, 7);
</pre><br />
<i>Note:</i><br/>
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").<br /><br />
</li>
<li>
<i>Otherwise</i> (<i>i.e.</i> if the template argument is not an integral
type), constructs&mdash;under the condition in the <tt>requires</tt>
clause&mdash;a bitset based on a range of blocks. Let <tt>*first</tt> be block
number 0, <tt>*++first</tt> block number 1, etc. Block number <tt>b</tt> is used
to initialize the bits of the dynamic_bitset in the position range
<tt>[b*bits_per_block, (b+1)*bits_per_block)</tt>. For each block number
<tt>b</tt> with value <tt>bval</tt>, the bit <tt>(bval &gt;&gt; i) &amp; 1</tt>
corresponds to the bit at position <tt>(b * bits_per_block + i)</tt> in the
bitset (where <tt>i</tt> goes through the range <tt>[0, bits_per_block)</tt>).
</li>
</ul>
<br />
<b>Requires:</b> <tt>BlockInputIterator</tt> must be either an integral type or
a model of <a href= "http://www.sgi.com/tech/stl/InputIterator.html">Input
Iterator</a> whose <tt>value_type</tt> is the same type as
<tt>Block</tt>.<br /> <b>Throws:</b> An allocation error if memory is exhausted
(<tt>std::bad_alloc</tt> if <tt>Allocator=std::allocator</tt>).<br />
<hr />
<pre>
@@ -1436,11 +1477,17 @@ from the stream.
<h3><a id="exception-guarantees">Exception guarantees</a></h3>
All of <tt>dynamic_bitset</tt> functions offer at least the basic
exception guarantee.
exception guarantee.
<hr />
<h3><a id="changes-from-previous-ver">Changes from previous version(s)</a></h3>
<h4><i>Changes in Boost 1.37.0</i></h4>
<ul>
<li>The constructor from a block-range implements a <i>do-the-right-thing</i>
behavior, a la standard sequences.</li>
</ul>
<!-- Changes from Boost 1.31.0 -->
<h4><i>Changes from Boost 1.31.0</i></h4>
<ul>
@@ -1514,9 +1561,19 @@ href="http://freshsources.com">Chuck Allison</a>, Senior Editor,
C/C++ Users Journal (<a
href="mailto:cda@freshsources.com">cda@freshsources.com</a>)<br
/></td> </tr> <tr>
<td>Copyright &copy; 2003-2004, 2008</td> <td>Gennaro Prota</td>
<td>Copyright &copy; 2003-2004, 2008</td> <td><a
href="http://gennaro-prota.50webs.com/">Gennaro Prota</a>
(name.surname yahoo.com)</td>
</tr>
</table>
<br />
<div class="legalnotice">
Distributed under the Boost Software License, Version 1.0.
(See accompanying file <a href="../../LICENSE_1_0.txt">LICENSE_1_0.txt</a>
or copy at <a class="ulink" href="http://www.boost.org/LICENSE_1_0.txt">
http://www.boost.org/LICENSE_1_0.txt</a>)
</div>
</div>
</div>