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

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