Boost logo

Boost-Commit :

From: dwalker07_at_[hidden]
Date: 2008-08-17 06:06:23


Author: dlwalker
Date: 2008-08-17 06:06:22 EDT (Sun, 17 Aug 2008)
New Revision: 48183
URL: http://svn.boost.org/trac/boost/changeset/48183

Log:
Added brand-new concept for 'hat,' this time as a container adaptor
Added:
   sandbox/hat/boost/containers/
   sandbox/hat/boost/containers/hat.hpp (contents, props changed)
   sandbox/hat/boost/containers_fwd.hpp (contents, props changed)
   sandbox/hat/libs/containers/
   sandbox/hat/libs/containers/test/
   sandbox/hat/libs/containers/test/hat_test.cpp (contents, props changed)

Added: sandbox/hat/boost/containers/hat.hpp
==============================================================================
--- (empty file)
+++ sandbox/hat/boost/containers/hat.hpp 2008-08-17 06:06:22 EDT (Sun, 17 Aug 2008)
@@ -0,0 +1,622 @@
+// Boost containers/hat.hpp header file -------------------------------------//
+/** \file
+ \brief Declaration of the \c hat container adaptor class template.
+
+ \author Daryle Walker
+
+ Contains the declaration (and definition) of the \c boost::containers::hat
+ container adaptor class template. The adaptor enables random selection of
+ its contents.
+
+ (C) Copyright Daryle Walker 2008. Distributed under the Boost Software
+ License, Version 1.0. (See the accompanying file LICENSE_1_0.txt or a copy
+ at <http://www.boost.org/LICENSE_1_0.txt>.)
+ */
+// See <http://www.boost.org/libs/containers> for documentation.
+
+#ifndef BOOST_CONTAINERS_HAT_HPP
+#define BOOST_CONTAINERS_HAT_HPP
+
+#include <boost/containers_fwd.hpp>
+
+#include <boost/concept/assert.hpp> // for BOOST_CONCEPT_ASSERT
+#include <boost/concept_check.hpp> // for boost::SGIAssignable, etc.
+#include <boost/mpl/assert.hpp> // for BOOST_MPL_ASSERT
+#include <boost/random/mersenne_twister.hpp> // for boost::mt19937
+#include <boost/random/uniform_int.hpp> // for boost::uniform_int
+#include <boost/swap.hpp> // for boost::swap
+#include <boost/type_traits/is_same.hpp> // for boost::is_same
+
+#include <deque> // for std::deque
+#include <iterator> // for std::iterator_traits, advance, distance
+
+
+namespace boost
+{
+namespace containers
+{
+
+
+// Hat (really) random-access container class template definition ----------//
+
+/** \brief A container adaptor that provides random selection of its contents,
+ similar to pulling names from a hat.
+
+ \author Daryle Walker (Boost implementation)
+ \author Jonathan Wooldridge [a.k.a. AngleWyrm] (original concept)
+
+ The interface is similar to that of \c std::priority_queue. The call to
+ \c #top will choose an element based on a randomly selected index. To refer
+ to a specific element repeatedly, token objects can be returned from random
+ draws instead. These tokens are required to remove a specific element after
+ it's first chosen. (The fact that calls to \c #top and the regular \c #pop
+ use separate random draws is why the token system was added.) All elements
+ are given equal consideration (i.e. weight) for selection, modulo any bias
+ in the random number generation.
+
+ Example containers that can be adapted are \c std::vector, \c std::deque,
+ \c std::list, and \c std::basic_string.
+
+ \pre Besides being suitable for container elements, \p T must be Swappable.
+ \pre \p Container must be a sequence-style container type. \p T must be
+ its element type.
+ \pre \p RandomNumberGenerator must have an interface compatible with the
+ engines that are part of the Boost.Random library, conforming to
+ UniformRandomNumberGenerator, CopyConstructable, and Assignable.
+
+ \tparam T The type of the elements.
+ \tparam Container The type of the container. If not given,
+ <code>std::deque&lt;<var>T</var>&gt;</code>
+ is the default.
+ \tparam RandomNumberGenerator The type of the uniform random number
+ generation engine. If not given,
+ \c boost::mt19937 is the default.
+
+ \todo Need to add a concept check for Swappable on T.
+ \todo Need to add concept check for UniformRandomNumberGenerator,
+ CopyConstructable, and Assignable on RandomNumberGenerator.
+ \todo Create constructors that use the new move semantics (i.e. r-value
+ &quot;&amp;&amp;&quot; references) for the components.
+ \todo Can the container's size get big enough, or the RNG engine's
+ randomness small enough, that gaps will exist between chosen indices?
+ If so, how can we tell? Is there some general parameter that can be
+ read from the engine so we'll know when this problem happens?
+ */
+template < typename T, class Container = std::deque<T>, class
+ RandomNumberGenerator = boost::mt19937 >
+class hat
+{
+ // Concept checks
+ BOOST_CONCEPT_ASSERT(( boost::SGIAssignable<T> ));
+
+ BOOST_CONCEPT_ASSERT(( boost::Sequence<Container> ));
+
+ BOOST_MPL_ASSERT(( boost::is_same<T, typename Container::value_type> ));
+
+ // Helper type-aliases
+ typedef typename Container::iterator iterator;
+ typedef typename Container::const_iterator const_iterator;
+
+ // Hidden implmentation member data
+ mutable RandomNumberGenerator e;
+
+public:
+ // Types
+ /** \brief Type of the container
+
+ Represents the class used for containing element objects.
+ */
+ typedef Container container_type;
+ /** \brief Type of the random number generation engine
+
+ Represents the class used for choosing randomly-selected numbers.
+ */
+ typedef RandomNumberGenerator engine_type;
+
+ /** \brief Type of elements
+
+ Represents the type of the container's elements. Copied from the
+ container's type profile.
+ */
+ typedef typename Container::value_type value_type;
+ /** \brief Type of size values
+
+ Represents the unsigned integral type used for sizing returns. Copied
+ from the container's type profile.
+ */
+ typedef typename Container::size_type size_type;
+
+ /** \brief Type of element references
+
+ Represents the type of references to the container's elements. Copied
+ from the container's type profile.
+ */
+ typedef typename Container::reference reference;
+ /** \brief Type of element references with immutable access
+
+ Represents the type of references to the container's elements with
+ immutable access. Copied from the container's type profile.
+ */
+ typedef typename Container::const_reference const_reference;
+
+ /** \brief Type of markers towards a container's element with immutable
+ access
+
+ Represents the type for access to a specific element after it's randomly
+ chosen. The main way to access an element, \c #top, changes its
+ referent after each call, so using tokens is the only method of later
+ referral. It is similar to an immutable-access iterator, except all
+ forms of traversal are disabled.
+ */
+ class const_token
+ {
+ public:
+ /** \brief The inner iterator
+
+ Accesses a particular element of the adaptor's container. Public to
+ avoid complicated (friend) definitions.
+ */
+ const_iterator i;
+
+ /** \brief Indirection
+
+ Dereferences the token to provide &quot;direct&quot; access to the
+ target element.
+
+ \return A <code>const</code> reference to this object's target.
+ */
+ const_reference operator *() const { return *this->i; }
+ /** \brief Class member access (via pointer)
+
+ Dereferences the token to provide access to the target element in
+ a pointer-like style.
+
+ \return A <code>const</code> pointer to this object's target.
+ */
+ value_type const * operator ->() const { return &this->operator *(); }
+
+ /** \brief Equals
+
+ Compares this token with another for equivalence. The tokens are
+ equal if they refer to the same element object. (This token acts as
+ the left-side operand.) This operator is also used when \p o is
+ really a \c boost::containers::hat::token object.
+
+ \param o The right-side operand to be compared.
+
+ \retval true \c *this and \p o are equivalent.
+ \retval false \c *this and \p o are not equivalent.
+ */
+ bool operator ==( const_token o ) const { return this->i == o.i; }
+ /** \brief Not-equals
+
+ Compares this token with another for non-equivalence. The tokens
+ are unequal if they refer to different element objects. (This token
+ acts as the left-side operand.) This operator is also used when
+ \p o is really a \c boost::containers::hat::token object.
+
+ \param o The right-side operand to be compared.
+
+ \retval true \c *this and \p o are not equivalent.
+ \retval false \c *this and \p o are equivalent.
+ */
+ bool operator !=( const_token o ) const {return !this->operator==(o);}
+ };
+ /** \brief Type of markers towards a container's element
+
+ Represents the type for access to a specific element after it's randomly
+ chosen. The main way to access an element, \c #top, changes its
+ referent after each call, so using tokens is the only method of later
+ referral. It is similar to a mutable-access iterator, except all forms
+ of traversal are disabled.
+ */
+ class token
+ {
+ public:
+ /** \brief The inner iterator
+
+ Accesses a particular element of the adaptor's container. Public to
+ avoid complicated (friend) definitions.
+ */
+ iterator i;
+
+ /** \brief Indirection
+
+ Dereferences the token to provide &quot;direct&quot; access to the
+ target element.
+
+ \return A non-<code>const</code> reference to this object's target.
+ */
+ reference operator *() const { return *this->i; }
+ /** \brief Class member access (via pointer)
+
+ Dereferences the token to provide access to the target element in
+ a pointer-like style.
+
+ \return A non-<code>const</code> pointer to this object's target.
+ */
+ value_type * operator ->() const { return &this->operator *(); }
+
+ /** \brief Conversion, immutable-access token
+
+ To meet the requirements of a container, a mutable-access iterator
+ has to be able convert to a immutable-access one of the same
+ element. Similarly, this ability is granted to tokens.
+
+ \return A token with immutable access (i.e. \c const) to the same
+ element that this token refers to.
+ */
+ operator const_token() const
+ {
+ const_token result = { this->i };
+
+ return result;
+ }
+
+ /** \brief Equals
+
+ Compares this token with another for equivalence. The tokens are
+ equal if they refer to the same element object. (This token acts as
+ the left-side operand.)
+
+ \param o The right-side operand to be compared.
+
+ \retval true \c *this and \p o are equivalent.
+ \retval false \c *this and \p o are not equivalent.
+ */
+ bool operator ==( token o ) const { return this->i == o.i; }
+ /** \brief Not-equals
+
+ Compares this token with another for non-equivalence. The tokens
+ are unequal if they refer to different element objects. (This token
+ acts as the left-side operand.)
+
+ \param o The right-side operand to be compared.
+
+ \retval true \c *this and \p o are not equivalent.
+ \retval false \c *this and \p o are equivalent.
+ */
+ bool operator !=( token o ) const { return !this->operator ==( o ); }
+
+ /** \brief Equals, cross-mutability
+
+ Compares this token with a \c boost::containers::hat::const_token for equivalence. The
+ tokens are equal if they refer to the same element objects. (This
+ token acts as the left-side operand.)
+
+ \param o The right-side operand to be compared.
+
+ \retval true \c *this and \p o are equivalent.
+ \retval false \c *this and \p o are not equivalent.
+ */
+ bool operator ==( const_token o ) const {return o.operator ==(*this);}
+ /** \brief Not-equals, cross-mutability
+
+ Compares this token with a \c boost::containers::hat::const_token for non-equivalence. The
+ tokens are unequal if they refer to different element objects.
+ (This token acts as the left-side operand.)
+
+ \param o The right-side operand to be compared.
+
+ \retval true \c *this and \p o are not equivalent.
+ \retval false \c *this and \p o are equivalent.
+ */
+ bool operator !=( const_token o ) const {return o.operator !=(*this);}
+ };
+
+protected:
+ // Exposed member data or access
+ /** \brief The inner container
+
+ Accesses the adaptor's container. Enables a derived class to
+ arbitrarily mess with the container.
+ */
+ Container c;
+
+ /** \brief The random number generator engine, mutable access
+
+ Accesses the adaptor's random number generator engine. Enables a
+ derived class to arbitrarily mess with the engine. Conventional access,
+ like \c #c, is not provided due to how the engine is set up in this
+ class.
+
+ \return A non-<code>const</code> reference to inner R.N.G. engine.
+ */
+ RandomNumberGenerator & engine() { return this->e; }
+ /** \brief The random number generator engine, immutable access
+
+ Accesses the adaptor's random number generator engine. Enables a
+ derived class to arbitrarily inspect the engine. Conventional access,
+ like \c #c, is not provided due to how the engine is set up in this
+ class.
+
+ \return A \c const reference to inner R.N.G. engine.
+ */
+ RandomNumberGenerator const & engine() const { return this->e; }
+
+ /** \brief Index random-selection
+
+ Generates an index value at random. The value is constrained to be a
+ valid offset (for non-empty containers). Even though this member
+ function is marked \c const, the inner R.N.G. engine may still change.
+ Enables derived classes to choose random elements without creating
+ either a token or a reference to an element.
+
+ \return An index to an element in \c #c, or zero if
+ <code>this-&gt;c.empty()</code>.
+ */
+ size_type choice() const
+ {
+ return uniform_int<size_type>( 0u, this->size() - !this->empty() )(
+ this->e );
+ }
+
+public:
+ // Lifetime management (use automatic copy constructor and destructor)
+ /** Constructs a \c #hat object with the given R.N.G. engine and container.
+ It can also either construct an empty hat with a given engine or serve
+ as the default constructor to an empty hat with default R.N.G. settings.
+
+ \param en The engine to copy settings. If not given, a default
+ constructed engine is used.
+ \param co The container to copy elements. If not given, a default
+ constructed container is used.
+
+ \post <code><var>en</var> == this-&gt;engine()</code>.
+ \post <code><var>co</var> == this-&gt;c</code>.
+ */
+ explicit hat( RandomNumberGenerator const &en = RandomNumberGenerator(),
+ Container const &co = Container() ) : c( co ), e( en ) {}
+
+ /** Constructs a \c #hat object with a given iterator range, R.N.G. engine,
+ and container. (The initial engine and container are optional.) The
+ elements of the iterator range are copied to the end of the inner
+ container in order.
+
+ \pre \p InputIterator models the input-iterator (or above) concept.
+ \pre The element type of \p InputIterator has to be compatible with
+ \c #value_type.
+ \pre \p last has to be reachable from \p first via a finite nonnegative
+ number of forward iterations.
+
+ \tparam InputIterator The type of the range's iterators.
+
+ \param first An iterator targeting the beginning of a list of entries
+ to be appended to \c #c. If this list is empty, then it
+ must equal \p last instead.
+ \param last An iterator targeting the past-the-end mark of a list of
+ entries to be appended to \c #c.
+ \param en The engine to copy settings. If not given, a default
+ constructed engine is used.
+ \param co The container to copy elements. If not given, a default
+ constructed container is used.
+
+ \post <code><var>en</var> == this-&gt;engine()</code>.
+ \post <code>std::equal( <var>co</var>.begin(), <var>co</var>.end(),
+ this-&gt;c.begin() ) &amp;&amp; std::equal( <var>first</var>,
+ <var>last</var>, this-&gt;c.begin() + <var>co</var>.size()
+ )</code>, excusing the assumptions that \p first and \p last are
+ reusable and that \c #container_type supports random-access
+ iterators.
+ */
+ template < typename InputIterator >
+ hat( InputIterator first, InputIterator last, RandomNumberGenerator const
+ &en = RandomNumberGenerator(), Container const &co = Container() )
+ : c( co ), e( en )
+ {
+ BOOST_CONCEPT_ASSERT(( boost::InputIterator<InputIterator> ));
+ BOOST_CONCEPT_ASSERT(( boost::Convertible<typename
+ std::iterator_traits<InputIterator>::value_type, value_type> ));
+
+ c.insert( c.end(), first, last );
+ }
+
+ // Sizing
+ /** \brief Checks if any elements are contained
+
+ This may be faster than using <code>this-&gt;size()</code> and an
+ equality-comparison with zero.
+
+ \return <code>this-&gt;size() == 0</code>
+
+ \see #size
+ */
+ bool empty() const { return this->c.empty(); }
+ /** \brief Returns the number of elements contained
+
+ \return The number of elements of the inner container.
+
+ \see #empty
+ */
+ size_type size() const { return this->c.size(); }
+
+ // Access
+ /** \brief Generates a marker to a randomly-chosen element
+
+ An element from \c #c is arbitrarily chosen, using the random number
+ generator \c #engine(). A token based off an iterator to that element
+ is created. Like container iterators, this token should be considered
+ invalid after any operation that changes the number of elements in
+ \c #c, even temporarily. (This includes \c #push and \c #pop,
+ especially if the latter removes the token's element.)
+
+ \pre <code>this-&gt;empty() == false</code>.
+
+ \return A \c boost::containers::hat::token to an element.
+
+ \post The R.N.G. engine may change.
+
+ \see #choice
+ \see #boost::containers::hat::token
+ */
+ token pick()
+ {
+ token result = { this->c.begin() };
+
+ std::advance( result.i, this->choice() );
+ return result;
+ }
+ /** \brief Generates marker to randomly-chosen element, immutable access
+
+ An element from \c #c is arbitrarily chosen, using the random number
+ generator \c #engine(). A token based off an iterator to that element
+ is created. Like container iterators, this token should be considered
+ invalid after any operation that changes the number of elements in
+ \c #c, even temporarily. (This includes \c #push and \c #pop,
+ especially if the latter removes the token's element.)
+
+ \pre <code>this-&gt;empty() == false</code>.
+
+ \return A token (actually a \c boost::containers::hat::const_token) to
+ an element.
+
+ \post The R.N.G. engine may change, even with \c const.
+
+ \see #choice
+ \see #boost::containers::hat::const_token
+ */
+ const_token pick() const
+ {
+ const_token result = { this->c.begin() };
+
+ std::advance( result.i, this->choice() );
+ return result;
+ }
+
+ /** \brief Generates a reference to a randomly-chosen element
+
+ An element from \c #c is arbitrarily chosen, using the random number
+ generator \c #engine(). Like direct container element references, this
+ reference should be considered invalid after any operations that change
+ the number of elements, even temporarily. (This includes \c #push and
+ \c #pop, especially if the latter removes the referenced element.)
+
+ \pre <code>this-&gt;empty() == false</code>.
+
+ \return A non-<code>const</code> reference to an element.
+
+ \post The R.N.G. engine may change.
+
+ \see #choice
+ */
+ reference top() { return *this->pick(); }
+ /** \brief Generates reference to randomly-chosen element, immutable access
+
+ An element from \c #c is arbitrarily chosen, using the random number
+ generator \c #engine(). Like direct container element references, this
+ reference should be considered invalid after any operations that change
+ the number of elements, even temporarily. (This includes \c #push and
+ \c #pop, especially if the latter removes the referenced element.)
+
+ \pre <code>this-&gt;empty() == false</code>.
+
+ \return A \c const reference to an element.
+
+ \post The R.N.G. engine may change, even with \c const.
+
+ \see #choice
+ */
+ const_reference top() const { return *this->pick(); }
+
+ // Element insertion/removal
+ /** \brief Adds an element
+
+ An element with the value \p x is added to the end of \c #c. Since the
+ \c push_back member function is optional for sequence-style containers,
+ the element is added with the inner container's \c insert member
+ function at the \c end point. Assume that it will invalidate any
+ outstanding element tokens and references.
+
+ \param x The value that will be copied into this object.
+
+ \post <code>this-&gt;size() == <var>old_this</var>.size() + 1</code>.
+ \post <code>*--this-&gt;c.end() == <var>x</var></code>.
+ */
+ void push( const_reference x ) { this->c.insert( this->c.end(), x ); }
+ /** \brief Removes a randomly-chosen element by marker, mutable access
+
+ The element referred to by \p t is removed from \c #c. Actually, its
+ value is swapped (using <code>boost::swap</code>) with the rear element
+ and then that rear element is removed, for efficiency's sake. (Since
+ the \c pop_back member function is optional for sequence-style
+ containers, the \c erase member function is used with an iterator to the
+ rear element.) This \e will ruin any sorting scheme that may be
+ maintained in the container, unless the rear element happened to be the
+ one chosen. Assume that it will invalidate any outstanding element
+ tokens and references.
+
+ \pre \p t is valid and it refers to a current element in \c c. (This
+ definately means that <code>this-&gt;empty() == false</code>.)
+
+ \param t A token to the element to be removed.
+
+ \post <code>this-&gt;size() == <var>old_this</var>.size() - 1</code>.
+ \post <code>std::count( this-&gt;c.begin(), this-&gt;c.end(), *
+ <var>t</var> ) + 1 == std::count( <var>old_this</var>.c.begin(),
+ <var>old_this</var>.c.end(), *<var>t</var> )</code>.
+
+ \see #boost::containers::hat::token
+ */
+ void pop( token t )
+ {
+ iterator rear = this->c.end();
+
+ boost::swap( *--rear, *t );
+ this->c.erase( rear );
+ }
+ /** \brief Removes a randomly-chosen element by marker, immutable access
+
+ The element referred to by \p t is removed from \c #c. Actually, this
+ operation is meant for mutable-access tokens, so \p t is translated to
+ such a token and then \c #pop(token) is called. This means that this
+ version may be slower. Any sorting scheme that may be maintained in the
+ container \e will be ruined, unless the rear element happened to be the
+ one chosen. Assume that it will invalidate any outstanding element
+ tokens and references.
+
+ \pre \p t is valid and it refers to a current element in \c c. (This
+ definately means that <code>this-&gt;empty() == false</code>.)
+
+ \param t A token to the element to be removed.
+
+ \post <code>this-&gt;size() == <var>old_this</var>.size() - 1</code>.
+ \post <code>std::count( this-&gt;c.begin(), this-&gt;c.end(), *
+ <var>t</var> ) + 1 == std::count( <var>old_this</var>.c.begin(),
+ <var>old_this</var>.c.end(), *<var>t</var> )</code>.
+
+ \see #boost::containers::hat::const_token
+ */
+ void pop( const_token t )
+ {
+ token location = { this->c.begin() };
+
+ std::advance(location.i,std::distance<const_iterator>(location.i, t.i));
+ this->pop( location );
+ }
+ /** \brief Removes a randomly-chosen element
+
+ Some element in \c #c is removed. There's no way to determine which one
+ without a bunch of comparisons and a save of the pre-<code>pop</code>
+ state. The removed element acts as if its value was swapped with the
+ rear element and then that one was removed. This means that any sorting
+ scheme maintained \e will be ruined (unless the rear element was the one
+ initially chosen). Assume that it will invalidate any outstanding
+ element tokens and references.
+
+ \pre <code>this-&gt;empty() == false</code>.
+
+ \post <code>this-&gt;size() == <var>old_this</var>.size() - 1</code>.
+ \post <code>0 &lt;= std::mismatch( this-&gt;c.begin(),
+ this-&gt;c.end(), <var>old_this</var>.c.begin() ).first -
+ this-&gt;c.begin() &lt;= this-&gt;size()</code>.
+ */
+ void pop() { this->pop( this->pick() ); }
+
+}; // boost::containers::hat
+
+
+} // namespace containers
+} // namespace boost
+
+
+#endif // BOOST_CONTAINERS_HAT_HPP

