mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Improvements to aged_containers (RIPD-363)
- Added unit tests for element erase - Added unit tests for range erase - Added unit tests for touch - Added unit tests for iterators and reverse_iterators - Un-inlined operator== for unordered containers - Fixed minor problems with ordered_container erase() - Made ordered_container... - erase (reverse_iterator pos) not compile - erase (reverse_iterator first, reverse_iterator last) not compile - touch (reverse iterator pos) not compile - Verified that ordered container... - insert() already rejects reverse_iterator - emplace_hint() already rejects reverse_iterator - Made set/multiset iterators const Regarding the set/multiset iterators, see section 1.5 of http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2913.pdf as pointed out by Vinnie.
This commit is contained in:
committed by
Vinnie Falco
parent
ee570a49d0
commit
df32f27762
@@ -51,20 +51,46 @@ class aged_container_iterator
|
||||
public:
|
||||
typedef typename Iterator::value_type::stashed::time_point time_point;
|
||||
|
||||
// Could be '= default', but Visual Studio 2013 chokes on it [Aug 2014]
|
||||
aged_container_iterator ()
|
||||
{
|
||||
}
|
||||
|
||||
template <class OtherIterator, class OtherBase>
|
||||
aged_container_iterator (aged_container_iterator <
|
||||
false, OtherIterator, OtherBase> const& other)
|
||||
// copy constructor
|
||||
aged_container_iterator (
|
||||
aged_container_iterator<is_const, Iterator, Base>
|
||||
const& other) = default;
|
||||
|
||||
// Disable constructing a const_iterator from a non-const_iterator.
|
||||
// Converting between reverse and non-reverse iterators should be explicit.
|
||||
template <bool other_is_const, class OtherIterator, class OtherBase,
|
||||
class = typename std::enable_if <
|
||||
(other_is_const == false || is_const == true) &&
|
||||
std::is_same<Iterator, OtherIterator>::value == false>::type>
|
||||
explicit aged_container_iterator (aged_container_iterator <
|
||||
other_is_const, OtherIterator, OtherBase> const& other)
|
||||
: m_iter (other.m_iter)
|
||||
{
|
||||
}
|
||||
|
||||
// Disable constructing a const_iterator from a non-const_iterator.
|
||||
template <bool other_is_const, class OtherBase,
|
||||
class = typename std::enable_if <
|
||||
other_is_const == false || is_const == true>::type>
|
||||
aged_container_iterator (aged_container_iterator <
|
||||
other_is_const, Iterator, OtherBase> const& other)
|
||||
: m_iter (other.m_iter)
|
||||
{
|
||||
}
|
||||
|
||||
// Disable assigning a const_iterator to a non-const iterator
|
||||
template <bool other_is_const, class OtherIterator, class OtherBase>
|
||||
aged_container_iterator& operator= (aged_container_iterator <
|
||||
other_is_const, OtherIterator, OtherBase> const& other)
|
||||
auto
|
||||
operator= (aged_container_iterator <
|
||||
other_is_const, OtherIterator, OtherBase> const& other) ->
|
||||
typename std::enable_if <
|
||||
other_is_const == false || is_const == true,
|
||||
aged_container_iterator&>::type
|
||||
{
|
||||
m_iter = other.m_iter;
|
||||
return *this;
|
||||
|
||||
@@ -42,6 +42,18 @@
|
||||
namespace beast {
|
||||
namespace detail {
|
||||
|
||||
// Traits templates used to discern reverse_iterators, which are disallowed
|
||||
// for mutating operations.
|
||||
template <class It>
|
||||
struct is_boost_reverse_iterator
|
||||
: std::false_type
|
||||
{};
|
||||
|
||||
template <class It>
|
||||
struct is_boost_reverse_iterator<boost::intrusive::detail::reverse_iterator<It>>
|
||||
: std::true_type
|
||||
{};
|
||||
|
||||
/** Associative container where each element is also indexed by time.
|
||||
|
||||
This container mirrors the interface of the standard library ordered
|
||||
@@ -384,13 +396,14 @@ private:
|
||||
return p;
|
||||
}
|
||||
|
||||
void delete_element (element* p)
|
||||
void delete_element (element const* p)
|
||||
{
|
||||
ElementAllocatorTraits::destroy (m_config.alloc(), p);
|
||||
ElementAllocatorTraits::deallocate (m_config.alloc(), p, 1);
|
||||
ElementAllocatorTraits::deallocate (
|
||||
m_config.alloc(), const_cast<element*>(p), 1);
|
||||
}
|
||||
|
||||
void unlink_and_delete_element (element* p)
|
||||
void unlink_and_delete_element (element const* p)
|
||||
{
|
||||
chronological.list.erase (
|
||||
chronological.list.iterator_to (*p));
|
||||
@@ -412,11 +425,13 @@ public:
|
||||
typedef typename std::allocator_traits <
|
||||
Allocator>::const_pointer const_pointer;
|
||||
|
||||
typedef detail::aged_container_iterator <false,
|
||||
// A set (that is, !IsMap) iterator is aways const because the elements
|
||||
// of a set are immutable.
|
||||
typedef detail::aged_container_iterator <!IsMap,
|
||||
typename cont_type::iterator> iterator;
|
||||
typedef detail::aged_container_iterator <true,
|
||||
typename cont_type::iterator> const_iterator;
|
||||
typedef detail::aged_container_iterator <false,
|
||||
typedef detail::aged_container_iterator <!IsMap,
|
||||
typename cont_type::reverse_iterator> reverse_iterator;
|
||||
typedef detail::aged_container_iterator <true,
|
||||
typename cont_type::reverse_iterator> const_reverse_iterator;
|
||||
@@ -433,11 +448,13 @@ public:
|
||||
class chronological_t
|
||||
{
|
||||
public:
|
||||
typedef detail::aged_container_iterator <false,
|
||||
// A set (that is, !IsMap) iterator is aways const because the elements
|
||||
// of a set are immutable.
|
||||
typedef detail::aged_container_iterator <!IsMap,
|
||||
typename list_type::iterator> iterator;
|
||||
typedef detail::aged_container_iterator <true,
|
||||
typename list_type::iterator> const_iterator;
|
||||
typedef detail::aged_container_iterator <false,
|
||||
typedef detail::aged_container_iterator <!IsMap,
|
||||
typename list_type::reverse_iterator> reverse_iterator;
|
||||
typedef detail::aged_container_iterator <true,
|
||||
typename list_type::reverse_iterator> const_reverse_iterator;
|
||||
@@ -823,7 +840,7 @@ public:
|
||||
template <bool maybe_multi = IsMulti>
|
||||
typename std::enable_if <maybe_multi,
|
||||
iterator>::type
|
||||
insert (const_iterator const& /*hint*/, value_type const& value)
|
||||
insert (const_iterator /*hint*/, value_type const& value)
|
||||
{
|
||||
// VFALCO TODO Figure out how to utilize 'hint'
|
||||
return insert (value);
|
||||
@@ -840,7 +857,7 @@ public:
|
||||
template <bool maybe_multi = IsMulti>
|
||||
typename std::enable_if <maybe_multi,
|
||||
iterator>::type
|
||||
insert (const_iterator const& /*hint*/, value_type&& value)
|
||||
insert (const_iterator /*hint*/, value_type&& value)
|
||||
{
|
||||
// VFALCO TODO Figure out how to utilize 'hint'
|
||||
return insert (std::move (value));
|
||||
@@ -882,7 +899,7 @@ public:
|
||||
|
||||
template <class InputIt>
|
||||
void
|
||||
insert (InputIt first, InputIt const& last)
|
||||
insert (InputIt first, InputIt last)
|
||||
{
|
||||
for (; first != last; ++first)
|
||||
insert (cend(), *first);
|
||||
@@ -911,7 +928,7 @@ public:
|
||||
// map, set
|
||||
template <bool maybe_multi = IsMulti, class... Args>
|
||||
auto
|
||||
emplace_hint (const_iterator const& hint, Args&&... args) ->
|
||||
emplace_hint (const_iterator hint, Args&&... args) ->
|
||||
typename std::enable_if <! maybe_multi,
|
||||
std::pair <iterator, bool>>::type;
|
||||
|
||||
@@ -919,24 +936,26 @@ public:
|
||||
template <bool maybe_multi = IsMulti, class... Args>
|
||||
typename std::enable_if <maybe_multi,
|
||||
iterator>::type
|
||||
emplace_hint (const_iterator const& /*hint*/, Args&&... args)
|
||||
emplace_hint (const_iterator /*hint*/, Args&&... args)
|
||||
{
|
||||
// VFALCO TODO Figure out how to utilize 'hint'
|
||||
return emplace <maybe_multi> (
|
||||
std::forward <Args> (args)...);
|
||||
}
|
||||
|
||||
template <bool is_const, class Iterator, class Base>
|
||||
// enable_if prevents erase (reverse_iterator pos) from compiling
|
||||
template <bool is_const, class Iterator, class Base,
|
||||
class = std::enable_if_t<!is_boost_reverse_iterator<Iterator>::value>>
|
||||
detail::aged_container_iterator <false, Iterator, Base>
|
||||
erase (detail::aged_container_iterator <
|
||||
is_const, Iterator, Base> const& pos);
|
||||
erase (detail::aged_container_iterator <is_const, Iterator, Base> pos);
|
||||
|
||||
template <bool is_const, class Iterator, class Base>
|
||||
// enable_if prevents erase (reverse_iterator first, reverse_iterator last)
|
||||
// from compiling
|
||||
template <bool is_const, class Iterator, class Base,
|
||||
class = std::enable_if_t<!is_boost_reverse_iterator<Iterator>::value>>
|
||||
detail::aged_container_iterator <false, Iterator, Base>
|
||||
erase (detail::aged_container_iterator <
|
||||
is_const, Iterator, Base> first,
|
||||
detail::aged_container_iterator <
|
||||
is_const, Iterator, Base> const& last);
|
||||
erase (detail::aged_container_iterator <is_const, Iterator, Base> first,
|
||||
detail::aged_container_iterator <is_const, Iterator, Base> last);
|
||||
|
||||
template <class K>
|
||||
auto
|
||||
@@ -948,10 +967,11 @@ public:
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
template <bool is_const, class Iterator, class Base>
|
||||
// enable_if prevents touch (reverse_iterator pos) from compiling
|
||||
template <bool is_const, class Iterator, class Base,
|
||||
class = std::enable_if_t<!is_boost_reverse_iterator<Iterator>::value>>
|
||||
void
|
||||
touch (detail::aged_container_iterator <
|
||||
is_const, Iterator, Base> const& pos)
|
||||
touch (detail::aged_container_iterator <is_const, Iterator, Base> pos)
|
||||
{
|
||||
touch (pos, clock().now());
|
||||
}
|
||||
@@ -1176,10 +1196,12 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
template <bool is_const, class Iterator, class Base>
|
||||
// enable_if prevents erase (reverse_iterator pos, now) from compiling
|
||||
template <bool is_const, class Iterator, class Base,
|
||||
class = std::enable_if_t<!is_boost_reverse_iterator<Iterator>::value>>
|
||||
void
|
||||
touch (detail::aged_container_iterator <
|
||||
is_const, Iterator, Base> const& pos,
|
||||
is_const, Iterator, Base> pos,
|
||||
typename clock_type::time_point const& now);
|
||||
|
||||
template <bool maybe_propagate = std::allocator_traits <
|
||||
@@ -1693,7 +1715,7 @@ template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
template <bool maybe_multi, class... Args>
|
||||
auto
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
emplace_hint (const_iterator const& hint, Args&&... args) ->
|
||||
emplace_hint (const_iterator hint, Args&&... args) ->
|
||||
typename std::enable_if <! maybe_multi,
|
||||
std::pair <iterator, bool>>::type
|
||||
{
|
||||
@@ -1716,36 +1738,27 @@ emplace_hint (const_iterator const& hint, Args&&... args) ->
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
template <bool is_const, class Iterator, class Base>
|
||||
auto
|
||||
template <bool is_const, class Iterator, class Base, class>
|
||||
detail::aged_container_iterator <false, Iterator, Base>
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
erase (detail::aged_container_iterator <
|
||||
is_const, Iterator, Base> const& pos) ->
|
||||
detail::aged_container_iterator <false, Iterator, Base>
|
||||
erase (detail::aged_container_iterator <is_const, Iterator, Base> pos)
|
||||
{
|
||||
auto iter (pos.iterator());
|
||||
auto p (&*iter++);
|
||||
unlink_and_delete_element (p);
|
||||
unlink_and_delete_element(&*((pos++).iterator()));
|
||||
return detail::aged_container_iterator <
|
||||
false, Iterator, Base> (iter);
|
||||
false, Iterator, Base> (pos.iterator());
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
template <bool is_const, class Iterator, class Base>
|
||||
auto
|
||||
template <bool is_const, class Iterator, class Base, class>
|
||||
detail::aged_container_iterator <false, Iterator, Base>
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
erase (detail::aged_container_iterator <
|
||||
is_const, Iterator, Base> first,
|
||||
detail::aged_container_iterator <
|
||||
is_const, Iterator, Base> const& last) ->
|
||||
detail::aged_container_iterator <false, Iterator, Base>
|
||||
erase (detail::aged_container_iterator <is_const, Iterator, Base> first,
|
||||
detail::aged_container_iterator <is_const, Iterator, Base> last)
|
||||
{
|
||||
for (; first != last;)
|
||||
{
|
||||
auto p (&*first++);
|
||||
unlink_and_delete_element (p);
|
||||
}
|
||||
unlink_and_delete_element(&*((first++).iterator()));
|
||||
|
||||
return detail::aged_container_iterator <
|
||||
false, Iterator, Base> (first.iterator());
|
||||
}
|
||||
@@ -1839,11 +1852,11 @@ operator== (
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Compare, class Allocator>
|
||||
template <bool is_const, class Iterator, class Base>
|
||||
template <bool is_const, class Iterator, class Base, class>
|
||||
void
|
||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||
touch (detail::aged_container_iterator <
|
||||
is_const, Iterator, Base> const& pos,
|
||||
is_const, Iterator, Base> pos,
|
||||
typename clock_type::time_point const& now)
|
||||
{
|
||||
auto& e (*pos.iterator());
|
||||
|
||||
@@ -584,13 +584,14 @@ private:
|
||||
return p;
|
||||
}
|
||||
|
||||
void delete_element (element* p)
|
||||
void delete_element (element const* p)
|
||||
{
|
||||
ElementAllocatorTraits::destroy (m_config.alloc(), p);
|
||||
ElementAllocatorTraits::deallocate (m_config.alloc(), p, 1);
|
||||
ElementAllocatorTraits::deallocate (
|
||||
m_config.alloc(), const_cast<element*>(p), 1);
|
||||
}
|
||||
|
||||
void unlink_and_delete_element (element* p)
|
||||
void unlink_and_delete_element (element const* p)
|
||||
{
|
||||
chronological.list.erase (
|
||||
chronological.list.iterator_to (*p));
|
||||
@@ -609,12 +610,14 @@ public:
|
||||
typedef typename std::allocator_traits <
|
||||
Allocator>::const_pointer const_pointer;
|
||||
|
||||
typedef detail::aged_container_iterator <false,
|
||||
// A set (that is, !IsMap) iterator is aways const because the elements
|
||||
// of a set are immutable.
|
||||
typedef detail::aged_container_iterator <!IsMap,
|
||||
typename cont_type::iterator> iterator;
|
||||
typedef detail::aged_container_iterator <true,
|
||||
typename cont_type::iterator> const_iterator;
|
||||
|
||||
typedef detail::aged_container_iterator <false,
|
||||
typedef detail::aged_container_iterator <!IsMap,
|
||||
typename cont_type::local_iterator> local_iterator;
|
||||
typedef detail::aged_container_iterator <true,
|
||||
typename cont_type::local_iterator> const_local_iterator;
|
||||
@@ -631,11 +634,13 @@ public:
|
||||
class chronological_t
|
||||
{
|
||||
public:
|
||||
typedef detail::aged_container_iterator <false,
|
||||
// A set (that is, !IsMap) iterator is aways const because the elements
|
||||
// of a set are immutable.
|
||||
typedef detail::aged_container_iterator <!IsMap,
|
||||
typename list_type::iterator> iterator;
|
||||
typedef detail::aged_container_iterator <true,
|
||||
typename list_type::iterator> const_iterator;
|
||||
typedef detail::aged_container_iterator <false,
|
||||
typedef detail::aged_container_iterator <!IsMap,
|
||||
typename list_type::reverse_iterator> reverse_iterator;
|
||||
typedef detail::aged_container_iterator <true,
|
||||
typename list_type::reverse_iterator> const_reverse_iterator;
|
||||
@@ -1021,7 +1026,7 @@ public:
|
||||
template <bool maybe_multi = IsMulti>
|
||||
typename std::enable_if <maybe_multi,
|
||||
iterator>::type
|
||||
insert (const_iterator const& /*hint*/, value_type const& value)
|
||||
insert (const_iterator /*hint*/, value_type const& value)
|
||||
{
|
||||
// VFALCO TODO The hint could be used to let
|
||||
// the client order equal ranges
|
||||
@@ -1043,7 +1048,7 @@ public:
|
||||
template <bool maybe_multi = IsMulti>
|
||||
typename std::enable_if <maybe_multi,
|
||||
iterator>::type
|
||||
insert (const_iterator const& /*hint*/, value_type&& value)
|
||||
insert (const_iterator /*hint*/, value_type&& value)
|
||||
{
|
||||
// VFALCO TODO The hint could be used to let
|
||||
// the client order equal ranges
|
||||
@@ -1083,7 +1088,7 @@ public:
|
||||
}
|
||||
|
||||
template <class InputIt>
|
||||
void insert (InputIt first, InputIt const& last)
|
||||
void insert (InputIt first, InputIt last)
|
||||
{
|
||||
insert (first, last,
|
||||
typename std::iterator_traits <
|
||||
@@ -1113,7 +1118,7 @@ public:
|
||||
// set, map
|
||||
template <bool maybe_multi = IsMulti, class... Args>
|
||||
auto
|
||||
emplace_hint (const_iterator const& /*hint*/, Args&&... args) ->
|
||||
emplace_hint (const_iterator /*hint*/, Args&&... args) ->
|
||||
typename std::enable_if <! maybe_multi,
|
||||
std::pair <iterator, bool>>::type;
|
||||
|
||||
@@ -1121,7 +1126,7 @@ public:
|
||||
template <bool maybe_multi = IsMulti, class... Args>
|
||||
typename std::enable_if <maybe_multi,
|
||||
iterator>::type
|
||||
emplace_hint (const_iterator const& /*hint*/, Args&&... args)
|
||||
emplace_hint (const_iterator /*hint*/, Args&&... args)
|
||||
{
|
||||
// VFALCO TODO The hint could be used for multi, to let
|
||||
// the client order equal ranges
|
||||
@@ -1132,14 +1137,14 @@ public:
|
||||
template <bool is_const, class Iterator, class Base>
|
||||
detail::aged_container_iterator <false, Iterator, Base>
|
||||
erase (detail::aged_container_iterator <
|
||||
is_const, Iterator, Base> const& pos);
|
||||
is_const, Iterator, Base> pos);
|
||||
|
||||
template <bool is_const, class Iterator, class Base>
|
||||
detail::aged_container_iterator <false, Iterator, Base>
|
||||
erase (detail::aged_container_iterator <
|
||||
is_const, Iterator, Base> first,
|
||||
detail::aged_container_iterator <
|
||||
is_const, Iterator, Base> const& last);
|
||||
is_const, Iterator, Base> last);
|
||||
|
||||
template <class K>
|
||||
auto
|
||||
@@ -1152,7 +1157,7 @@ public:
|
||||
template <bool is_const, class Iterator, class Base>
|
||||
void
|
||||
touch (detail::aged_container_iterator <
|
||||
is_const, Iterator, Base> const& pos)
|
||||
is_const, Iterator, Base> pos)
|
||||
{
|
||||
touch (pos, clock().now());
|
||||
}
|
||||
@@ -1349,24 +1354,11 @@ public:
|
||||
class OtherAllocator,
|
||||
bool maybe_multi = IsMulti
|
||||
>
|
||||
typename std::enable_if <! maybe_multi,
|
||||
bool>::type
|
||||
typename std::enable_if <! maybe_multi, bool>::type
|
||||
operator== (
|
||||
aged_unordered_container <false, OtherIsMap,
|
||||
OtherKey, OtherT, OtherDuration, OtherHash, KeyEqual,
|
||||
OtherAllocator> const& other) const
|
||||
{
|
||||
if (size() != other.size())
|
||||
return false;
|
||||
for (auto iter (cbegin()), last (cend()), olast (other.cend());
|
||||
iter != last; ++iter)
|
||||
{
|
||||
auto oiter (other.find (extract (*iter)));
|
||||
if (oiter == olast)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
OtherAllocator> const& other) const;
|
||||
|
||||
template <
|
||||
bool OtherIsMap,
|
||||
@@ -1377,35 +1369,11 @@ public:
|
||||
class OtherAllocator,
|
||||
bool maybe_multi = IsMulti
|
||||
>
|
||||
typename std::enable_if <maybe_multi,
|
||||
bool>::type
|
||||
typename std::enable_if <maybe_multi, bool>::type
|
||||
operator== (
|
||||
aged_unordered_container <true, OtherIsMap,
|
||||
OtherKey, OtherT, OtherDuration, OtherHash, KeyEqual,
|
||||
OtherAllocator> const& other) const
|
||||
{
|
||||
if (size() != other.size())
|
||||
return false;
|
||||
typedef std::pair <const_iterator, const_iterator> EqRng;
|
||||
for (auto iter (cbegin()), last (cend()); iter != last;)
|
||||
{
|
||||
auto const& k (extract (*iter));
|
||||
auto const eq (equal_range (k));
|
||||
auto const oeq (other.equal_range (k));
|
||||
#if BEAST_NO_CXX14_IS_PERMUTATION
|
||||
if (std::distance (eq.first, eq.second) !=
|
||||
std::distance (oeq.first, oeq.second) ||
|
||||
! std::is_permutation (eq.first, eq.second, oeq.first))
|
||||
return false;
|
||||
#else
|
||||
if (! std::is_permutation (eq.first,
|
||||
eq.second, oeq.first, oeq.second))
|
||||
return false;
|
||||
#endif
|
||||
iter = eq.second;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
OtherAllocator> const& other) const;
|
||||
|
||||
template <
|
||||
bool OtherIsMulti,
|
||||
@@ -1456,7 +1424,7 @@ private:
|
||||
|
||||
template <class InputIt>
|
||||
void
|
||||
insert_unchecked (InputIt first, InputIt const& last)
|
||||
insert_unchecked (InputIt first, InputIt last)
|
||||
{
|
||||
for (; first != last; ++first)
|
||||
insert_unchecked (*first);
|
||||
@@ -1464,7 +1432,7 @@ private:
|
||||
|
||||
template <class InputIt>
|
||||
void
|
||||
insert (InputIt first, InputIt const& last,
|
||||
insert (InputIt first, InputIt last,
|
||||
std::input_iterator_tag)
|
||||
{
|
||||
for (; first != last; ++first)
|
||||
@@ -1473,7 +1441,7 @@ private:
|
||||
|
||||
template <class InputIt>
|
||||
void
|
||||
insert (InputIt first, InputIt const& last,
|
||||
insert (InputIt first, InputIt last,
|
||||
std::random_access_iterator_tag)
|
||||
{
|
||||
auto const n (std::distance (first, last));
|
||||
@@ -1484,7 +1452,7 @@ private:
|
||||
template <bool is_const, class Iterator, class Base>
|
||||
void
|
||||
touch (detail::aged_container_iterator <
|
||||
is_const, Iterator, Base> const& pos,
|
||||
is_const, Iterator, Base> pos,
|
||||
typename clock_type::time_point const& now)
|
||||
{
|
||||
auto& e (*pos.iterator());
|
||||
@@ -2268,7 +2236,7 @@ template <bool maybe_multi, class... Args>
|
||||
auto
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
emplace_hint (const_iterator const& /*hint*/, Args&&... args) ->
|
||||
emplace_hint (const_iterator /*hint*/, Args&&... args) ->
|
||||
typename std::enable_if <! maybe_multi,
|
||||
std::pair <iterator, bool>>::type
|
||||
{
|
||||
@@ -2298,13 +2266,11 @@ detail::aged_container_iterator <false, Iterator, Base>
|
||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
Hash, KeyEqual, Allocator>::
|
||||
erase (detail::aged_container_iterator <
|
||||
is_const, Iterator, Base> const& pos)
|
||||
is_const, Iterator, Base> pos)
|
||||
{
|
||||
auto iter (pos.iterator());
|
||||
auto p (&*iter++);
|
||||
unlink_and_delete_element (p);
|
||||
unlink_and_delete_element(&*((pos++).iterator()));
|
||||
return detail::aged_container_iterator <
|
||||
false, Iterator, Base> (iter);
|
||||
false, Iterator, Base> (pos.iterator());
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
@@ -2316,14 +2282,11 @@ aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||
erase (detail::aged_container_iterator <
|
||||
is_const, Iterator, Base> first,
|
||||
detail::aged_container_iterator <
|
||||
is_const, Iterator, Base> const& last)
|
||||
is_const, Iterator, Base> last)
|
||||
{
|
||||
size_type n (0);
|
||||
for (; first != last; ++n)
|
||||
{
|
||||
auto p (&*first++);
|
||||
unlink_and_delete_element (p);
|
||||
}
|
||||
for (; first != last;)
|
||||
unlink_and_delete_element(&*((first++).iterator()));
|
||||
|
||||
return detail::aged_container_iterator <
|
||||
false, Iterator, Base> (first.iterator());
|
||||
}
|
||||
@@ -2387,6 +2350,79 @@ touch (K const& k) ->
|
||||
return n;
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
template <
|
||||
bool OtherIsMap,
|
||||
class OtherKey,
|
||||
class OtherT,
|
||||
class OtherDuration,
|
||||
class OtherHash,
|
||||
class OtherAllocator,
|
||||
bool maybe_multi
|
||||
>
|
||||
typename std::enable_if <! maybe_multi, bool>::type
|
||||
aged_unordered_container <
|
||||
IsMulti, IsMap, Key, T, Duration, Hash, KeyEqual, Allocator>::
|
||||
operator== (
|
||||
aged_unordered_container <false, OtherIsMap,
|
||||
OtherKey, OtherT, OtherDuration, OtherHash, KeyEqual,
|
||||
OtherAllocator> const& other) const
|
||||
{
|
||||
if (size() != other.size())
|
||||
return false;
|
||||
for (auto iter (cbegin()), last (cend()), olast (other.cend());
|
||||
iter != last; ++iter)
|
||||
{
|
||||
auto oiter (other.find (extract (*iter)));
|
||||
if (oiter == olast)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||
class Duration, class Hash, class KeyEqual, class Allocator>
|
||||
template <
|
||||
bool OtherIsMap,
|
||||
class OtherKey,
|
||||
class OtherT,
|
||||
class OtherDuration,
|
||||
class OtherHash,
|
||||
class OtherAllocator,
|
||||
bool maybe_multi
|
||||
>
|
||||
typename std::enable_if <maybe_multi, bool>::type
|
||||
aged_unordered_container <
|
||||
IsMulti, IsMap, Key, T, Duration, Hash, KeyEqual, Allocator>::
|
||||
operator== (
|
||||
aged_unordered_container <true, OtherIsMap,
|
||||
OtherKey, OtherT, OtherDuration, OtherHash, KeyEqual,
|
||||
OtherAllocator> const& other) const
|
||||
{
|
||||
if (size() != other.size())
|
||||
return false;
|
||||
typedef std::pair <const_iterator, const_iterator> EqRng;
|
||||
for (auto iter (cbegin()), last (cend()); iter != last;)
|
||||
{
|
||||
auto const& k (extract (*iter));
|
||||
auto const eq (equal_range (k));
|
||||
auto const oeq (other.equal_range (k));
|
||||
#if BEAST_NO_CXX14_IS_PERMUTATION
|
||||
if (std::distance (eq.first, eq.second) !=
|
||||
std::distance (oeq.first, oeq.second) ||
|
||||
! std::is_permutation (eq.first, eq.second, oeq.first))
|
||||
return false;
|
||||
#else
|
||||
if (! std::is_permutation (eq.first,
|
||||
eq.second, oeq.first, oeq.second))
|
||||
return false;
|
||||
#endif
|
||||
iter = eq.second;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// map, set
|
||||
|
||||
@@ -482,6 +482,23 @@ public:
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
||||
void
|
||||
testIterator ();
|
||||
|
||||
// Unordered containers don't have reverse iterators
|
||||
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
||||
typename std::enable_if <! IsUnordered>::type
|
||||
testReverseIterator();
|
||||
|
||||
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
||||
typename std::enable_if <IsUnordered>::type
|
||||
testReverseIterator()
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
template <class Container, class Values>
|
||||
void checkInsertCopy (Container& c, Values const& v);
|
||||
|
||||
@@ -524,6 +541,31 @@ public:
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
// Helpers for erase tests
|
||||
template <class Container, class Values>
|
||||
void reverseFillAgedContainer(Container& c, Values const& v);
|
||||
|
||||
template <class Iter>
|
||||
Iter nextToEndIter (Iter const beginIter, Iter const endItr);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
template <class Container, class Iter>
|
||||
bool doElementErase (Container& c, Iter const beginItr, Iter const endItr);
|
||||
|
||||
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
||||
void testElementErase();
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
template <class Container, class BeginEndSrc>
|
||||
void doRangeErase (Container& c, BeginEndSrc const& beginEndSrc);
|
||||
|
||||
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
||||
void testRangeErase();
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
// ordered
|
||||
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
||||
typename std::enable_if <! IsUnordered>::type
|
||||
@@ -1083,6 +1125,163 @@ testCopyMove ()
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Iterator construction and assignment
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
||||
void
|
||||
aged_associative_container_test_base::
|
||||
testIterator()
|
||||
{
|
||||
typedef TestTraits <IsUnordered, IsMulti, IsMap> Traits;
|
||||
typedef typename Traits::Value Value;
|
||||
typedef typename Traits::Alloc Alloc;
|
||||
typename Traits::Clock clock;
|
||||
auto const v (Traits::values());
|
||||
|
||||
//testcase (Traits::name() + " iterators");
|
||||
testcase ("iterator");
|
||||
|
||||
typename Traits::template Cont <> c {clock};
|
||||
|
||||
using iterator = decltype (c.begin());
|
||||
using const_iterator = decltype (c.cbegin());
|
||||
|
||||
// Should be able to construct or assign an iterator from an iterator.
|
||||
iterator nnIt_0 {c.begin()};
|
||||
iterator nnIt_1 {nnIt_0};
|
||||
expect (nnIt_0 == nnIt_1, "iterator constructor failed");
|
||||
iterator nnIt_2;
|
||||
nnIt_2 = nnIt_1;
|
||||
expect (nnIt_1 == nnIt_2, "iterator assignment failed");
|
||||
|
||||
// Should be able to construct or assign a const_iterator from a
|
||||
// const_iterator.
|
||||
const_iterator ccIt_0 {c.cbegin()};
|
||||
const_iterator ccIt_1 {ccIt_0};
|
||||
expect (ccIt_0 == ccIt_1, "const_iterator constructor failed");
|
||||
const_iterator ccIt_2;
|
||||
ccIt_2 = ccIt_1;
|
||||
expect (ccIt_1 == ccIt_2, "const_iterator assignment failed");
|
||||
|
||||
// Comparison between iterator and const_iterator is okay
|
||||
expect (nnIt_0 == ccIt_0,
|
||||
"Comparing an iterator to a const_iterator failed");
|
||||
expect (ccIt_1 == nnIt_1,
|
||||
"Comparing a const_iterator to an iterator failed");
|
||||
|
||||
// Should be able to construct a const_iterator from an iterator.
|
||||
const_iterator ncIt_3 {c.begin()};
|
||||
const_iterator ncIt_4 {nnIt_0};
|
||||
expect (ncIt_3 == ncIt_4,
|
||||
"const_iterator construction from iterator failed");
|
||||
const_iterator ncIt_5;
|
||||
ncIt_5 = nnIt_2;
|
||||
expect (ncIt_5 == ncIt_4,
|
||||
"const_iterator assignment from iterator failed");
|
||||
|
||||
// None of these should compile because they construct or assign to a
|
||||
// non-const iterator with a const_iterator.
|
||||
|
||||
// iterator cnIt_0 {c.cbegin()};
|
||||
|
||||
// iterator cnIt_1 {ccIt_0};
|
||||
|
||||
// iterator cnIt_2;
|
||||
// cnIt_2 = ccIt_2;
|
||||
}
|
||||
|
||||
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
||||
typename std::enable_if <! IsUnordered>::type
|
||||
aged_associative_container_test_base::
|
||||
testReverseIterator()
|
||||
{
|
||||
typedef TestTraits <IsUnordered, IsMulti, IsMap> Traits;
|
||||
typedef typename Traits::Value Value;
|
||||
typedef typename Traits::Alloc Alloc;
|
||||
typename Traits::Clock clock;
|
||||
auto const v (Traits::values());
|
||||
|
||||
//testcase (Traits::name() + " reverse_iterators");
|
||||
testcase ("reverse_iterator");
|
||||
|
||||
typename Traits::template Cont <> c {clock};
|
||||
|
||||
using iterator = decltype (c.begin());
|
||||
using const_iterator = decltype (c.cbegin());
|
||||
using reverse_iterator = decltype (c.rbegin());
|
||||
using const_reverse_iterator = decltype (c.crbegin());
|
||||
|
||||
// Naming decoder ring
|
||||
// constructed from ------+ +----- constructed type
|
||||
// /\/\ -- character pairs
|
||||
// xAyBit
|
||||
// r (reverse) or f (forward)--^-^
|
||||
// ^-^------ C (const) or N (non-const)
|
||||
|
||||
// Should be able to construct or assign a reverse_iterator from a
|
||||
// reverse_iterator.
|
||||
reverse_iterator rNrNit_0 {c.rbegin()};
|
||||
reverse_iterator rNrNit_1 {rNrNit_0};
|
||||
expect (rNrNit_0 == rNrNit_1, "reverse_iterator constructor failed");
|
||||
reverse_iterator xXrNit_2;
|
||||
xXrNit_2 = rNrNit_1;
|
||||
expect (rNrNit_1 == xXrNit_2, "reverse_iterator assignment failed");
|
||||
|
||||
// Should be able to construct or assign a const_reverse_iterator from a
|
||||
// const_reverse_iterator
|
||||
const_reverse_iterator rCrCit_0 {c.crbegin()};
|
||||
const_reverse_iterator rCrCit_1 {rCrCit_0};
|
||||
expect (rCrCit_0 == rCrCit_1, "reverse_iterator constructor failed");
|
||||
const_reverse_iterator xXrCit_2;
|
||||
xXrCit_2 = rCrCit_1;
|
||||
expect (rCrCit_1 == xXrCit_2, "reverse_iterator assignment failed");
|
||||
|
||||
// Comparison between reverse_iterator and const_reverse_iterator is okay
|
||||
expect (rNrNit_0 == rCrCit_0,
|
||||
"Comparing an iterator to a const_iterator failed");
|
||||
expect (rCrCit_1 == rNrNit_1,
|
||||
"Comparing a const_iterator to an iterator failed");
|
||||
|
||||
// Should be able to construct or assign a const_reverse_iterator from a
|
||||
// reverse_iterator
|
||||
const_reverse_iterator rNrCit_0 {c.rbegin()};
|
||||
const_reverse_iterator rNrCit_1 {rNrNit_0};
|
||||
expect (rNrCit_0 == rNrCit_1,
|
||||
"const_reverse_iterator construction from reverse_iterator failed");
|
||||
xXrCit_2 = rNrNit_1;
|
||||
expect (rNrCit_1 == xXrCit_2,
|
||||
"const_reverse_iterator assignment from reverse_iterator failed");
|
||||
|
||||
// The standard allows these conversions:
|
||||
// o reverse_iterator is explicitly constructible from iterator.
|
||||
// o const_reverse_iterator is explicitly constructible from const_iterator.
|
||||
// Should be able to construct or assign reverse_iterators from
|
||||
// non-reverse iterators.
|
||||
reverse_iterator fNrNit_0 {c.begin()};
|
||||
const_reverse_iterator fNrCit_0 {c.begin()};
|
||||
expect (fNrNit_0 == fNrCit_0,
|
||||
"reverse_iterator construction from iterator failed");
|
||||
const_reverse_iterator fCrCit_0 {c.cbegin()};
|
||||
expect (fNrCit_0 == fCrCit_0,
|
||||
"const_reverse_iterator construction from const_iterator failed");
|
||||
|
||||
// None of these should compile because they construct a non-reverse
|
||||
// iterator from a reverse_iterator.
|
||||
// iterator rNfNit_0 {c.rbegin()};
|
||||
// const_iterator rNfCit_0 {c.rbegin()};
|
||||
// const_iterator rCfCit_0 {c.crbegin()};
|
||||
|
||||
// You should not be able to assign an iterator to a reverse_iterator or
|
||||
// vise-versa. So the following lines should not compile.
|
||||
iterator xXfNit_0;
|
||||
// xXfNit_0 = xXrNit_2;
|
||||
// xXrNit_2 = xXfNit_0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Modifiers
|
||||
@@ -1232,9 +1431,12 @@ testChronological ()
|
||||
c.chronological.cbegin(), c.chronological.cend(),
|
||||
v.begin(), v.end(), equal_value <Traits> ()));
|
||||
|
||||
for (auto iter (v.rbegin()); iter != v.rend(); ++iter)
|
||||
// Test touch() with a non-const iterator.
|
||||
for (auto iter (v.crbegin()); iter != v.crend(); ++iter)
|
||||
{
|
||||
auto found (c.find (Traits::extract (*iter)));
|
||||
using iterator = typename decltype (c)::iterator;
|
||||
iterator found (c.find (Traits::extract (*iter)));
|
||||
|
||||
expect (found != c.cend());
|
||||
if (found == c.cend())
|
||||
return;
|
||||
@@ -1243,7 +1445,30 @@ testChronological ()
|
||||
|
||||
expect (std::equal (
|
||||
c.chronological.cbegin(), c.chronological.cend(),
|
||||
v.rbegin(), v.rend(), equal_value <Traits> ()));
|
||||
v.crbegin(), v.crend(), equal_value <Traits> ()));
|
||||
|
||||
// Test touch() with a const_iterator
|
||||
for (auto iter (v.cbegin()); iter != v.cend(); ++iter)
|
||||
{
|
||||
using const_iterator = typename decltype (c)::const_iterator;
|
||||
const_iterator found (c.find (Traits::extract (*iter)));
|
||||
|
||||
expect (found != c.cend());
|
||||
if (found == c.cend())
|
||||
return;
|
||||
c.touch (found);
|
||||
}
|
||||
|
||||
expect (std::equal (
|
||||
c.chronological.cbegin(), c.chronological.cend(),
|
||||
v.cbegin(), v.cend(), equal_value <Traits> ()));
|
||||
|
||||
{
|
||||
// Because touch (reverse_iterator pos) is not allowed, the following
|
||||
// lines should not compile for any aged_container type.
|
||||
// c.touch (c.rbegin());
|
||||
// c.touch (c.crbegin());
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -1282,6 +1507,270 @@ testArrayCreate()
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Helpers for erase tests
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <class Container, class Values>
|
||||
void
|
||||
aged_associative_container_test_base::
|
||||
reverseFillAgedContainer (Container& c, Values const& values)
|
||||
{
|
||||
// Just in case the passed in container was not empty.
|
||||
c.clear();
|
||||
|
||||
// c.clock() returns an abstract_clock, so dynamic_cast to manual_clock.
|
||||
typedef TestTraitsBase::Clock Clock;
|
||||
Clock& clk (dynamic_cast <Clock&> (c.clock ()));
|
||||
clk.set (0);
|
||||
|
||||
Values rev (values);
|
||||
std::sort (rev.begin (), rev.end ());
|
||||
std::reverse (rev.begin (), rev.end ());
|
||||
for (auto& v : rev)
|
||||
{
|
||||
// Add values in reverse order so they are reversed chronologically.
|
||||
++clk;
|
||||
c.insert (v);
|
||||
}
|
||||
}
|
||||
|
||||
// Get one iterator before endIter. We have to use operator++ because you
|
||||
// cannot use operator-- with unordered container iterators.
|
||||
template <class Iter>
|
||||
Iter
|
||||
aged_associative_container_test_base::
|
||||
nextToEndIter (Iter beginIter, Iter const endIter)
|
||||
{
|
||||
if (beginIter == endIter)
|
||||
{
|
||||
fail ("Internal test failure. Cannot advance beginIter");
|
||||
return beginIter;
|
||||
}
|
||||
|
||||
//
|
||||
Iter nextToEnd = beginIter;
|
||||
do
|
||||
{
|
||||
nextToEnd = beginIter++;
|
||||
} while (beginIter != endIter);
|
||||
return nextToEnd;
|
||||
}
|
||||
|
||||
// Implementation for the element erase tests
|
||||
//
|
||||
// This test accepts:
|
||||
// o the container from which we will erase elements
|
||||
// o iterators into that container defining the range of the erase
|
||||
//
|
||||
// This implementation does not declare a pass, since it wants to allow
|
||||
// the caller to examine the size of the container and the returned iterator
|
||||
//
|
||||
// Note that this test works on the aged_associative containers because an
|
||||
// erase only invalidates references and iterators to the erased element
|
||||
// (see 23.2.4/13). Therefore the passed-in end iterator stays valid through
|
||||
// the whole test.
|
||||
template <class Container, class Iter>
|
||||
bool aged_associative_container_test_base::
|
||||
doElementErase (Container& c, Iter const beginItr, Iter const endItr)
|
||||
{
|
||||
auto it (beginItr);
|
||||
size_t count = c.size();
|
||||
while (it != endItr)
|
||||
{
|
||||
auto expectIt = it;
|
||||
++expectIt;
|
||||
it = c.erase (it);
|
||||
|
||||
if (it != expectIt)
|
||||
{
|
||||
fail ("Unexpected returned iterator from element erase");
|
||||
return false;
|
||||
}
|
||||
|
||||
--count;
|
||||
if (count != c.size())
|
||||
{
|
||||
fail ("Failed to erase element");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (c.empty ())
|
||||
{
|
||||
if (it != endItr)
|
||||
{
|
||||
fail ("Erase of last element didn't produce end");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Erase of individual elements
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
||||
void
|
||||
aged_associative_container_test_base::
|
||||
testElementErase ()
|
||||
{
|
||||
typedef TestTraits <IsUnordered, IsMulti, IsMap> Traits;
|
||||
|
||||
//testcase (Traits::name() + " element erase"
|
||||
testcase ("element erase");
|
||||
|
||||
// Make and fill the container
|
||||
typename Traits::Clock ck;
|
||||
typename Traits::template Cont <> c {ck};
|
||||
reverseFillAgedContainer (c, Traits::values());
|
||||
|
||||
{
|
||||
// Test standard iterators
|
||||
auto tempContainer (c);
|
||||
if (! doElementErase (tempContainer,
|
||||
tempContainer.cbegin(), tempContainer.cend()))
|
||||
return; // Test failed
|
||||
|
||||
expect (tempContainer.empty(), "Failed to erase all elements");
|
||||
pass();
|
||||
}
|
||||
{
|
||||
// Test chronological iterators
|
||||
auto tempContainer (c);
|
||||
auto& chron (tempContainer.chronological);
|
||||
if (! doElementErase (tempContainer, chron.begin(), chron.end()))
|
||||
return; // Test failed
|
||||
|
||||
expect (tempContainer.empty(),
|
||||
"Failed to chronologically erase all elements");
|
||||
pass();
|
||||
}
|
||||
{
|
||||
// Test standard iterator partial erase
|
||||
auto tempContainer (c);
|
||||
expect (tempContainer.size() > 2,
|
||||
"Internal failure. Container too small.");
|
||||
if (! doElementErase (tempContainer, ++tempContainer.begin(),
|
||||
nextToEndIter (tempContainer.begin(), tempContainer.end())))
|
||||
return; // Test failed
|
||||
|
||||
expect (tempContainer.size() == 2,
|
||||
"Failed to erase expected number of elements");
|
||||
pass();
|
||||
}
|
||||
{
|
||||
// Test chronological iterator partial erase
|
||||
auto tempContainer (c);
|
||||
expect (tempContainer.size() > 2,
|
||||
"Internal failure. Container too small.");
|
||||
auto& chron (tempContainer.chronological);
|
||||
if (! doElementErase (tempContainer, ++chron.begin(),
|
||||
nextToEndIter (chron.begin(), chron.end())))
|
||||
return; // Test failed
|
||||
|
||||
expect (tempContainer.size() == 2,
|
||||
"Failed to chronologically erase expected number of elements");
|
||||
pass();
|
||||
}
|
||||
{
|
||||
auto tempContainer (c);
|
||||
expect (tempContainer.size() > 4,
|
||||
"Internal failure. Container too small.");
|
||||
// erase(reverse_iterator) is not allowed. None of the following
|
||||
// should compile for any aged_container type.
|
||||
// c.erase (c.rbegin());
|
||||
// c.erase (c.crbegin());
|
||||
// c.erase(c.rbegin(), ++c.rbegin());
|
||||
// c.erase(c.crbegin(), ++c.crbegin());
|
||||
}
|
||||
}
|
||||
|
||||
// Implementation for the range erase tests
|
||||
//
|
||||
// This test accepts:
|
||||
//
|
||||
// o A container with more than 2 elements and
|
||||
// o An object to ask for begin() and end() iterators in the passed container
|
||||
//
|
||||
// This peculiar interface allows either the container itself to be passed as
|
||||
// the second argument or the container's "chronological" element. Both
|
||||
// sources of iterators need to be tested on the container.
|
||||
//
|
||||
// The test locates iterators such that a range-based delete leaves the first
|
||||
// and last elements in the container. It then validates that the container
|
||||
// ended up with the expected contents.
|
||||
//
|
||||
template <class Container, class BeginEndSrc>
|
||||
void
|
||||
aged_associative_container_test_base::
|
||||
doRangeErase (Container& c, BeginEndSrc const& beginEndSrc)
|
||||
{
|
||||
expect (c.size () > 2,
|
||||
"Internal test failure. Container must have more than 2 elements");
|
||||
auto itBeginPlusOne (beginEndSrc.begin ());
|
||||
auto const valueFront = *itBeginPlusOne;
|
||||
++itBeginPlusOne;
|
||||
|
||||
// Get one iterator before end()
|
||||
auto itBack (nextToEndIter (itBeginPlusOne, beginEndSrc.end ()));
|
||||
auto const valueBack = *itBack;
|
||||
|
||||
// Erase all elements but first and last
|
||||
auto const retIter = c.erase (itBeginPlusOne, itBack);
|
||||
|
||||
expect (c.size() == 2,
|
||||
"Unexpected size for range-erased container");
|
||||
|
||||
expect (valueFront == *(beginEndSrc.begin()),
|
||||
"Unexpected first element in range-erased container");
|
||||
|
||||
expect (valueBack == *(++beginEndSrc.begin()),
|
||||
"Unexpected last element in range-erased container");
|
||||
|
||||
expect (retIter == (++beginEndSrc.begin()),
|
||||
"Unexpected return iterator from erase");
|
||||
|
||||
pass ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Erase range of elements
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
||||
void
|
||||
aged_associative_container_test_base::
|
||||
testRangeErase ()
|
||||
{
|
||||
typedef TestTraits <IsUnordered, IsMulti, IsMap> Traits;
|
||||
|
||||
//testcase (Traits::name() + " element erase"
|
||||
testcase ("range erase");
|
||||
|
||||
// Make and fill the container
|
||||
typename Traits::Clock ck;
|
||||
typename Traits::template Cont <> c {ck};
|
||||
reverseFillAgedContainer (c, Traits::values());
|
||||
|
||||
// Not bothering to test range erase with reverse iterators.
|
||||
{
|
||||
auto tempContainer (c);
|
||||
doRangeErase (tempContainer, tempContainer);
|
||||
}
|
||||
{
|
||||
auto tempContainer (c);
|
||||
doRangeErase (tempContainer, tempContainer.chronological);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Container-wide comparison
|
||||
@@ -1378,9 +1867,13 @@ testMaybeUnorderedMultiMap ()
|
||||
testConstructRange <IsUnordered, IsMulti, IsMap> ();
|
||||
testConstructInitList <IsUnordered, IsMulti, IsMap> ();
|
||||
testCopyMove <IsUnordered, IsMulti, IsMap> ();
|
||||
testIterator <IsUnordered, IsMulti, IsMap> ();
|
||||
testReverseIterator <IsUnordered, IsMulti, IsMap> ();
|
||||
testModifiers <IsUnordered, IsMulti, IsMap> ();
|
||||
testChronological <IsUnordered, IsMulti, IsMap> ();
|
||||
testArrayCreate <IsUnordered, IsMulti, IsMap> ();
|
||||
testElementErase <IsUnordered, IsMulti, IsMap> ();
|
||||
testRangeErase <IsUnordered, IsMulti, IsMap> ();
|
||||
testCompare <IsUnordered, IsMulti, IsMap> ();
|
||||
testObservers <IsUnordered, IsMulti, IsMap> ();
|
||||
}
|
||||
@@ -1514,4 +2007,4 @@ BEAST_DEFINE_TESTSUITE(aged_unordered_map,container,beast);
|
||||
BEAST_DEFINE_TESTSUITE(aged_unordered_multiset,container,beast);
|
||||
BEAST_DEFINE_TESTSUITE(aged_unordered_multimap,container,beast);
|
||||
|
||||
}
|
||||
} // namespace beast
|
||||
|
||||
Reference in New Issue
Block a user