Integrate and adapt "devector's", from Thaler Benedek's implementation.

This commit is contained in:
Ion Gaztañaga
2020-08-10 00:16:58 +02:00
parent 844b779a7d
commit ebcd0222b4
20 changed files with 8665 additions and 24 deletions

283
bench/bench_vectors.cpp Normal file
View File

@ -0,0 +1,283 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2007-2013. Distributed under 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)
//
// See http://www.boost.org/libs/container for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifdef _MSC_VER
#pragma warning (disable : 4512)
#pragma warning (disable : 4267)
#pragma warning (disable : 4244)
#endif
#include <vector>
#include <deque>
#include <boost/container/vector.hpp>
#include <boost/container/devector.hpp>
#include <boost/container/deque.hpp>
#include <boost/container/small_vector.hpp>
#include <boost/container/stable_vector.hpp>
#include <memory> //std::allocator
#include <iostream> //std::cout, std::endl
#include <cstring> //std::strcmp
#include <boost/timer/timer.hpp>
#include <typeinfo>
//capacity
#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME capacity
#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG namespace boost { namespace container { namespace test {
#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}}
#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN 0
#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX 0
#include <boost/intrusive/detail/has_member_function_callable_with.hpp>
using boost::timer::cpu_timer;
using boost::timer::cpu_times;
using boost::timer::nanosecond_type;
namespace bc = boost::container;
class MyInt
{
int int_;
public:
explicit MyInt(int i = 0)
: int_(i)
{}
MyInt(const MyInt &other)
: int_(other.int_)
{}
MyInt & operator=(const MyInt &other)
{
int_ = other.int_;
return *this;
}
~MyInt()
{
int_ = 0;
}
};
template<class C, bool = boost::container::test::
has_member_function_callable_with_capacity<C>::value>
struct capacity_wrapper
{
static typename C::size_type get_capacity(const C &c)
{ return c.capacity(); }
static void set_reserve(C &c, typename C::size_type cp)
{ c.reserve(cp); }
};
template<class C>
struct capacity_wrapper<C, false>
{
static typename C::size_type get_capacity(const C &)
{ return 0u; }
static void set_reserve(C &, typename C::size_type )
{ }
};
const std::size_t RangeSize = 5;
struct insert_end_range
{
std::size_t capacity_multiplier() const
{ return RangeSize; }
template<class C>
BOOST_CONTAINER_FORCEINLINE void operator()(C &c, int)
{ c.insert(c.end(), &a[0], &a[0]+RangeSize); }
const char *name() const
{ return "insert_end_range"; }
MyInt a[RangeSize];
};
struct insert_end_repeated
{
std::size_t capacity_multiplier() const
{ return RangeSize; }
template<class C>
BOOST_CONTAINER_FORCEINLINE void operator()(C &c, int i)
{ c.insert(c.end(), RangeSize, MyInt(i)); }
const char *name() const
{ return "insert_end_repeated"; }
MyInt a[RangeSize];
};
struct push_back
{
std::size_t capacity_multiplier() const
{ return 1; }
template<class C>
BOOST_CONTAINER_FORCEINLINE void operator()(C &c, int i)
{ c.push_back(MyInt(i)); }
const char *name() const
{ return "push_back"; }
};
struct emplace_back
{
std::size_t capacity_multiplier() const
{ return 1; }
template<class C>
BOOST_CONTAINER_FORCEINLINE void operator()(C &c, int i)
{ c.emplace_back(MyInt(i)); }
const char *name() const
{ return "emplace_back"; }
};
struct insert_near_end_repeated
{
std::size_t capacity_multiplier() const
{ return RangeSize; }
template<class C>
BOOST_CONTAINER_FORCEINLINE void operator()(C &c, int i)
{ c.insert(c.size() >= RangeSize ? c.end()-RangeSize : c.begin(), RangeSize, MyInt(i)); }
const char *name() const
{ return "insert_near_end_repeated"; }
};
struct insert_near_end_range
{
std::size_t capacity_multiplier() const
{ return RangeSize; }
template<class C>
BOOST_CONTAINER_FORCEINLINE void operator()(C &c, int)
{
c.insert(c.size() >= RangeSize ? c.end()-RangeSize : c.begin(), &a[0], &a[0]+RangeSize);
}
const char *name() const
{ return "insert_near_end_repeated"; }
MyInt a[RangeSize];
};
struct insert_near_end
{
std::size_t capacity_multiplier() const
{ return 1; }
template<class C>
BOOST_CONTAINER_FORCEINLINE void operator()(C &c, int i)
{
typedef typename C::iterator it_t;
it_t it (c.end());
it -= static_cast<typename C::size_type>(!c.empty());
c.insert(it, MyInt(i));
}
const char *name() const
{ return "insert_near_end"; }
};
template<class Container, class Operation>
void vector_test_template(unsigned int num_iterations, unsigned int num_elements, const char *cont_name)
{
cpu_timer timer;
timer.resume();
unsigned int capacity = 0;
Operation op;
typedef capacity_wrapper<Container> cpw_t;
const typename Container::size_type multiplier = op.capacity_multiplier();
for(unsigned int r = 0; r != num_iterations; ++r){
Container c;
cpw_t::set_reserve(c, num_elements);
for(unsigned e = 0, max = num_elements/multiplier; e != max; ++e){
op(c, static_cast<int>(e));
}
capacity = static_cast<unsigned int>(cpw_t::get_capacity(c));
}
timer.stop();
nanosecond_type nseconds = timer.elapsed().wall;
std::cout << cont_name << "->" << op.name() <<" ns: "
<< float(nseconds)/(num_iterations*num_elements)
<< '\t'
<< "Capacity: " << (unsigned int)capacity
<< "\n";
}
template<class Operation>
void test_vectors()
{
//#define SINGLE_TEST
#define SIMPLE_IT
#ifdef SINGLE_TEST
#ifdef NDEBUG
std::size_t numit [] = { 100 };
#else
std::size_t numit [] = { 20 };
#endif
std::size_t numele [] = { 10000 };
#elif defined SIMPLE_IT
std::size_t numit [] = { 100 };
std::size_t numele [] = { 10000 };
#else
#ifdef NDEBUG
unsigned int numit [] = { 1000, 10000, 100000, 1000000 };
#else
unsigned int numit [] = { 100, 1000, 10000, 100000 };
#endif
unsigned int numele [] = { 10000, 1000, 100, 10 };
#endif
for(unsigned int i = 0; i < sizeof(numele)/sizeof(numele[0]); ++i){
vector_test_template< std::vector<MyInt, std::allocator<MyInt> >, Operation >(numit[i], numele[i] , "std::vector ");
vector_test_template< bc::vector<MyInt, std::allocator<MyInt> >, Operation >(numit[i], numele[i] , "vector ");
vector_test_template< bc::devector<MyInt, std::allocator<MyInt> >, Operation >(numit[i], numele[i] , "devector ");
vector_test_template< bc::small_vector<MyInt, 0, std::allocator<MyInt> >, Operation >(numit[i], numele[i] , "small_vector ");
vector_test_template< std::deque<MyInt, std::allocator<MyInt> >, Operation >(numit[i], numele[i] , "std::deque ");
vector_test_template< bc::deque<MyInt, std::allocator<MyInt> >, Operation >(numit[i], numele[i] , "deque ");
}
std::cout << "---------------------------------\n---------------------------------\n";
}
int main()
{
//end
test_vectors<push_back>();
test_vectors<emplace_back>();
test_vectors<insert_end_range>();
test_vectors<insert_end_repeated>();
//near end
test_vectors<insert_near_end>();
test_vectors<insert_near_end_range>();
test_vectors<insert_near_end_repeated>();
return 0;
}