Added: sandbox/hat/boost/containers_fwd.hpp
==============================================================================
--- (empty file)
+++ sandbox/hat/boost/containers_fwd.hpp 2008-08-17 06:06:22 EDT (Sun, 17 Aug 2008)
@@ -0,0 +1,40 @@
+// Boost containers_fwd.hpp header file -------------------------------------//
+/** \file
+ \brief Forward declarations of Boost.Container components.
+
+ Contains the forward declarations of Boost.Container's public structures,
+ classes, and templates thereof, and any type aliases.
+
+ (C) Copyright Daryle Walker 2008. Distributed under the Boost Software
+ License, Version 1.0. (See the accompanying file LICENSE_1_0.txt or a copy
+ at <http://www.boost.org/LICENSE_1_0.txt>.)
+ */
+// See <http://www.boost.org/libs/containers> for documentation.
+
+#ifndef BOOST_CONTAINERS_FWD_HPP
+#define BOOST_CONTAINERS_FWD_HPP
+
+
+namespace boost
+{
+/** \brief Name-space for Boost.Container
+
+ Primary name-space for the public components of a library providing various
+ container classes and class templates.
+ */
+namespace containers
+{
+
+
+// From <boost/containers/hat.hpp> -----------------------------------------//
+
+template < typename T, class Container /*= std::deque<T>*/, class
+ RandomNumberGenerator /*= boost::mt19937*/ >
+ class hat;
+
+
+} // namespace containers
+} // namespace boost
+
+
+#endif // BOOST_CONTAINERS_FWD_HPP

