diff --git a/include/boost/assign/list_of.hpp b/include/boost/assign/list_of.hpp index c135b58..07caf1b 100755 --- a/include/boost/assign/list_of.hpp +++ b/include/boost/assign/list_of.hpp @@ -18,6 +18,10 @@ #include #include +#include +#include +#include +#include #include #include #include @@ -44,13 +48,18 @@ namespace boost namespace assign_detail { + ///////////////////////////////////////////////////////////////////////// + // Part 0: common conversion code + ///////////////////////////////////////////////////////////////////////// + template< class T, std::size_t sz > type_traits::yes_type is_array( const array* ); type_traits::no_type is_array( ... ); template< class T, class U > type_traits::yes_type is_pair( const std::pair* ); type_traits::no_type is_pair( ... ); - + + struct array_type_tag { @@ -80,14 +89,138 @@ namespace assign_detail char dummy_; // BCB would by default use 8 bytes #endif }; - + template< class T > + class generic_list; + + template< class Derived > + class converter + { + public: + + template< class Container > + operator Container() const + { + static Container* c = 0; + BOOST_STATIC_CONSTANT( bool, is_array_flag = sizeof( assign_detail::is_array( c ) ) + == sizeof( type_traits::yes_type ) ); + + typedef BOOST_DEDUCED_TYPENAME mpl::if_c< is_array_flag, + array_type_tag, + default_type_tag >::type tag_type; + + return convert( c, tag_type() ); + } + + template< class Container > + Container convert( const Container*, default_type_tag ) const + { + +#if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, == 1) +// old Dinkumware doesn't support iterator type as template + Container result; + BOOST_DEDUCED_TYPENAME Derived::iterator + it = static_cast(this)->begin(); + end = static_cast(this)->end(); + while( it != end ) + { + result.insert( result.end(), *it ); + ++it; + } + return result; +#else + return Container( static_cast(this)->begin(), + static_cast(this)->end() ); +#endif + } + + template< class Array > + Array convert( const Array*, array_type_tag ) const + { + typedef BOOST_DEDUCED_TYPENAME Array::value_type value_type; + Array array; + const std::size_t sz = array.size(); + if( sz < static_cast(this)->size() ) + throw assign::assignment_exception( "array initialized with too many elements" ); + std::size_t n = 0; + BOOST_DEDUCED_TYPENAME Derived::iterator + i = static_cast(this)->begin(), + end = static_cast(this)->end(); + for( ; i != end; ++i, ++n ) + array[n] = *i; + for( ; n < sz; ++n ) + array[n] = value_type(); + return array; + } + + template< class Adapter > + Adapter convert_to_adapter( const Adapter* = 0 ) const + { + Adapter a; + BOOST_DEDUCED_TYPENAME Derived::iterator + i = static_cast(this)->begin(), + end = static_cast(this)->end(); + for( ; i != end; ++i ) + a.push( *i ); + return a; + } + + private: + struct adapter_converter; + friend struct adapter_converter; + + struct adapter_converter + { + const converter& gl; + adapter_converter( const converter& this_ ) : gl( this_ ) + {} + + adapter_converter( const adapter_converter& r ) + : gl( r.gl ) + { } + + template< class Adapter > + operator Adapter() const + { + return gl.convert_to_adapter(); + } + }; + + public: + template< class Container > + Container to_container( Container& c ) const + { + return convert( &c, default_type_tag() ); + } + + adapter_converter to_adapter() const + { + return adapter_converter( *this ); + } + + template< class Adapter > + Adapter to_adapter( Adapter& a ) const + { + return this->convert_to_adapter( &a ); + } + + template< class Array > + Array to_array( Array& a ) const + { + return convert( &a, array_type_tag() ); + } + }; + + ///////////////////////////////////////////////////////////////////////// + // Part 1: flexible, but inefficient interface + ///////////////////////////////////////////////////////////////////////// + template< class T > - class generic_list + class generic_list : public converter< generic_list > { typedef std::deque impl_type; - impl_type values_; + mutable impl_type values_; public: typedef BOOST_DEDUCED_TYPENAME impl_type::iterator iterator; @@ -97,10 +230,8 @@ namespace assign_detail typedef BOOST_DEDUCED_TYPENAME impl_type::difference_type difference_type; public: - iterator begin() { return values_.begin(); } - const_iterator begin() const { return values_.begin(); } - iterator end() { return values_.end(); } - const_iterator end() const { return values_.end(); } + iterator begin() const { return values_.begin(); } + iterator end() const { return values_.end(); } bool empty() const { return values_.empty(); } size_type size() const { return values_.size(); } @@ -160,115 +291,100 @@ namespace assign_detail this->push_back( fun() ); return *this; } - - template< class Container > - operator Container() const - { - static Container* c = 0; - BOOST_STATIC_CONSTANT( bool, is_array_flag = sizeof( assign_detail::is_array( c ) ) - == sizeof( type_traits::yes_type ) ); - - typedef BOOST_DEDUCED_TYPENAME mpl::if_c< is_array_flag, - array_type_tag, - default_type_tag >::type tag_type; - - return convert( c, tag_type() ); - } - - template< class Container > - Container convert( const Container*, default_type_tag ) const - { + }; -#if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, == 1) -// old Dinkumware doesn't support iterator type as template - Container result; - BOOST_DEDUCED_TYPENAME std::deque::const_iterator - it = this->begin(), end = this->end(); - while( it != end ) - { - result.insert( result.end(), *it ); - ++it; - } - return result; -#else - return Container( this->begin(), this->end() ); -#endif - } - - template< class Array > - Array convert( const Array*, array_type_tag ) const + ///////////////////////////////////////////////////////////////////////// + // Part 2: efficient, but inconvenient interface + ///////////////////////////////////////////////////////////////////////// + + template< class T > + struct assign_reference + { + assign_reference() + { } + + assign_reference( T& r ) : ref_(&r) + { } + + void operator=( const assign_reference r ) { - typedef BOOST_DEDUCED_TYPENAME Array::value_type value_type; - Array array; - if( array.size() < this->size() ) - throw assign::assignment_exception( "array initialized with too many elements" ); - std::size_t n = 0; - BOOST_DEDUCED_TYPENAME std::deque::const_iterator - i = this->begin(), end = this->end(); - for( ; i != end; ++i, ++n ) - array[n] = *i; - for( ; n < array.size(); ++n ) - array[n] = value_type(); - return array; + ref_ = r.ref_; } - - template< class Adapter > - Adapter convert_to_adapter( const Adapter* = 0 ) const + + operator T&() const { - Adapter a; - BOOST_DEDUCED_TYPENAME std::deque::const_iterator - i = this->begin(), end = this->end(); - for( ; i != end; ++i ) - a.push( *i ); - return a; + return *ref_; + } + + void swap( assign_reference& r ) + { + std::swap( *ref_, *r.ref_ ); } private: - struct adapter_converter; - friend struct adapter_converter; - - struct adapter_converter + T* ref_; + }; + + template< class T > + void swap( assign_reference& l, assign_reference& r ) + { + l.swap( r ); + } + + + + template< class T, int N > + struct static_generic_list : public converter< static_generic_list > + { + typedef BOOST_DEDUCED_TYPENAME + remove_reference::type internal_value_type; + typedef assign_reference value_type; + typedef value_type* iterator; + typedef const value_type* const_iterator; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + + static_generic_list( T r ) : + current_(1) { - const generic_list& gl; - adapter_converter( const generic_list& this_ ) : gl( this_ ) - {} - - adapter_converter( const adapter_converter& r ) - : gl( r.gl ) - { } - - template< class Adapter > - operator Adapter() const - { - return gl.convert_to_adapter(); - } - }; - - public: - template< class Container > - Container to_container( Container& c ) const - { - return convert( &c, default_type_tag() ); - } - - adapter_converter to_adapter() const - { - return adapter_converter( *this ); - } - - template< class Adapter > - Adapter to_adapter( Adapter& a ) const - { - return this->convert_to_adapter( &a ); + refs_[0] = r; } - template< class Array > - Array to_array( Array& a ) const + static_generic_list& operator()( T r ) { - return convert( &a, array_type_tag() ); + refs_[current_] = r; + ++current_; + return *this; } + + iterator begin() const + { + return &refs_[0]; + } + + iterator end() const + { + return &refs_[current_]; + } + + size_type size() const + { + return static_cast( current_ ); + } + + bool empty() const + { + return false; + } + + private: + static_generic_list(); + + mutable assign_reference refs_[N]; + int current_; }; - + } // namespace 'assign_detail' namespace assign @@ -286,7 +402,15 @@ namespace assign { return assign_detail::generic_list()( t ); } - + + template< int N, class T > + inline assign_detail::static_generic_list + list_of( T t ) + { + // This version is on for reference arguments + //BOOST_STATIC_ASSERT(( boost::is_reference::value && "only reference values allowed" )); + return assign_detail::static_generic_list( t ); + } #define BOOST_PP_LOCAL_LIMITS (1, BOOST_ASSIGN_MAX_PARAMETERS) #define BOOST_PP_LOCAL_MACRO(n) \ diff --git a/test/Jamfile b/test/Jamfile index 4420e64..9d7fc87 100755 --- a/test/Jamfile +++ b/test/Jamfile @@ -1,46 +1,36 @@ +# Boost.Assign library +# +# Copyright Thorsten Ottosen 2003-2005. Use, modification and +# distribution is subject to the Boost Software License, Version +# 1.0. (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) +# +# For more information, see http://www.boost.org/libs/assign/ +# + subproject libs/assign/test ; -SEARCH on testing.jam = $(BOOST_BUILD_PATH) ; -include testing.jam ; +import testing ; -test-suite "assign" - : [ run - basic.cpp - : basic_usage - ] - : [ run - array.cpp - : array - ] - : [ run - std.cpp - : std - ] - : [ run - list_of.cpp - : list_of - ] - : [ run - list_inserter.cpp - : list_inserter - ] - : [ run - list_of_workaround.cpp - : list_of_workaround - ] - : [ run - email_example.cpp - : email - ] - : [ run - my_vector_example.cpp - : my_vector - ] - : [ run - multi_index_container.cpp - : multi_index_container - ] - - ; +rule assign-test ( name ) +{ + return [ + run $(name).cpp + ../../test/build/boost_unit_test_framework + : : : $(BOOST_ROOT) + ] ; +} + +test-suite assign : + [ assign-test basic ] + [ assign-test std ] + [ assign-test list_of ] + [ assign-test static_list_of ] + [ assign-test list_inserter ] + [ assign-test list_of_workaround ] + [ assign-test email_example ] + [ assign-test my_vector_example ] + [ assign-test multi_index_container ] + ; diff --git a/test/TODO b/test/TODO index 37e3046..1098a61 100755 --- a/test/TODO +++ b/test/TODO @@ -30,3 +30,5 @@ 10. Consider adding list_of and iterable_list_of to complement each other. However, for tight code, list_of<7> works pretty well and provides random_access iterators. recursive_list_of(2)(6); + +11. make begin()/end() const members diff --git a/test/array.cpp b/test/array.cpp index bc4d338..ee5be1c 100755 --- a/test/array.cpp +++ b/test/array.cpp @@ -17,7 +17,6 @@ #include #include -#include #include #include #include @@ -69,9 +68,10 @@ void check_array() } -#include -using boost::unit_test_framework::test_suite; +#include +using boost::unit_test::test_suite; + test_suite* init_unit_test_suite( int argc, char* argv[] ) { diff --git a/test/basic.cpp b/test/basic.cpp index 97599de..0efdfa3 100755 --- a/test/basic.cpp +++ b/test/basic.cpp @@ -35,9 +35,8 @@ void check_basic_usage() -#include - -using boost::unit_test_framework::test_suite; +#include +using boost::unit_test::test_suite; test_suite* init_unit_test_suite( int argc, char* argv[] ) { diff --git a/test/email_example.cpp b/test/email_example.cpp index 59534d3..ac81553 100755 --- a/test/email_example.cpp +++ b/test/email_example.cpp @@ -17,7 +17,6 @@ #endif #include -#include #include #include #include @@ -142,10 +141,8 @@ void check_list_inserter() } - -#include - -using boost::unit_test_framework::test_suite; +#include +using boost::unit_test::test_suite; test_suite* init_unit_test_suite( int argc, char* argv[] ) { diff --git a/test/list_inserter.cpp b/test/list_inserter.cpp index 1346f0d..4fd161e 100755 --- a/test/list_inserter.cpp +++ b/test/list_inserter.cpp @@ -18,7 +18,6 @@ #include #include -#include #include #include #include @@ -149,9 +148,8 @@ void check_list_inserter() -#include - -using boost::unit_test_framework::test_suite; +#include +using boost::unit_test::test_suite; test_suite* init_unit_test_suite( int argc, char* argv[] ) { diff --git a/test/list_of.cpp b/test/list_of.cpp index 763c1d3..7e1592d 100755 --- a/test/list_of.cpp +++ b/test/list_of.cpp @@ -17,7 +17,6 @@ #endif #include -#include #include #include #include @@ -232,9 +231,8 @@ void check_list_of() -#include - -using boost::unit_test_framework::test_suite; +#include +using boost::unit_test::test_suite; test_suite* init_unit_test_suite( int argc, char* argv[] ) { diff --git a/test/list_of_workaround.cpp b/test/list_of_workaround.cpp index cb4f02c..ab0388d 100755 --- a/test/list_of_workaround.cpp +++ b/test/list_of_workaround.cpp @@ -17,7 +17,6 @@ #endif #include -#include #include #include #include @@ -44,9 +43,8 @@ void check_list_of() -#include - -using boost::unit_test_framework::test_suite; +#include +using boost::unit_test::test_suite; test_suite* init_unit_test_suite( int argc, char* argv[] ) { diff --git a/test/multi_index_container.cpp b/test/multi_index_container.cpp index 686428a..d7da4be 100755 --- a/test/multi_index_container.cpp +++ b/test/multi_index_container.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -154,9 +153,8 @@ void test_multi_index_container() -#include - -using boost::unit_test_framework::test_suite; +#include +using boost::unit_test::test_suite; test_suite* init_unit_test_suite( int argc, char* argv[] ) { diff --git a/test/my_vector_example.cpp b/test/my_vector_example.cpp index 466509c..234060a 100755 --- a/test/my_vector_example.cpp +++ b/test/my_vector_example.cpp @@ -17,7 +17,6 @@ #endif #include -#include #include #include #include @@ -102,9 +101,8 @@ void check_list_inserter() -#include - -using boost::unit_test_framework::test_suite; +#include +using boost::unit_test::test_suite; test_suite* init_unit_test_suite( int argc, char* argv[] ) { diff --git a/test/static_list_of.cpp b/test/static_list_of.cpp new file mode 100755 index 0000000..9dfe850 --- /dev/null +++ b/test/static_list_of.cpp @@ -0,0 +1,91 @@ +// Boost.Assign library +// +// Copyright Thorsten Ottosen 2003-2004. Use, modification and +// distribution is subject to the Boost Software License, Version +// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// For more information, see http://www.boost.org/libs/assign/ +// + + +#include + +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) +# pragma warn -8091 // supress warning in Boost.Test +# pragma warn -8057 // unused argument argc/argv in Boost.Test +#endif + +#include +#include +#include +#include + +template< class Range > +void print( const Range& r ) +{ + std::cout << "\n printing " << typeid(r).name() << " \n"; + std::cout << "\n"; + for( typename Range::iterator i = r.begin(), e = r.end(); + i !=e; ++i ) + std::cout << " " << *i; +} + +template< class Range > +void sort( const Range& r ) +{ + std::cout << "\n sorting " << typeid(r).name() << " \n"; + std::sort( r.begin(), r.end() ); + print( r ); +} + +template< class Range, class Pred > +void sort( const Range& r, Pred pred ) +{ + std::cout << "\n sorting " << typeid(r).name() << " \n"; + std::sort( r.begin(), r.end(), pred ); + print( r ); +} + +template< class Range > +typename Range::const_iterator max_element( const Range& r ) +{ + return std::max_element( r.begin(), r.end() ); +} + + + +void check_static_list_of() +{ + using namespace boost::assign; + + BOOST_CHECK( list_of<5>( 1 )( 2 )( 3 )( 4 ).size() == 4 ); + + int a=1,b=5,c=3,d=4,e=2,f=9,g=0,h=7; + + int& max = *max_element( list_of<8,int&>(a)(b)(c)(d)(e)(f)(g)(h) ); + BOOST_CHECK_EQUAL( max, f ); + max = 8; + BOOST_CHECK_EQUAL( f, 8 ); + const int& const_max = *max_element( list_of<8,const int&>(a)(b)(c)(d)(e)(f)(g)(h) ); + BOOST_CHECK_EQUAL( max, const_max ); + + // print( list_of<8>(a)(b)(c)(d)(e)(f)(g)(h) ); + sort( list_of<8,int&>(a)(b)(c)(d)(e)(f)(g)(h) ); + print( list_of<8>(a)(b)(c)(d)(e)(f)(g)(h) ); + +} + +#include +using boost::unit_test::test_suite; + +test_suite* init_unit_test_suite( int argc, char* argv[] ) +{ + test_suite* test = BOOST_TEST_SUITE( "List Test Suite" ); + + test->add( BOOST_TEST_CASE( &check_static_list_of ) ); + + return test; +} + + diff --git a/test/std.cpp b/test/std.cpp index 8344cd8..584859d 100755 --- a/test/std.cpp +++ b/test/std.cpp @@ -17,7 +17,6 @@ #endif #include -#include #include #include #include @@ -206,9 +205,8 @@ void check_std() -#include - -using boost::unit_test_framework::test_suite; +#include +using boost::unit_test::test_suite; test_suite* init_unit_test_suite( int argc, char* argv[] ) {