View File

@ -47,12 +47,14 @@ In short, what does [*Boost.Container] offer?
searches.
* [classref boost::container::stable_vector stable_vector]: a std::list and std::vector hybrid
container: vector-like random-access iterators and list-like iterator stability in insertions and erasures.
* [classref boost::container::static_vector static_vector ]: a vector-like container that internally embeds
* [classref boost::container::static_vector static_vector]: a vector-like container that internally embeds
(statically allocates) all needed memory up to the maximum capacity. Maximum capacity can't be increased and
it's specified at compile time.
* [classref boost::container::small_vector small_vector ]: a vector-like container that internally embeds
* [classref boost::container::small_vector small_vector]: a vector-like container that internally embeds
(statically allocates) a minimum amount of memory, but dynamically allocates elements when capacity
has to be increased. This minimum capacity is specified at compile time.
* [classref boost::container::devector devector]: is a hybrid of the standard vector and deque containers.
It offers cheap (amortized constant time) insertion at both the front and back ends.
* [classref boost::container::slist slist]: the classic pre-standard singly linked list implementation
offering constant-time `size()`. Note that C++11 `forward_list` has no `size()`.
@ -458,6 +460,21 @@ erasure times considerably. Flat associative containers have the following attri
[endsect]
[section:devector ['devector]]
`devector` is a hybrid of the standard vector and deque containers originally written by Thaler Benedek.
It offers cheap (amortized constant time) insertion at both the front and back ends,
while also providing the regular features of `vector`, in particular the contiguous underlying memory.
Unlike `vector`, devector can have free capacity both before and after the elements. This enables efficient
implementation of methods that modify the devector at the front. In general, `devector`'s available methods
are a superset of those of `vector` with identical behaviour, barring a couple of iterator invalidation
guarantees that differ.
The overhead for devector is one extra `size_t` per container: Usually sizeof(devector) == 4*sizeof(T*).
[endsect]
[section:slist ['slist]]
When the standard template library was designed, it contained a singly linked list called `slist`.
@ -1306,6 +1323,10 @@ use [*Boost.Container]? There are several reasons for that:
* `static_vector` was based on Andrew Hundt's and Adam Wulkiewicz's high-performance `varray` class.
Many performance improvements of `vector` were also inspired by their implementation. Thanks!
* `devector` is based on Thaler Benedek's high-performance `devector` implementation, then
adapted for [*Boost.Container]. Also inspired by similar implemenations by Orson Peters and Lars Hagen.
Thanks for such a great code and documentation!
* Howard Hinnant's help and advices were essential when implementing move semantics,
improving allocator support or implementing small string optimization. Thanks Howard
for your wonderful standard library implementations.

View File

@ -26,6 +26,7 @@
//! - boost::container::static_vector
//! - boost::container::small_vector_base
//! - boost::container::small_vector
//! - boost::container::devector
//! - boost::container::slist
//! - boost::container::list
//! - boost::container::set
@ -122,6 +123,11 @@ template < class T
, class Options = void >
class small_vector;
template <class T
,class Allocator = void
,class Options = void>
class devector;
template <class T
,class Allocator = void
,class Options = void>

View File

@ -0,0 +1,389 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2005-2014. Distributed under 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)
//
// See http://www.boost.org/libs/container for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_CONTAINER_CONTAINER_FWD_HPP
#define BOOST_CONTAINER_CONTAINER_FWD_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
//! \file
//! This header file forward declares the following containers:
//! - boost::container::vector
//! - boost::container::stable_vector
//! - boost::container::static_vector
//! - boost::container::small_vector_base
//! - boost::container::small_vector
//! - boost::container::slist
//! - boost::container::list
//! - boost::container::set
//! - boost::container::multiset
//! - boost::container::map
//! - boost::container::multimap
//! - boost::container::flat_set
//! - boost::container::flat_multiset
//! - boost::container::flat_map
//! - boost::container::flat_multimap
//! - boost::container::basic_string
//! - boost::container::string
//! - boost::container::wstring
//!
//! Forward declares the following allocators:
//! - boost::container::allocator
//! - boost::container::node_allocator
//! - boost::container::adaptive_pool
//!
//! Forward declares the following polymorphic resource classes:
//! - boost::container::pmr::memory_resource
//! - boost::container::pmr::polymorphic_allocator
//! - boost::container::pmr::monotonic_buffer_resource
//! - boost::container::pmr::pool_options
//! - boost::container::pmr::unsynchronized_pool_resource
//! - boost::container::pmr::synchronized_pool_resource
//!
//! And finally it defines the following types
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
//Std forward declarations
#ifndef BOOST_CONTAINER_DETAIL_STD_FWD_HPP
#include <boost/container/detail/std_fwd.hpp>
#endif
namespace boost{
namespace intrusive{
namespace detail{
//Create namespace to avoid compilation errors
}}}
namespace boost{ namespace container{ namespace dtl{
namespace bi = boost::intrusive;
namespace bid = boost::intrusive::detail;
}}}
namespace boost{ namespace container{ namespace pmr{
namespace bi = boost::intrusive;
namespace bid = boost::intrusive::detail;
}}}
#include <cstddef>
#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
//////////////////////////////////////////////////////////////////////////////
// Containers
//////////////////////////////////////////////////////////////////////////////
namespace boost {
namespace container {
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
template<class T1, class T2>
struct pair;
template<class T>
class new_allocator;
template <class T
,class Allocator = void
,class Options = void>
class vector;
template <class T
,class Allocator = void >
class stable_vector;
template < class T
, std::size_t Capacity
, class Options = void>
class static_vector;
template < class T
, class Allocator = void
, class Options = void >
class small_vector_base;
template < class T
, std::size_t N
, class Allocator = void
, class Options = void >
class small_vector;
template <class T
,class Allocator = void
,class Options = void>
class devector;
template <class T
,class Allocator = void
,class Options = void>
class deque;
template <class T
,class Allocator = void >
class list;
template <class T
,class Allocator = void >
class slist;
template <class Key
,class Compare = std::less<Key>
,class Allocator = void
,class Options = void>
class set;
template <class Key
,class Compare = std::less<Key>
,class Allocator = void
,class Options = void >
class multiset;
template <class Key
,class T
,class Compare = std::less<Key>
,class Allocator = void
,class Options = void >
class map;
template <class Key
,class T
,class Compare = std::less<Key>
,class Allocator = void
,class Options = void >
class multimap;
template <class Key
,class Compare = std::less<Key>
,class Allocator = void >
class flat_set;
template <class Key
,class Compare = std::less<Key>
,class Allocator = void >
class flat_multiset;
template <class Key
,class T
,class Compare = std::less<Key>
,class Allocator = void >
class flat_map;
template <class Key
,class T
,class Compare = std::less<Key>
,class Allocator = void >
class flat_multimap;
#ifndef BOOST_NO_CXX11_TEMPLATE_ALIASES
//! Alias templates for small_flat_[multi]{set|map} using small_vector as container
template < class Key
, std::size_t N
, class Compare = std::less<Key>
, class SmallVectorAllocator = void
, class SmallVectorOptions = void >
using small_flat_set = flat_set<Key, Compare, small_vector<Key, N, SmallVectorAllocator, SmallVectorOptions>>;
template < class Key
, std::size_t N
, class Compare = std::less<Key>
, class SmallVectorAllocator = void
, class SmallVectorOptions = void >
using small_flat_multiset = flat_multiset<Key, Compare, small_vector<Key, N, SmallVectorAllocator, SmallVectorOptions>>;
template < class Key
, class T
, std::size_t N
, class Compare = std::less<Key>
, class SmallVectorAllocator = void
, class SmallVectorOptions = void >
using small_flat_map = flat_map<Key, T, Compare, small_vector<std::pair<Key, T>, N, SmallVectorAllocator, SmallVectorOptions>>;
template < class Key
, class T
, std::size_t N
, class Compare = std::less<Key>
, class SmallVectorAllocator = void
, class SmallVectorOptions = void >
using small_flat_multimap = flat_multimap<Key, T, Compare, small_vector<std::pair<Key, T>, N, SmallVectorAllocator, SmallVectorOptions>>;
#endif // #ifndef BOOST_NO_CXX11_TEMPLATE_ALIASES
//! A portable metafunction to obtain a small_flat_set
template < class Key
, std::size_t N
, class Compare = std::less<Key>
, class SmallVectorAllocator = void
, class SmallVectorOptions = void >
struct small_flat_set_of
{
typedef flat_set<Key, Compare, small_vector<Key, N, SmallVectorAllocator, SmallVectorOptions> > type;
};
//! A portable metafunction to obtain a small_flat_multiset
template < class Key
, std::size_t N
, class Compare = std::less<Key>
, class SmallVectorAllocator = void
, class SmallVectorOptions = void >
struct small_flat_multiset_of
{
typedef flat_multiset<Key, Compare, small_vector<Key, N, SmallVectorAllocator, SmallVectorOptions> > type;
};
//! A portable metafunction to obtain a small_flat_map
template < class Key
, class T
, std::size_t N
, class Compare = std::less<Key>
, class SmallVectorAllocator = void
, class SmallVectorOptions = void >
struct small_flat_map_of
{
typedef flat_map<Key, T, Compare, small_vector<std::pair<Key, T>, N, SmallVectorAllocator, SmallVectorOptions> > type;
};
//! A portable metafunction to obtain a small_flat_multimap
template < class Key
, class T
, std::size_t N
, class Compare = std::less<Key>
, class SmallVectorAllocator = void
, class SmallVectorOptions = void >
struct small_flat_multimap_of
{
typedef flat_multimap<Key, T, Compare, small_vector<std::pair<Key, T>, N, SmallVectorAllocator, SmallVectorOptions> > type;
};
template <class CharT
,class Traits = std::char_traits<CharT>
,class Allocator = void >
class basic_string;
typedef basic_string <char> string;
typedef basic_string<wchar_t> wstring;
static const std::size_t ADP_nodes_per_block = 256u;
static const std::size_t ADP_max_free_blocks = 2u;
static const std::size_t ADP_overhead_percent = 1u;
static const std::size_t ADP_only_alignment = 0u;
template < class T
, std::size_t NodesPerBlock = ADP_nodes_per_block
, std::size_t MaxFreeBlocks = ADP_max_free_blocks
, std::size_t OverheadPercent = ADP_overhead_percent
, unsigned Version = 2
>
class adaptive_pool;
template < class T
, unsigned Version = 2
, unsigned int AllocationDisableMask = 0>
class allocator;
static const std::size_t NodeAlloc_nodes_per_block = 256u;
template
< class T
, std::size_t NodesPerBlock = NodeAlloc_nodes_per_block
, std::size_t Version = 2>
class node_allocator;
namespace pmr {
class memory_resource;
template<class T>
class polymorphic_allocator;
class monotonic_buffer_resource;
struct pool_options;
template <class Allocator>
class resource_adaptor_imp;
class unsynchronized_pool_resource;
class synchronized_pool_resource;
} //namespace pmr {
#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
//! Type used to tag that the input range is
//! guaranteed to be ordered
struct ordered_range_t
{};
//! Value used to tag that the input range is
//! guaranteed to be ordered
static const ordered_range_t ordered_range = ordered_range_t();
//! Type used to tag that the input range is
//! guaranteed to be ordered and unique
struct ordered_unique_range_t
: public ordered_range_t
{};
//! Value used to tag that the input range is
//! guaranteed to be ordered and unique
static const ordered_unique_range_t ordered_unique_range = ordered_unique_range_t();
//! Type used to tag that the inserted values
//! should be default initialized
struct default_init_t
{};
//! Value used to tag that the inserted values
//! should be default initialized
static const default_init_t default_init = default_init_t();
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
//! Type used to tag that the inserted values
//! should be value initialized
struct value_init_t
{};
//! Value used to tag that the inserted values
//! should be value initialized
static const value_init_t value_init = value_init_t();
namespace container_detail_really_deep_namespace {
//Otherwise, gcc issues a warning of previously defined
//anonymous_instance and unique_instance
struct dummy
{
dummy()
{
(void)ordered_range;
(void)ordered_unique_range;
(void)default_init;
}
};
} //detail_really_deep_namespace {
#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
}} //namespace boost { namespace container {
#endif //#ifndef BOOST_CONTAINER_CONTAINER_FWD_HPP

View File

@ -130,7 +130,8 @@ void flat_tree_container_inplace_merge //is_contiguous_container == true
value_type *const braw = boost::movelib::iterator_to_raw_pointer(dest.begin());
value_type *const iraw = boost::movelib::iterator_to_raw_pointer(it);
value_type *const eraw = boost::movelib::iterator_to_raw_pointer(dest.end());
boost::movelib::adaptive_merge(braw, iraw, eraw, comp, eraw, dest.capacity()- dest.size());
boost::movelib::adaptive_merge
(braw, iraw, eraw, comp, eraw, back_free_capacity<SequenceContainer>::get(dest));
}
template<class SequenceContainer, class Compare>
@ -152,7 +153,8 @@ void flat_tree_container_inplace_sort_ending //is_contiguous_container == true
typedef typename SequenceContainer::value_type value_type;
value_type *const iraw = boost::movelib::iterator_to_raw_pointer(it);
value_type *const eraw = boost::movelib::iterator_to_raw_pointer(dest.end());
boost::movelib::adaptive_sort(iraw, eraw, comp, eraw, dest.capacity()- dest.size());
boost::movelib::adaptive_sort
(iraw, eraw, comp, eraw, back_free_capacity<SequenceContainer>::get(dest));
}
template<class SequenceContainer, class Compare>
@ -984,10 +986,7 @@ class flat_tree
ret.first = this->nth(data.position - this->cbegin());
}
else{
typedef typename emplace_functor_type<try_emplace_t, KeyType, Args...>::type func_t;
typedef emplace_iterator<value_type, func_t, difference_type> it_t;
func_t func(try_emplace_t(), ::boost::forward<KeyType>(key), ::boost::forward<Args>(args)...);
ret.first = this->m_data.m_seq.insert(data.position, it_t(func), it_t());
ret.first = this->m_data.m_seq.emplace(data.position, try_emplace_t(), ::boost::forward<KeyType>(key), ::boost::forward<Args>(args)...);
}
return ret;
}
@ -1053,10 +1052,7 @@ class flat_tree
ret.first = this->nth(data.position - this->cbegin());\
}\
else{\
typedef typename emplace_functor_type<try_emplace_t, KeyType BOOST_MOVE_I##N BOOST_MOVE_TARG##N>::type func_t;\
typedef emplace_iterator<value_type, func_t, difference_type> it_t;\
func_t func(try_emplace_t(), ::boost::forward<KeyType>(key) BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\
ret.first = this->m_data.m_seq.insert(data.position, it_t(func), it_t());\
ret.first = this->m_data.m_seq.emplace(data.position, try_emplace_t(), ::boost::forward<KeyType>(key) BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\
}\
return ret;\
}\
@ -1080,10 +1076,7 @@ class flat_tree
ret.first->second = boost::forward<M>(obj);
}
else{
typedef typename emplace_functor_type<KeyType, M>::type func_t;
typedef emplace_iterator<value_type, func_t, difference_type> it_t;
func_t func(boost::forward<KeyType>(key), boost::forward<M>(obj));
ret.first = this->m_data.m_seq.insert(data.position, it_t(func), it_t());
ret.first = this->m_data.m_seq.emplace(data.position, boost::forward<KeyType>(key), boost::forward<M>(obj));
}
return ret;
}

View File

@ -0,0 +1,198 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Benedek Thaler 2015-2016
// (C) Copyright Ion Gaztanaga 2019-2020. Distributed under 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)
//
// See http://erenon.hu/container for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_CONTAINER_DETAIL_GUARDS_HPP
#define BOOST_CONTAINER_DETAIL_GUARDS_HPP
#include <boost/container/detail/config_begin.hpp>
#include <boost/container/detail/workaround.hpp>
#include <boost/move/core.hpp> // BOOST_MOVABLE_BUT_NOT_COPYABLE
// move/detail
#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
#include <boost/move/detail/fwd_macros.hpp>
#endif
#include <boost/container/allocator_traits.hpp>
namespace boost {
namespace container {
namespace detail {
class null_construction_guard
{
public:
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
template <typename... Args>
null_construction_guard(Args&&...) {}
#else
#define NULL_CONSTRUCTION_GUARD_CODE(N) \
BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \
BOOST_CONTAINER_FORCEINLINE null_construction_guard(BOOST_MOVE_UREFANON##N)\
{}\
//
BOOST_MOVE_ITERATE_0TO9(NULL_CONSTRUCTION_GUARD_CODE)
#undef NULL_CONSTRUCTION_GUARD_CODE
#endif
void release() {}
void extend() {}
};
template <typename Allocator>
class construction_guard
{
typedef typename boost::container::allocator_traits<Allocator>::pointer pointer;
typedef typename boost::container::allocator_traits<Allocator>::size_type size_type;
BOOST_MOVABLE_BUT_NOT_COPYABLE(construction_guard)
public:
construction_guard()
: _alloc_ptr()
, _elem_count()
, _allocator()
{}
construction_guard(pointer alloc_ptr, Allocator& allocator)
:_alloc_ptr(alloc_ptr)
, _elem_count(0)
, _allocator(&allocator)
{}
construction_guard(BOOST_RV_REF(construction_guard) rhs)
:_alloc_ptr(rhs._alloc_ptr)
, _elem_count(rhs._elem_count)
, _allocator(rhs._allocator)
{
rhs._elem_count = 0;
}
~construction_guard()
{
while (_elem_count) {
--_elem_count;
boost::container::allocator_traits<Allocator>::destroy(*_allocator, _alloc_ptr++);
}
}
void release()
{
_elem_count = 0;
}
void extend()
{
++_elem_count;
}
private:
pointer _alloc_ptr;
size_type _elem_count;
Allocator* _allocator;
};
/**
* Has two ranges
*
* On success, destroys the first range (src),
* on failure, destroys the second range (dst).
*
* Can be used when copying/moving a range
*/
template <class Allocator>
class nand_construction_guard
{
typedef typename boost::container::allocator_traits<Allocator>::pointer pointer;
typedef typename boost::container::allocator_traits<Allocator>::size_type size_type;
construction_guard<Allocator> _src;
construction_guard<Allocator> _dst;
bool _dst_released;
public:
nand_construction_guard()
: _src()
, _dst()
, _dst_released(false)
{}
nand_construction_guard( pointer src, Allocator& src_alloc
, pointer dst, Allocator& dst_alloc)
:_src(src, src_alloc),
_dst(dst, dst_alloc),
_dst_released(false)
{}
void extend()
{
_src.extend();
_dst.extend();
}
void release() // on success
{
_dst.release();
_dst_released = true;
}
~nand_construction_guard()
{
if (! _dst_released) { _src.release(); }
}
};
template <typename Allocator>
class allocation_guard
{
typedef typename boost::container::allocator_traits<Allocator>::pointer pointer;
typedef typename boost::container::allocator_traits<Allocator>::size_type size_type;
BOOST_MOVABLE_BUT_NOT_COPYABLE(allocation_guard)
public:
allocation_guard(pointer alloc_ptr, size_type alloc_size, Allocator& allocator)
:_alloc_ptr(alloc_ptr),
_alloc_size(alloc_size),
_allocator(allocator)
{}
~allocation_guard()
{
if (_alloc_ptr)
{
boost::container::allocator_traits<Allocator>::deallocate(_allocator, _alloc_ptr, _alloc_size);
}
}
void release()
{
_alloc_ptr = 0;
}
private:
pointer _alloc_ptr;
size_type _alloc_size;
Allocator& _allocator;
};
}}} // namespace boost::container::detail
#include <boost/container/detail/config_end.hpp>
#endif // BOOST_CONTAINER_DETAIL_GUARDS_HPP

File diff suppressed because it is too large Load Diff

View File

@ -215,6 +215,13 @@ class default_next_capacity;
typedef vector_opt<void, void> vector_null_opt;
template<class GrowthType, class StoredSizeType>
struct devector_opt
: vector_opt<GrowthType, StoredSizeType>
{};
typedef devector_opt<void, void> devector_null_opt;
#else //!defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
//!This growth factor argument specifies that the container should increase it's
@ -442,6 +449,40 @@ using static_vector_options_t = typename boost::container::static_vector_options
#endif
//! Helper metafunction to combine options into a single type to be used
//! by \c boost::container::devector.
//! Supported options are: \c boost::container::growth_factor and \c boost::container::stored_size
#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) || defined(BOOST_CONTAINER_VARIADIC_TEMPLATES)
template<class ...Options>
#else
template<class O1 = void, class O2 = void, class O3 = void, class O4 = void>
#endif
struct devector_options
{
/// @cond
typedef typename ::boost::intrusive::pack_options
< devector_null_opt,
#if !defined(BOOST_CONTAINER_VARIADIC_TEMPLATES)
O1, O2, O3, O4
#else
Options...
#endif
>::type packed_options;
typedef devector_opt< typename packed_options::growth_factor_type
, typename packed_options::stored_size_type> implementation_defined;
/// @endcond
typedef implementation_defined type;
};
#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES)
//! Helper alias metafunction to combine options into a single type to be used
//! by \c boost::container::devector.
//! Supported options are: \c boost::container::growth_factor and \c boost::container::stored_size
template<class ...Options>
using devector_options_t = typename boost::container::devector_options<Options...>::type;
#endif
////////////////////////////////////////////////////////////////
//

View File

@ -0,0 +1,51 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under 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)
//
// See http://www.boost.org/libs/container for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_CONTAINER_PMR_VECTOR_HPP
#define BOOST_CONTAINER_PMR_VECTOR_HPP
#if defined (_MSC_VER)
# pragma once
#endif
#include <boost/container/devector.hpp>
#include <boost/container/pmr/polymorphic_allocator.hpp>
namespace boost {
namespace container {
namespace pmr {
#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES)
template <
typename T,
typename GrowthPolicy = growth_factor_60
>
using devector = boost::container::devector<T, GrowthPolicy, polymorphic_allocator<T> >;
#endif
//! A portable metafunction to obtain a vector
//! that uses a polymorphic allocator
template <
typename T,
typename GrowthPolicy = growth_factor_60
>
struct devector_of
{
typedef boost::container::devector
< T, GrowthPolicy, polymorphic_allocator<T> > type;
};
} //namespace pmr {
} //namespace container {
} //namespace boost {
#endif //BOOST_CONTAINER_PMR_VECTOR_HPP