Added: sandbox/hat/libs/containers/test/hat_test.cpp
==============================================================================
--- (empty file)
+++ sandbox/hat/libs/containers/test/hat_test.cpp 2008-08-17 06:06:22 EDT (Sun, 17 Aug 2008)
@@ -0,0 +1,349 @@
+// Boost hat_test.cpp test file ---------------------------------------------//
+
+// (C) Copyright 2008 Daryle Walker. Distributed under the Boost Software
+// License, Version 1.0. (See the accompanying file LICENSE_1_0.txt or a copy
+// at <http://www.boost.org/LICENSE_1_0.txt>.)
+
+// See <http://www.boost.org/libs/containers> for the library's home page.
+
+#define BOOST_TEST_MODULE "Hat tests"
+
+#include <boost/containers/hat.hpp>
+
+#include <boost/test/unit_test.hpp> // unit-test framework
+#include <boost/test/output/compiler_log_formatter.hpp> // for new formatter
+#include <boost/mpl/assert.hpp> // for BOOST_MPL_ASSERT
+#include <boost/random/mersenne_twister.hpp> // for boost::mt19937
+#include <boost/type_traits/is_same.hpp> // for boost::is_same
+
+#include <algorithm> // for std::copy, remove, sort, mismatch
+#include <cmath> // for std::abs
+#include <complex> // for std::complex
+#include <ctime> // for std::time
+#include <deque> // for std::deque
+#include <iterator> // for std::ostream_iterator
+#include <map> // for std::map
+#include <memory> // for std::auto_ptr [for xcode_config]
+#include <ostream> // for std::(basic_)ostream [even for xcode_log_formatter]
+
+
+#pragma mark Intro stuff
+
+// Put any using-ed types & templates, and typedefs here
+
+
+// Put custom types/templates, helper functions, and objects here
+namespace
+{
+
+#ifdef __APPLE_CC__
+/* Xcode-compatible logging format, idea by Richard Dingwall at
+ <http://richarddingwall.name/2008/06/01/using-the-boost-unit-test-framework-
+ with-xcode-3/>.
+*/
+class xcode_log_formatter
+ : public boost::unit_test::output::compiler_log_formatter
+{
+protected:
+ virtual void print_prefix( std::ostream &o, boost::unit_test::const_string
+ file, std::size_t line )
+ {
+ o << file << ':' << line << ": ";
+ }
+
+}; // xcode_log_formatter
+
+class xcode_config
+{
+public:
+ xcode_config()
+ {
+ std::auto_ptr<xcode_log_formatter> p( new xcode_log_formatter );
+
+ boost::unit_test::unit_test_log.set_formatter( p.get() );
+ p.release();
+ }
+
+}; // xcode_config
+
+BOOST_GLOBAL_FIXTURE(xcode_config);
+#endif
+
+// Sample wrapping container to inspect what's happening
+template < typename T, class C = std::deque<T>, class R = boost::mt19937 >
+class my_container
+ : public boost::containers::hat<T, C, R>
+{
+ typedef boost::containers::hat<T, C, R> base_type;
+
+public:
+ // Forwarding constructors
+ explicit my_container( R const &e = R(), C const &c = C() )
+ : base_type( e, c ) {}
+
+ template < typename InputIterator >
+ my_container( InputIterator f, InputIterator l, R const &e = R(), C const &c
+ = C() ) : base_type( f, l, e, c ) {}
+
+ // Move the protected members to public for testing
+ using base_type::c;
+ using base_type::engine;
+
+};
+
+template < typename T1, typename T2, class C1, class C2, class R1, class R2 >
+inline bool
+operator ==( my_container<T1,C1,R1> const &l, my_container<T2,C2,R2> const &r )
+{ return ( l.c == r.c ) && ( l.engine() == r.engine() ); }
+
+template < typename T1, typename T2, class C1, class C2, class R1, class R2 >
+inline bool
+operator !=( my_container<T1,C1,R1> const &l, my_container<T2,C2,R2> const &r )
+{ return !operator ==( l, r ); }
+
+template < typename Ch, class Tr, typename T, class C, class R >
+std::basic_ostream<Ch, Tr> &
+operator <<( std::basic_ostream<Ch, Tr> &o, my_container<T, C, R> const &h )
+{
+ o << '[';
+ std::copy( h.c.begin(), h.c.end(), std::ostream_iterator<T>(o, ", ") );
+ return o << h.engine() << ']';
+}
+
+typedef std::complex<double> complexd;
+typedef my_container<complexd> cd_hat;
+
+} // unnamed namespace
+
+
+// Mark any unprintable tested types here
+BOOST_TEST_DONT_PRINT_LOG_VALUE( std::deque<complexd> );
+
+
+#pragma mark -
+#pragma mark Hat Suite
+
+// Test the operations of the hat container adapter
+BOOST_AUTO_TEST_SUITE( hat_suite )
+
+// Initialization and member access
+BOOST_AUTO_TEST_CASE( hat_init_mem_test )
+{
+ using boost::is_same;
+ using boost::mt19937;
+
+ typedef std::deque<complexd> cd_deque;
+
+ // Type checks
+ BOOST_MPL_ASSERT(( is_same<cd_deque, cd_hat::container_type> ));
+ BOOST_MPL_ASSERT(( is_same<mt19937, cd_hat::engine_type> ));
+
+ BOOST_MPL_ASSERT(( is_same<complexd, cd_hat::value_type> ));
+ BOOST_MPL_ASSERT(( is_same<complexd &, cd_hat::reference> ));
+ BOOST_MPL_ASSERT(( is_same<complexd const &, cd_hat::const_reference> ));
+
+ // Default construction
+ cd_hat const c1;
+
+ BOOST_CHECK_EQUAL( c1.c, cd_deque() );
+ BOOST_CHECK_EQUAL( c1.engine(), mt19937() );
+
+ // Member construction
+ cd_hat const c2( mt19937(17u) );
+
+ BOOST_CHECK_EQUAL( c2.c, cd_deque() );
+ BOOST_CHECK_NE( c2.engine(), mt19937() ); // const member access tests
+
+ cd_hat c3( mt19937(21u), cd_deque(3, complexd( 6.0, -8.0 )) );
+
+ BOOST_CHECK_NE( c3.c, cd_deque() );
+ BOOST_CHECK_NE( c3.engine(), mt19937() ); // non-const member access tests
+
+ complexd const samples[ 5 ] = { complexd(6.0, -8.0), complexd(6.0, -8.0),
+ complexd(6.0, -8.0), complexd(-9.0, 2.0), complexd(10.5, 11.0) };
+ cd_hat const c4( samples + 3, samples + 5, mt19937(3u), cd_deque(3,
+ complexd( 6.0, -8.0 )) );
+
+ BOOST_CHECK_NE( c4.c, cd_deque() );
+ BOOST_CHECK_NE( c4.engine(), mt19937() );
+
+ BOOST_CHECK_EQUAL_COLLECTIONS( c3.c.begin(), c3.c.end(), samples, samples +
+ 3 );
+ BOOST_CHECK_EQUAL_COLLECTIONS( c4.c.begin(), c4.c.end(), samples, samples +
+ 5 );
+
+ // Should the copy constructor and the copy-assignment operator be tested?
+ // They're automatically generated by the compiler, so why should I test
+ // code that I didn't have to write?
+}
+
+// Pushing and counting elements
+BOOST_AUTO_TEST_CASE( hat_push_count_test )
+{
+ // Empty
+ cd_hat c1;
+
+ BOOST_CHECK_EQUAL( c1.size(), 0u );
+ BOOST_CHECK( c1.empty() );
+
+ // One element
+ c1.push( complexd(1.0, 2.0) );
+
+ BOOST_CHECK_EQUAL( c1.size(), 1u );
+ BOOST_CHECK( !c1.empty() );
+ BOOST_CHECK_EQUAL( c1.c.back(), complexd(1.0, 2.0) );
+
+ // Two elements
+ c1.push( complexd(-4.5, 3.0) );
+
+ BOOST_CHECK_EQUAL( c1.size(), 2u );
+ BOOST_CHECK_EQUAL( c1.c.back(), complexd(-4.5, 3.0) );
+ BOOST_CHECK_EQUAL( c1.c.front(), complexd(1.0, 2.0) );
+
+ // Three elements
+ complexd const samples[ 3 ] = { complexd(1.0, 2.0), complexd(-4.5, 3.0),
+ complexd(0.0, -5.0) };
+
+ c1.push( samples[2] );
+
+ BOOST_CHECK_EQUAL( c1.size(), 3u );
+ BOOST_CHECK_EQUAL( c1.c.back(), complexd(0.0, -5.0) );
+ BOOST_CHECK_EQUAL( c1.c.front(), complexd(1.0, 2.0) );
+ BOOST_CHECK_EQUAL_COLLECTIONS( c1.c.begin(), c1.c.end(), samples, samples +
+ 3 );
+}
+
+// Choosing, with or without tokens
+BOOST_AUTO_TEST_CASE( hat_choose_and_iterator_test )
+{
+ int const samples[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ int const sample_size = sizeof(samples) / sizeof(samples[0]);
+ cd_hat c1( samples, samples + sample_size );
+ cd_hat const & c2( c1 );
+
+ // Non-mutable access
+ cd_hat::const_token t1 = c2.pick();
+ complexd const &s1 = *t1, &s2 = c2.top();
+
+ BOOST_CHECK_LE( 0, t1->real() );
+ BOOST_CHECK_LE( t1->real(), 9 );
+ BOOST_CHECK_EQUAL( s1.imag(), 0 );
+ BOOST_CHECK_EQUAL( s2.imag(), 0 );
+ BOOST_CHECK_GE( s2.real(), 0 );
+ BOOST_CHECK_GE( 9, s2.real() );
+
+ // Mutable access
+ cd_hat::token t2 = c1.pick();
+ complexd &s3 = *t2, &s4 = c1.top();
+
+ BOOST_CHECK_LE( 0, t2->real() );
+ BOOST_CHECK_LE( t2->real(), 9 );
+ BOOST_CHECK_EQUAL( s3.imag(), 0 );
+ BOOST_CHECK_EQUAL( s4.imag(), 0 );
+ BOOST_CHECK_GE( s4.real(), 0 );
+ BOOST_CHECK_GE( 9, s4.real() );
+
+ // Actually mutate; also check token conversion
+ cd_hat::const_token t3( t2 );
+ complexd const old = *t3;
+
+ BOOST_CHECK_EQUAL( &*t2, &*t3 );
+ *t2 = 15.0;
+ BOOST_CHECK_EQUAL( 15.0, *t3 );
+ *t2 = old;
+ BOOST_CHECK_EQUAL( old, *t3 );
+
+ // Mutable-token comparison
+ cd_hat::token x1 = { c1.c.begin() }, x2 = x1, x3 = { c1.c.end() - 1 };
+
+ BOOST_CHECK( x1 == x2 );
+ BOOST_CHECK( x2 != x3 );
+
+ // Const-token comparison
+ cd_hat::const_token y1 = x3, y2 = y1, y3 = { c2.c.begin() };
+
+ BOOST_CHECK( y1 == y2 );
+ BOOST_CHECK( y2 != y3 );
+
+ // Cross-mutability token comparison, all combinations
+ BOOST_CHECK( t2 == t3 );
+ BOOST_CHECK( !(t3 != t2) );
+ BOOST_CHECK( t3 == t2 );
+ BOOST_CHECK( !(t2 != t3) );
+}
+
+// Choosing and popping elements
+BOOST_AUTO_TEST_CASE( hat_choose_pop_test )
+{
+ typedef int sample_type;
+ typedef my_container<sample_type> container_type;
+
+ int const samples[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ int const sample_size = sizeof(samples) / sizeof(samples[0]);
+ container_type c1( samples, samples + sample_size,
+ boost::mt19937(std::time( 0 )) );
+
+ // Check random sampling trends
+ {
+ typedef long count_type;
+ typedef std::map<sample_type, count_type> map_type;
+
+ map_type counts;
+ count_type const single_trial_size = 10000;
+ count_type const total_trial_size = sample_size * single_trial_size;
+ double const expected_result( single_trial_size );
+
+ for ( count_type i = 0 ; i < total_trial_size ; ++i )
+ ++counts[ c1.top() ];
+
+ BOOST_CHECK_CLOSE( double(counts[0]), expected_result, 5.0 );
+ BOOST_CHECK_CLOSE( double(counts[1]), expected_result, 5.0 );
+ BOOST_CHECK_CLOSE( double(counts[2]), expected_result, 5.0 );
+ BOOST_CHECK_CLOSE( double(counts[3]), expected_result, 5.0 );
+ BOOST_CHECK_CLOSE( double(counts[4]), expected_result, 5.0 );
+ BOOST_CHECK_CLOSE( double(counts[5]), expected_result, 5.0 );
+ BOOST_CHECK_CLOSE( double(counts[6]), expected_result, 5.0 );
+ BOOST_CHECK_CLOSE( double(counts[7]), expected_result, 5.0 );
+ BOOST_CHECK_CLOSE( double(counts[8]), expected_result, 5.0 );
+ BOOST_CHECK_CLOSE( double(counts[9]), expected_result, 5.0 );
+ }
+
+ // Check popping
+ {
+ using std::remove;
+ using std::sort;
+
+ sample_type scratch[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ sample_type *stop = scratch + sizeof(scratch) / sizeof(scratch[0]);
+
+ // Remove via mutable-token
+ container_type::token t1 = c1.pick();
+
+ BOOST_REQUIRE_EQUAL_COLLECTIONS( scratch,stop,c1.c.begin(),c1.c.end() );
+ BOOST_REQUIRE_EQUAL( 1, stop - remove(scratch, stop, *t1) );
+ c1.pop( t1 );
+ sort( c1.c.begin(), c1.c.end() );
+ BOOST_REQUIRE_EQUAL_COLLECTIONS( scratch, --stop, c1.c.begin(),
+ c1.c.end() );
+
+ // Remove via non-mutable-token
+ container_type::const_token t2 = c1.pick();
+
+ BOOST_REQUIRE_EQUAL( 1, stop - remove(scratch, stop, *t2) );
+ c1.pop( t2 );
+ sort( c1.c.begin(), c1.c.end() );
+ BOOST_REQUIRE_EQUAL_COLLECTIONS( scratch, --stop, c1.c.begin(),
+ c1.c.end() );
+
+ // Remove via regular "pop;" the tedious part is determining which
+ // element was removed, so it can be removed from "scratch" too
+ c1.pop();
+ BOOST_REQUIRE_EQUAL( 1, stop - remove(scratch, stop,
+ *std::mismatch( c1.c.begin(), c1.c.end(), scratch ).second) );
+ sort( c1.c.begin(), c1.c.end() );
+ BOOST_REQUIRE_EQUAL_COLLECTIONS( scratch, --stop, c1.c.begin(),
+ c1.c.end() );
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk