mirror of
https://github.com/boostorg/container.git
synced 2026-07-05 10:30:47 +02:00
424 lines
12 KiB
C++
424 lines
12 KiB
C++
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// (C) Copyright Ion Gaztanaga 2025-2026. 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.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Simple segmented container for testing segmented algorithms.
|
|
// Models a vector-of-vectors with a sentinel empty segment at the end.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
#ifndef BOOST_CONTAINER_TEST_SEGMENTED_TEST_HELPER_HPP
|
|
#define BOOST_CONTAINER_TEST_SEGMENTED_TEST_HELPER_HPP
|
|
|
|
#include <boost/container/experimental/segmented_iterator_traits.hpp>
|
|
#include <boost/container/detail/iterator.hpp>
|
|
#include <boost/container/vector.hpp>
|
|
#include <cstddef>
|
|
#include <iosfwd>
|
|
|
|
namespace test_detail {
|
|
|
|
class movable_int
|
|
{
|
|
BOOST_MOVABLE_BUT_NOT_COPYABLE(movable_int)
|
|
|
|
int val_;
|
|
public:
|
|
explicit movable_int(int v = 0) : val_(v) {}
|
|
movable_int(BOOST_RV_REF(movable_int) other) BOOST_NOEXCEPT
|
|
: val_(other.val_)
|
|
{ other.val_ = -1; }
|
|
|
|
movable_int& operator=(BOOST_RV_REF(movable_int) other) BOOST_NOEXCEPT
|
|
{ val_ = other.val_; other.val_ = -1; return *this; }
|
|
|
|
int value() const { return val_; }
|
|
|
|
friend bool operator==(const movable_int& a, const movable_int& b) { return a.val_ == b.val_; }
|
|
friend bool operator!=(const movable_int& a, const movable_int& b) { return a.val_ != b.val_; }
|
|
friend std::ostream& operator<<(std::ostream& os, const movable_int& m) { return os << m.val_; }
|
|
};
|
|
|
|
template<class T>
|
|
class seg_vector_iterator
|
|
{
|
|
public:
|
|
typedef T value_type;
|
|
typedef T& reference;
|
|
typedef T* pointer;
|
|
typedef std::ptrdiff_t difference_type;
|
|
typedef std::bidirectional_iterator_tag iterator_category;
|
|
|
|
typedef boost::container::vector<boost::container::vector<T> > segments_type;
|
|
typedef typename segments_type::iterator seg_iter_t;
|
|
typedef typename boost::container::vector<T>::iterator local_iter_t;
|
|
|
|
seg_iter_t seg_;
|
|
local_iter_t local_;
|
|
|
|
seg_vector_iterator()
|
|
: seg_(), local_()
|
|
{}
|
|
|
|
seg_vector_iterator(seg_iter_t s, local_iter_t l)
|
|
: seg_(s), local_(l)
|
|
{}
|
|
|
|
reference operator*() const { return *local_; }
|
|
pointer operator->() const { return &*local_; }
|
|
|
|
seg_vector_iterator& operator++()
|
|
{
|
|
++local_;
|
|
if(local_ == seg_->end()) {
|
|
++seg_;
|
|
local_ = seg_->begin();
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
seg_vector_iterator operator++(int)
|
|
{
|
|
seg_vector_iterator tmp = *this;
|
|
++*this;
|
|
return tmp;
|
|
}
|
|
|
|
seg_vector_iterator& operator--()
|
|
{
|
|
if(local_ == seg_->begin()) {
|
|
--seg_;
|
|
local_ = seg_->end();
|
|
}
|
|
--local_;
|
|
return *this;
|
|
}
|
|
|
|
seg_vector_iterator operator--(int)
|
|
{
|
|
seg_vector_iterator tmp = *this;
|
|
--*this;
|
|
return tmp;
|
|
}
|
|
|
|
friend bool operator==(const seg_vector_iterator& a, const seg_vector_iterator& b)
|
|
{ return a.seg_ == b.seg_ && a.local_ == b.local_; }
|
|
|
|
friend bool operator!=(const seg_vector_iterator& a, const seg_vector_iterator& b)
|
|
{ return !(a == b); }
|
|
};
|
|
|
|
template<class T>
|
|
class seg_vector
|
|
{
|
|
// Last entry is always an empty sentinel segment, following
|
|
// the convention from Austern's segmented-iterator paper.
|
|
boost::container::vector<boost::container::vector<T> > segments_;
|
|
|
|
BOOST_COPYABLE_AND_MOVABLE(seg_vector)
|
|
|
|
public:
|
|
typedef seg_vector_iterator<T> iterator;
|
|
|
|
seg_vector()
|
|
{
|
|
segments_.push_back(boost::container::vector<T>());
|
|
}
|
|
|
|
seg_vector(const seg_vector &x)
|
|
: segments_(x.segments_)
|
|
{}
|
|
|
|
seg_vector(BOOST_RV_REF(seg_vector) x)
|
|
: segments_(boost::move(x.segments_))
|
|
{}
|
|
|
|
seg_vector &operator= (BOOST_RV_REF(seg_vector) x)
|
|
{
|
|
segments_ = boost::move(x.segments_);
|
|
return *this;
|
|
}
|
|
|
|
seg_vector &operator= (BOOST_COPY_ASSIGN_REF(seg_vector) x)
|
|
{
|
|
segments_ = x.segments_;
|
|
return *this;
|
|
}
|
|
|
|
void add_segment(std::size_t n, const T& val)
|
|
{
|
|
segments_.insert(segments_.end() - 1, boost::container::vector<T>(n, val));
|
|
}
|
|
|
|
template<class InpIt>
|
|
void add_segment_range(InpIt first, InpIt last)
|
|
{
|
|
segments_.insert(segments_.end() - 1, boost::container::vector<T>(first, last));
|
|
}
|
|
|
|
void add_segment_from_ints(const int* first, const int* last)
|
|
{
|
|
boost::container::vector<T> v;
|
|
v.reserve(static_cast<std::size_t>(last - first));
|
|
for(; first != last; ++first)
|
|
v.push_back(T(*first));
|
|
segments_.insert(segments_.end() - 1, boost::move(v));
|
|
}
|
|
|
|
iterator begin()
|
|
{
|
|
typename boost::container::vector<boost::container::vector<T> >::iterator s = segments_.begin();
|
|
return iterator(s, s->begin());
|
|
}
|
|
|
|
iterator end()
|
|
{
|
|
typename boost::container::vector<boost::container::vector<T> >::iterator s = segments_.end() - 1;
|
|
return iterator(s, s->begin());
|
|
}
|
|
|
|
std::size_t total_size() const
|
|
{
|
|
std::size_t n = 0;
|
|
for(std::size_t i = 0; i + 1 < segments_.size(); ++i)
|
|
n += segments_[i].size();
|
|
return n;
|
|
}
|
|
|
|
boost::container::vector<boost::container::vector<T> >& segments() { return segments_; }
|
|
const boost::container::vector<boost::container::vector<T> >& segments() const { return segments_; }
|
|
};
|
|
|
|
template<class Iter>
|
|
class sentinel_wrapper
|
|
{
|
|
Iter it_;
|
|
public:
|
|
explicit sentinel_wrapper(Iter it) : it_(it) {}
|
|
|
|
operator Iter() const { return it_; }
|
|
|
|
friend bool operator==(const Iter& a, const sentinel_wrapper& b) { return a == b.it_; }
|
|
friend bool operator!=(const Iter& a, const sentinel_wrapper& b) { return !(a == b.it_); }
|
|
friend bool operator==(const sentinel_wrapper& a, const Iter& b) { return a.it_ == b; }
|
|
friend bool operator!=(const sentinel_wrapper& a, const Iter& b) { return !(a.it_ == b); }
|
|
};
|
|
|
|
template<class Iter>
|
|
sentinel_wrapper<Iter> make_sentinel(Iter it) { return sentinel_wrapper<Iter>(it); }
|
|
|
|
template<class Iter>
|
|
class sized_sentinel_wrapper
|
|
{
|
|
Iter it_;
|
|
public:
|
|
explicit sized_sentinel_wrapper(Iter it) : it_(it) {}
|
|
|
|
operator Iter() const { return it_; }
|
|
|
|
friend bool operator==(const Iter& a, const sized_sentinel_wrapper& b) { return a == b.it_; }
|
|
friend bool operator!=(const Iter& a, const sized_sentinel_wrapper& b) { return !(a == b.it_); }
|
|
friend bool operator==(const sized_sentinel_wrapper& a, const Iter& b) { return a.it_ == b; }
|
|
friend bool operator!=(const sized_sentinel_wrapper& a, const Iter& b) { return !(a.it_ == b); }
|
|
|
|
friend typename boost::container::iterator_traits<Iter>::difference_type
|
|
operator-(const sized_sentinel_wrapper& a, const Iter& b) { return a.it_ - b; }
|
|
|
|
friend typename boost::container::iterator_traits<Iter>::difference_type
|
|
operator-(const Iter& a, const sized_sentinel_wrapper& b) { return a - b.it_; }
|
|
};
|
|
|
|
template<class Iter>
|
|
sized_sentinel_wrapper<Iter> make_sized_sentinel(Iter it) { return sized_sentinel_wrapper<Iter>(it); }
|
|
|
|
template<class T>
|
|
class seg2_vector_iterator
|
|
{
|
|
public:
|
|
typedef T value_type;
|
|
typedef T& reference;
|
|
typedef T* pointer;
|
|
typedef std::ptrdiff_t difference_type;
|
|
typedef std::bidirectional_iterator_tag iterator_category;
|
|
|
|
typedef boost::container::vector<seg_vector<T> > segments_type;
|
|
typedef typename segments_type::iterator seg_iter_t;
|
|
typedef seg_vector_iterator<T> local_iter_t;
|
|
|
|
seg_iter_t seg_;
|
|
local_iter_t local_;
|
|
|
|
seg2_vector_iterator()
|
|
: seg_(), local_()
|
|
{}
|
|
|
|
seg2_vector_iterator(seg_iter_t s, local_iter_t l)
|
|
: seg_(s), local_(l)
|
|
{}
|
|
|
|
reference operator*() const { return *local_; }
|
|
pointer operator->() const { return &*local_; }
|
|
|
|
seg2_vector_iterator& operator++()
|
|
{
|
|
++local_;
|
|
if(local_ == seg_->end()) {
|
|
++seg_;
|
|
local_ = seg_->begin();
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
seg2_vector_iterator operator++(int)
|
|
{
|
|
seg2_vector_iterator tmp = *this;
|
|
++*this;
|
|
return tmp;
|
|
}
|
|
|
|
seg2_vector_iterator& operator--()
|
|
{
|
|
if(local_ == seg_->begin()) {
|
|
--seg_;
|
|
local_ = seg_->end();
|
|
}
|
|
--local_;
|
|
return *this;
|
|
}
|
|
|
|
seg2_vector_iterator operator--(int)
|
|
{
|
|
seg2_vector_iterator tmp = *this;
|
|
--*this;
|
|
return tmp;
|
|
}
|
|
|
|
friend bool operator==(const seg2_vector_iterator& a, const seg2_vector_iterator& b)
|
|
{ return a.seg_ == b.seg_ && a.local_ == b.local_; }
|
|
|
|
friend bool operator!=(const seg2_vector_iterator& a, const seg2_vector_iterator& b)
|
|
{ return !(a == b); }
|
|
};
|
|
|
|
template<class T>
|
|
class seg2_vector
|
|
{
|
|
boost::container::vector<seg_vector<T> > segments_;
|
|
|
|
public:
|
|
typedef seg2_vector_iterator<T> iterator;
|
|
|
|
seg2_vector()
|
|
{
|
|
segments_.push_back(seg_vector<T>());
|
|
}
|
|
|
|
void add_segment(const seg_vector<T>& sv)
|
|
{
|
|
segments_.insert(segments_.end() - 1, sv);
|
|
}
|
|
|
|
template<class InpIt>
|
|
void add_flat_segment_range(InpIt first, InpIt last)
|
|
{
|
|
seg_vector<T> sv;
|
|
sv.add_segment_range(first, last);
|
|
segments_.insert(segments_.end() - 1, boost::move(sv));
|
|
}
|
|
|
|
void add_flat_segment_from_ints(const int* first, const int* last)
|
|
{
|
|
seg_vector<T> sv;
|
|
sv.add_segment_from_ints(first, last);
|
|
segments_.insert(segments_.end() - 1, boost::move(sv));
|
|
}
|
|
|
|
iterator begin()
|
|
{
|
|
typename boost::container::vector<seg_vector<T> >::iterator s = segments_.begin();
|
|
return iterator(s, s->begin());
|
|
}
|
|
|
|
iterator end()
|
|
{
|
|
typename boost::container::vector<seg_vector<T> >::iterator s = segments_.end() - 1;
|
|
return iterator(s, s->begin());
|
|
}
|
|
|
|
std::size_t total_size() const
|
|
{
|
|
std::size_t n = 0;
|
|
for(std::size_t i = 0; i + 1 < segments_.size(); ++i)
|
|
n += segments_[i].total_size();
|
|
return n;
|
|
}
|
|
|
|
boost::container::vector<seg_vector<T> >& segments() { return segments_; }
|
|
const boost::container::vector<seg_vector<T> >& segments() const { return segments_; }
|
|
};
|
|
|
|
} // namespace test_detail
|
|
|
|
namespace boost {
|
|
namespace container {
|
|
|
|
template<class T>
|
|
struct segmented_iterator_traits<test_detail::seg_vector_iterator<T> >
|
|
{
|
|
typedef segmented_iterator_tag is_segmented_iterator;
|
|
|
|
typedef typename boost::container::vector<boost::container::vector<T> >::iterator segment_iterator;
|
|
typedef typename boost::container::vector<T>::iterator local_iterator;
|
|
typedef test_detail::seg_vector_iterator<T> iterator;
|
|
|
|
static segment_iterator segment(iterator it) { return it.seg_; }
|
|
static local_iterator local(iterator it) { return it.local_; }
|
|
|
|
static iterator compose(segment_iterator s, local_iterator l)
|
|
{
|
|
if(l == s->end() && !s->empty()) {
|
|
++s;
|
|
l = s->begin();
|
|
}
|
|
return iterator(s, l);
|
|
}
|
|
|
|
static local_iterator begin(segment_iterator s) { return s->begin(); }
|
|
static local_iterator end(segment_iterator s) { return s->end(); }
|
|
};
|
|
|
|
template<class T>
|
|
struct segmented_iterator_traits<test_detail::seg2_vector_iterator<T> >
|
|
{
|
|
typedef segmented_iterator_tag is_segmented_iterator;
|
|
|
|
typedef typename boost::container::vector<test_detail::seg_vector<T> >::iterator segment_iterator;
|
|
typedef test_detail::seg_vector_iterator<T> local_iterator;
|
|
typedef test_detail::seg2_vector_iterator<T> iterator;
|
|
|
|
static segment_iterator segment(iterator it) { return it.seg_; }
|
|
static local_iterator local(iterator it) { return it.local_; }
|
|
|
|
static iterator compose(segment_iterator s, local_iterator l)
|
|
{
|
|
if(l == s->end() && s->total_size() != 0) {
|
|
++s;
|
|
l = s->begin();
|
|
}
|
|
return iterator(s, l);
|
|
}
|
|
|
|
static local_iterator begin(segment_iterator s) { return s->begin(); }
|
|
static local_iterator end(segment_iterator s) { return s->end(); }
|
|
};
|
|
|
|
} // namespace container
|
|
} // namespace boost
|
|
|
|
#endif // BOOST_CONTAINER_TEST_SEGMENTED_TEST_HELPER_HPP
|