View File

@ -39,10 +39,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "flat_set_test", "flat_set_t
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hash_table_test", "hash_table_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792606}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "list_test", "list_test.vcproj", "{58CCE183-6092-48FE-A4F7-BA0D3A792632}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
@ -383,10 +379,6 @@ Global
{58CCE183-6092-48FE-A4F7-BA0D3A792637}.Debug.Build.0 = Debug|Win32
{58CCE183-6092-48FE-A4F7-BA0D3A792637}.Release.ActiveCfg = Release|Win32
{58CCE183-6092-48FE-A4F7-BA0D3A792637}.Release.Build.0 = Release|Win32
{58CCE183-6092-48FE-A4F7-BA0D3A792606}.Debug.ActiveCfg = Debug|Win32
{58CCE183-6092-48FE-A4F7-BA0D3A792606}.Debug.Build.0 = Debug|Win32
{58CCE183-6092-48FE-A4F7-BA0D3A792606}.Release.ActiveCfg = Release|Win32
{58CCE183-6092-48FE-A4F7-BA0D3A792606}.Release.Build.0 = Release|Win32
{58CCE183-6092-48FE-A4F7-BA0D3A792632}.Debug.ActiveCfg = Debug|Win32
{58CCE183-6092-48FE-A4F7-BA0D3A792632}.Debug.Build.0 = Debug|Win32
{58CCE183-6092-48FE-A4F7-BA0D3A792632}.Release.ActiveCfg = Release|Win32

View File

@ -0,0 +1,121 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2004-2013. Distributed under 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)
//
// See http://www.boost.org/libs/container for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#include <boost/container/devector.hpp>
#include <boost/container/allocator.hpp>
#include <boost/container/detail/next_capacity.hpp>
#include <boost/core/lightweight_test.hpp>
using namespace boost::container;
template<class Unsigned, class DevectorType>
void test_stored_size_type_impl()
{
DevectorType v;
typedef typename DevectorType::size_type size_type;
typedef typename DevectorType::value_type value_type;
size_type const max = Unsigned(-1);
v.resize(5);
v.resize(max);
BOOST_TEST_THROWS(v.resize(max+1), std::exception);
BOOST_TEST_THROWS(v.push_back(value_type(1)), std::exception);
BOOST_TEST_THROWS(v.insert(v.begin(), value_type(1)), std::exception);
BOOST_TEST_THROWS(v.emplace(v.begin(), value_type(1)),std::exception);
BOOST_TEST_THROWS(v.reserve(max+1), std::exception);
BOOST_TEST_THROWS(DevectorType v2(max+1), std::exception);
}
template<class Unsigned>
void test_stored_size_type()
{
#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES)
using options_t = devector_options_t< stored_size<Unsigned> >;
#else
typedef typename devector_options
< stored_size<Unsigned> >::type options_t;
#endif
//Test first with a typical allocator
{
typedef devector<unsigned char, new_allocator<unsigned char>, options_t> devector_t;
test_stored_size_type_impl<Unsigned, devector_t>();
}
//Test with a V2 allocator
{
typedef devector<unsigned char, allocator<unsigned char>, options_t> devector_t;
test_stored_size_type_impl<Unsigned, devector_t>();
}
}
void test_growth_factor_50()
{
#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES)
using options_t = devector_options_t< growth_factor<growth_factor_50> >;
#else
typedef devector_options
< growth_factor<growth_factor_50> >::type options_t;
#endif
devector<int, new_allocator<int>, options_t> v;
v.resize(5);
v.resize(v.capacity());
std::size_t old_capacity = v.capacity();
v.push_back(0);
std::size_t new_capacity = v.capacity();
BOOST_TEST(new_capacity == old_capacity + old_capacity/2);
}
void test_growth_factor_60()
{
#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES)
using options_t = devector_options_t< growth_factor<growth_factor_60> >;
#else
typedef devector_options
< growth_factor<growth_factor_60> >::type options_t;
#endif
devector<int, new_allocator<int>, options_t> v;
v.resize(5);
v.resize(v.capacity());
std::size_t old_capacity = v.capacity();
v.push_back(0);
std::size_t new_capacity = v.capacity();
BOOST_TEST(new_capacity == old_capacity + 3*old_capacity/5);
}
void test_growth_factor_100()
{
#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES)
using options_t = devector_options_t< growth_factor<growth_factor_100> >;
#else
typedef devector_options
< growth_factor<growth_factor_100> >::type options_t;
#endif
devector<int, new_allocator<int>, options_t> v;
v.resize(5);
v.resize(v.capacity());
std::size_t old_capacity = v.capacity();
v.push_back(0);
std::size_t new_capacity = v.capacity();
BOOST_TEST(new_capacity == 2*old_capacity);
}
int main()
{
test_growth_factor_50();
test_growth_factor_60();
test_growth_factor_100();
test_stored_size_type<unsigned char>();
test_stored_size_type<unsigned short>();
return ::boost::report_errors();
}

3932
test/devector_test.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,41 @@
//////////////////////////////////////////////////////////////////////////////
//
// \(C\) Copyright Benedek Thaler 2015-2016
// \(C\) Copyright Ion Gaztanaga 2019-2020. Distributed under 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)
//
// See http://www.boost.org/libs/container for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#include <boost/container/devector.hpp>
#include "movable_int.hpp"
struct empty
{
friend bool operator == (const empty &, const empty &){ return true; }
friend bool operator < (const empty &, const empty &){ return true; }
};
template class ::boost::container::devector<empty>;
namespace boost {
namespace container {
//Test stored_size option
template class devector< test::movable_and_copyable_int
, new_allocator<test::movable_and_copyable_int>
, devector_options< stored_size<unsigned short> >::type
>;
} //namespace container {
} //namespace boost {
int main()
{
::boost::container::devector<empty> dummy;
(void)dummy;
return 0;
}

View File

@ -12,6 +12,7 @@
#include <boost/container/static_vector.hpp>
#include <boost/container/stable_vector.hpp>
#include <boost/container/vector.hpp>
#include <boost/container/devector.hpp>
#include <boost/container/deque.hpp>
#include <boost/static_assert.hpp>
@ -99,6 +100,15 @@ int main()
std::cout << "Error in map_test<deque<std::pair<int, int> > >" << std::endl;
return 1;
}
if (0 != test::map_test
< GetMapContainer<devector<std::pair<int, int> > >::apply<int>::map_type
, MyStdMap
, GetMapContainer<devector<std::pair<int, int> > >::apply<int>::multimap_type
, MyStdMultiMap>()) {
std::cout << "Error in map_test<vector<std::pair<int, int> > >" << std::endl;
return 1;
}
}
{
using namespace boost::container;

View File

@ -13,6 +13,7 @@
#include <boost/container/stable_vector.hpp>
#include <boost/container/vector.hpp>
#include <boost/container/deque.hpp>
#include <boost/container/devector.hpp>
#include <boost/static_assert.hpp>
#include <boost/container/detail/container_or_allocator_rebind.hpp>
@ -96,6 +97,14 @@ int main()
std::cout << "Error in set_test<deque<int> >" << std::endl;
return 1;
}
if (0 != test::set_test
< GetSetContainer<devector<int> >::apply<int>::set_type
, MyStdSet
, GetSetContainer<devector<int> >::apply<int>::multiset_type
, MyStdMultiSet>()) {
std::cout << "Error in set_test<deque<int> >" << std::endl;
return 1;
}
}
{
using namespace boost::container;

119
test/input_iterator.hpp Normal file
View File

@ -0,0 +1,119 @@
//////////////////////////////////////////////////////////////////////////////
//
// \(C\) Copyright Benedek Thaler 2015-2016
// \(C\) Copyright Ion Gaztanaga 2019-2020. Distributed under 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)
//
// See http://erenon.hu/double_ended for documentation.
//
//////////////////////////////////////////////////////////////////////////////
/**
* Emulates input iterator, validates algorithm
* does a single pass only, removes visited elements.
*
* Container::erase(front_iterator) must not invalidate other iterators.
*
* The hack around `_erase_on_destroy` is required to make `*it++` work.
*/
template <typename Container>
class input_iterator
{
typedef typename Container::iterator iterator;
public:
typedef std::input_iterator_tag iterator_category;
typedef typename Container::value_type value_type;
typedef typename Container::pointer pointer;
typedef typename Container::reference reference;
typedef typename Container::difference_type difference_type;
struct erase_on_destroy {};
public:
input_iterator()
: _container()
, _it()
, _erase_on_destroy()
{}
input_iterator(Container& c, iterator it)
:_container(&c)
, _it(it)
, _erase_on_destroy()
{}
input_iterator(const input_iterator& rhs)
:_container(rhs._container),
_it(rhs._it),
_erase_on_destroy(rhs._erase_on_destroy)
{
rhs._erase_on_destroy = false;
}
input_iterator & operator=(const input_iterator& rhs)
{
_container = rhs._container;
_it = rhs._it;
_erase_on_destroy = rhs._erase_on_destroy;
rhs._erase_on_destroy = false;
return *this;
}
input_iterator(const input_iterator& rhs, erase_on_destroy)
:_container(rhs._container),
_it(rhs._it),
_erase_on_destroy(true)
{}
~input_iterator()
{
if (_erase_on_destroy)
{
_container->erase(_it); // must not invalidate other iterators
}
}
const value_type& operator*()
{
return *_it;
}
input_iterator operator++()
{
_container->erase(_it);
++_it;
return *this;
}
input_iterator operator++(int)
{
input_iterator old(*this, erase_on_destroy());
++_it;
return old;
}
friend bool operator==(const input_iterator a, const input_iterator b)
{
return a._it == b._it;
}
friend bool operator!=(const input_iterator a, const input_iterator b)
{
return !(a == b);
}
private:
Container* _container;
iterator _it;
mutable bool _erase_on_destroy;
};
template <typename Container>
input_iterator<Container> make_input_iterator(Container& c, typename Container::iterator it)
{
return input_iterator<Container>(c, it);
}

View File

@ -0,0 +1,26 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under 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)
//
// See http://www.boost.org/libs/container for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#include <boost/container/pmr/devector.hpp>
#include <boost/static_assert.hpp>
#include <boost/container/detail/type_traits.hpp>
int main()
{
using namespace boost::container;
using boost::container::dtl::is_same;
typedef devector<int, growth_factor_60, pmr::polymorphic_allocator<int> > intcontainer_t;
BOOST_STATIC_ASSERT(( is_same<intcontainer_t, pmr::devector_of<int>::type >::value ));
#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES)
BOOST_STATIC_ASSERT(( is_same<intcontainer_t, pmr::devector<int> >::value ));
#endif
return 0;
}

319
test/test_elem.hpp Normal file
View File

@ -0,0 +1,319 @@
//////////////////////////////////////////////////////////////////////////////
//
// \(C\) Copyright Benedek Thaler 2015-2016
// \(C\) Copyright Ion Gaztanaga 2019-2020. Distributed under 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)
//
// See http://erenon.hu/double_ended for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_CONTAINER_TEST_TEST_ELEM_HPP
#define BOOST_CONTAINER_TEST_TEST_ELEM_HPP
#include <boost/utility/compare_pointees.hpp>
namespace boost {
namespace container {
struct test_exception {};
struct test_elem_throw
{
private:
static int throw_on_ctor_after /*= -1*/;
static int throw_on_copy_after /*= -1*/;
static int throw_on_move_after /*= -1*/;
public:
static void on_ctor_after(int x) { throw_on_ctor_after = x; }
static void on_copy_after(int x) { throw_on_copy_after = x; }
static void on_move_after(int x) { throw_on_move_after = x; }
static void do_not_throw()
{
throw_on_ctor_after = -1;
throw_on_copy_after = -1;
throw_on_move_after = -1;
}
static void in_constructor() { maybe_throw(throw_on_ctor_after); }
static void in_copy() { maybe_throw(throw_on_copy_after); }
static void in_move() { maybe_throw(throw_on_move_after); }
private:
static void maybe_throw(int& counter)
{
if (counter > 0)
{
--counter;
if (counter == 0)
{
--counter;
throw test_exception();
}
}
}
};
int test_elem_throw::throw_on_ctor_after = -1;
int test_elem_throw::throw_on_copy_after = -1;
int test_elem_throw::throw_on_move_after = -1;
struct test_elem_base
{
private:
BOOST_COPYABLE_AND_MOVABLE(test_elem_base)
public:
test_elem_base()
{
test_elem_throw::in_constructor();
_index = new int(0);
++_live_count;
}
test_elem_base(int index)
{
test_elem_throw::in_constructor();
_index = new int(index);
++_live_count;
}
explicit test_elem_base(const test_elem_base& rhs)
{
test_elem_throw::in_copy();
_index = new int(*rhs._index);
++_live_count;
}
test_elem_base(BOOST_RV_REF(test_elem_base) rhs)
{
test_elem_throw::in_move();
_index = rhs._index;
rhs._index = 0;
++_live_count;
}
test_elem_base &operator=(BOOST_COPY_ASSIGN_REF(test_elem_base) rhs)
{
test_elem_throw::in_copy();
if (_index) { delete _index; }
_index = new int(*rhs._index);
return *this;
}
test_elem_base &operator=(BOOST_RV_REF(test_elem_base) rhs)
{
test_elem_throw::in_move();
if (_index) { delete _index; }
_index = rhs._index;
rhs._index = 0;
return *this;
}
~test_elem_base()
{
if (_index) { delete _index; }
--_live_count;
}
friend bool operator==(const test_elem_base& a, const test_elem_base& b)
{
return a._index && b._index && *(a._index) == *(b._index);
}
friend bool operator==(int a, const test_elem_base& b)
{
return b._index != 0 && a == *(b._index);
}
friend bool operator==(const test_elem_base& a, int b)
{
return a._index != 0 && *(a._index) == b;
}
friend bool operator<(const test_elem_base& a, const test_elem_base& b)
{
return boost::less_pointees(a._index, b._index);
}
friend std::ostream& operator<<(std::ostream& out, const test_elem_base& elem)
{
if (elem._index) { out << *elem._index; }
else { out << "null"; }
return out;
}
template <typename Archive>
void serialize(Archive& ar, unsigned /* version */)
{
ar & *_index;
}
static bool no_living_elem()
{
return _live_count == 0;
}
private:
int* _index;
static int _live_count;
};
int test_elem_base::_live_count = 0;
struct regular_elem : test_elem_base
{
private:
BOOST_COPYABLE_AND_MOVABLE(regular_elem)
public:
regular_elem()
{}
regular_elem(int index) : test_elem_base(index) {}
regular_elem(const regular_elem& rhs)
:test_elem_base(rhs)
{}
regular_elem(BOOST_RV_REF(regular_elem) rhs)
:test_elem_base(BOOST_MOVE_BASE(test_elem_base, rhs))
{}
regular_elem &operator=(BOOST_COPY_ASSIGN_REF(regular_elem) rhs)
{
static_cast<test_elem_base&>(*this) = rhs;
return *this;
}
regular_elem &operator=(BOOST_RV_REF(regular_elem) rhs)
{
regular_elem &r = rhs;
static_cast<test_elem_base&>(*this) = boost::move(r);
return *this;
}
};
struct noex_move : test_elem_base
{
private:
BOOST_COPYABLE_AND_MOVABLE(noex_move)
public:
noex_move()
{}
noex_move(int index) : test_elem_base(index) {}
noex_move(const noex_move& rhs)
:test_elem_base(rhs)
{}
noex_move(BOOST_RV_REF(noex_move) rhs) BOOST_NOEXCEPT
:test_elem_base(BOOST_MOVE_BASE(test_elem_base, rhs))
{}
noex_move &operator=(BOOST_COPY_ASSIGN_REF(noex_move) rhs)
{
static_cast<test_elem_base&>(*this) = rhs;
return *this;
}
noex_move &operator=(BOOST_RV_REF(noex_move) rhs) BOOST_NOEXCEPT
{
noex_move & r = rhs;
static_cast<test_elem_base&>(*this) = boost::move(r);
return *this;
}
};
struct noex_copy : test_elem_base
{
private:
BOOST_COPYABLE_AND_MOVABLE(noex_copy)
public:
noex_copy(){}
noex_copy(int index) : test_elem_base(index) {}
noex_copy(const noex_copy& rhs) BOOST_NOEXCEPT
:test_elem_base(rhs)
{}
noex_copy(BOOST_RV_REF(noex_copy) rhs)
:test_elem_base(BOOST_MOVE_BASE(test_elem_base, rhs))
{}
noex_copy &operator=(BOOST_COPY_ASSIGN_REF(noex_copy) rhs) BOOST_NOEXCEPT
{
static_cast<test_elem_base&>(*this) = rhs;
return *this;
}
noex_copy &operator=(BOOST_RV_REF(noex_copy) rhs)
{
noex_copy &r = rhs;
static_cast<test_elem_base&>(*this) = boost::move(r);
return *this;
}
};
struct only_movable : test_elem_base
{
private:
BOOST_MOVABLE_BUT_NOT_COPYABLE(only_movable)
public:
only_movable(){};
only_movable(int index) : test_elem_base(index) {}
only_movable(BOOST_RV_REF(only_movable) rhs)
:test_elem_base(BOOST_MOVE_BASE(test_elem_base, rhs))
{}
only_movable &operator=(BOOST_RV_REF(only_movable) rhs)
{
static_cast<test_elem_base&>(*this) = boost::move(rhs);
return *this;
}
};
struct no_default_ctor : test_elem_base
{
private:
BOOST_COPYABLE_AND_MOVABLE(no_default_ctor)
public:
no_default_ctor(int index) : test_elem_base(index) {}
no_default_ctor(const no_default_ctor& rhs)
:test_elem_base(rhs)
{}
no_default_ctor(BOOST_RV_REF(no_default_ctor) rhs)
:test_elem_base(BOOST_MOVE_BASE(test_elem_base, rhs))
{}
no_default_ctor &operator=(BOOST_RV_REF(no_default_ctor) rhs)
{
static_cast<test_elem_base&>(*this) = boost::move(rhs);
return *this;
}
no_default_ctor &operator=(BOOST_COPY_ASSIGN_REF(no_default_ctor) rhs)
{
static_cast<test_elem_base&>(*this) = rhs;
return *this;
}
};
}}
#endif //BOOST_CONTAINER_TEST_TEST_ELEM_HPP

139
test/test_util.hpp Normal file
View File

@ -0,0 +1,139 @@
//////////////////////////////////////////////////////////////////////////////
//
// \(C\) Copyright Benedek Thaler 2015-2016
// \(C\) Copyright Ion Gaztanaga 2019-2020. Distributed under 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)
//
// See http://erenon.hu/double_ended for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_CONTAINER_TEST_TEST_UTIL_HPP
#define BOOST_CONTAINER_TEST_TEST_UTIL_HPP
#include "test_elem.hpp"
// get_range
template <typename DeVector>
void get_range(int fbeg, int fend, int bbeg, int bend, DeVector &c)
{
c.clear();
for (int i = fend; i > fbeg ;)
{
c.emplace_front(--i);
}
for (int i = bbeg; i < bend; ++i)
{
c.emplace_back(i);
}
}
template <typename Container>
void get_range(int count, Container &c)
{
c.clear();
for (int i = 1; i <= count; ++i)
{
c.emplace_back(i);
}
}
template <typename Container>
void get_range(Container &c)
{
get_range<Container>(1, 13, 13, 25, c);
}
template <typename C1>
void test_equal_range(const C1& a)
{
BOOST_TEST(a.empty());
}
template <typename Iterator>
void print_range(std::ostream& out, Iterator b, Iterator e)
{
out << '[';
bool first = true;
for (; b != e; ++b)
{
if (first) { first = false; }
else { out << ','; }
out << *b;
}
out << ']';
}
template <typename Range>
void print_range(std::ostream& out, const Range& range)
{
print_range(out, range.cbegin(), range.cend());
}
template <typename Array, std::size_t N>
void print_range(std::ostream& out, Array (&range)[N])
{
print_range(out, range, range + N);
}
template <typename C1, typename C2, unsigned N>
void test_equal_range(const C1& a, const C2 (&b)[N])
{
bool equals = boost::algorithm::equal
(a.begin(), a.end(), b, b+N);
BOOST_TEST(equals);
if (!equals)
{
print_range(std::cerr, a);
std::cerr << "\n";
print_range(std::cerr, b);
std::cerr << "\n";
}
}
template <typename C1, typename C2>
void test_equal_range(const C1& a, const C2&b)
{
bool equals = boost::algorithm::equal
(a.begin(), a.end(), b.begin(), b.end());
BOOST_TEST(equals);
if (!equals)
{
print_range(std::cerr, a);
std::cerr << "\n";
print_range(std::cerr, b);
std::cerr << "\n";
}
}
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
// support initializer_list
template <typename C>
void test_equal_range(const C& a, std::initializer_list<unsigned> il)
{
typedef typename C::value_type T;
boost::container::vector<T> b;
for (auto&& elem : il)
{
b.emplace_back(elem);
}
test_equal_range(a, b);
}
#endif //#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
#endif //BOOST_CONTAINER_TEST_TEST_UTIL_HPP