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:
|
public:
|
||||||
typedef typename Iterator::value_type::stashed::time_point time_point;
|
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 ()
|
aged_container_iterator ()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class OtherIterator, class OtherBase>
|
// copy constructor
|
||||||
aged_container_iterator (aged_container_iterator <
|
aged_container_iterator (
|
||||||
false, OtherIterator, OtherBase> const& other)
|
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)
|
: 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>
|
template <bool other_is_const, class OtherIterator, class OtherBase>
|
||||||
aged_container_iterator& operator= (aged_container_iterator <
|
auto
|
||||||
other_is_const, OtherIterator, OtherBase> const& other)
|
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;
|
m_iter = other.m_iter;
|
||||||
return *this;
|
return *this;
|
||||||
|
|||||||
@@ -42,6 +42,18 @@
|
|||||||
namespace beast {
|
namespace beast {
|
||||||
namespace detail {
|
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.
|
/** Associative container where each element is also indexed by time.
|
||||||
|
|
||||||
This container mirrors the interface of the standard library ordered
|
This container mirrors the interface of the standard library ordered
|
||||||
@@ -384,13 +396,14 @@ private:
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
void delete_element (element* p)
|
void delete_element (element const* p)
|
||||||
{
|
{
|
||||||
ElementAllocatorTraits::destroy (m_config.alloc(), 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.erase (
|
||||||
chronological.list.iterator_to (*p));
|
chronological.list.iterator_to (*p));
|
||||||
@@ -412,11 +425,13 @@ public:
|
|||||||
typedef typename std::allocator_traits <
|
typedef typename std::allocator_traits <
|
||||||
Allocator>::const_pointer const_pointer;
|
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;
|
typename cont_type::iterator> iterator;
|
||||||
typedef detail::aged_container_iterator <true,
|
typedef detail::aged_container_iterator <true,
|
||||||
typename cont_type::iterator> const_iterator;
|
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;
|
typename cont_type::reverse_iterator> reverse_iterator;
|
||||||
typedef detail::aged_container_iterator <true,
|
typedef detail::aged_container_iterator <true,
|
||||||
typename cont_type::reverse_iterator> const_reverse_iterator;
|
typename cont_type::reverse_iterator> const_reverse_iterator;
|
||||||
@@ -433,11 +448,13 @@ public:
|
|||||||
class chronological_t
|
class chronological_t
|
||||||
{
|
{
|
||||||
public:
|
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;
|
typename list_type::iterator> iterator;
|
||||||
typedef detail::aged_container_iterator <true,
|
typedef detail::aged_container_iterator <true,
|
||||||
typename list_type::iterator> const_iterator;
|
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;
|
typename list_type::reverse_iterator> reverse_iterator;
|
||||||
typedef detail::aged_container_iterator <true,
|
typedef detail::aged_container_iterator <true,
|
||||||
typename list_type::reverse_iterator> const_reverse_iterator;
|
typename list_type::reverse_iterator> const_reverse_iterator;
|
||||||
@@ -823,7 +840,7 @@ public:
|
|||||||
template <bool maybe_multi = IsMulti>
|
template <bool maybe_multi = IsMulti>
|
||||||
typename std::enable_if <maybe_multi,
|
typename std::enable_if <maybe_multi,
|
||||||
iterator>::type
|
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'
|
// VFALCO TODO Figure out how to utilize 'hint'
|
||||||
return insert (value);
|
return insert (value);
|
||||||
@@ -840,7 +857,7 @@ public:
|
|||||||
template <bool maybe_multi = IsMulti>
|
template <bool maybe_multi = IsMulti>
|
||||||
typename std::enable_if <maybe_multi,
|
typename std::enable_if <maybe_multi,
|
||||||
iterator>::type
|
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'
|
// VFALCO TODO Figure out how to utilize 'hint'
|
||||||
return insert (std::move (value));
|
return insert (std::move (value));
|
||||||
@@ -882,7 +899,7 @@ public:
|
|||||||
|
|
||||||
template <class InputIt>
|
template <class InputIt>
|
||||||
void
|
void
|
||||||
insert (InputIt first, InputIt const& last)
|
insert (InputIt first, InputIt last)
|
||||||
{
|
{
|
||||||
for (; first != last; ++first)
|
for (; first != last; ++first)
|
||||||
insert (cend(), *first);
|
insert (cend(), *first);
|
||||||
@@ -911,7 +928,7 @@ public:
|
|||||||
// map, set
|
// map, set
|
||||||
template <bool maybe_multi = IsMulti, class... Args>
|
template <bool maybe_multi = IsMulti, class... Args>
|
||||||
auto
|
auto
|
||||||
emplace_hint (const_iterator const& hint, Args&&... args) ->
|
emplace_hint (const_iterator hint, Args&&... args) ->
|
||||||
typename std::enable_if <! maybe_multi,
|
typename std::enable_if <! maybe_multi,
|
||||||
std::pair <iterator, bool>>::type;
|
std::pair <iterator, bool>>::type;
|
||||||
|
|
||||||
@@ -919,24 +936,26 @@ public:
|
|||||||
template <bool maybe_multi = IsMulti, class... Args>
|
template <bool maybe_multi = IsMulti, class... Args>
|
||||||
typename std::enable_if <maybe_multi,
|
typename std::enable_if <maybe_multi,
|
||||||
iterator>::type
|
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'
|
// VFALCO TODO Figure out how to utilize 'hint'
|
||||||
return emplace <maybe_multi> (
|
return emplace <maybe_multi> (
|
||||||
std::forward <Args> (args)...);
|
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>
|
detail::aged_container_iterator <false, Iterator, Base>
|
||||||
erase (detail::aged_container_iterator <
|
erase (detail::aged_container_iterator <is_const, Iterator, Base> pos);
|
||||||
is_const, Iterator, Base> const& 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>
|
detail::aged_container_iterator <false, Iterator, Base>
|
||||||
erase (detail::aged_container_iterator <
|
erase (detail::aged_container_iterator <is_const, Iterator, Base> first,
|
||||||
is_const, Iterator, Base> first,
|
detail::aged_container_iterator <is_const, Iterator, Base> last);
|
||||||
detail::aged_container_iterator <
|
|
||||||
is_const, Iterator, Base> const& last);
|
|
||||||
|
|
||||||
template <class K>
|
template <class K>
|
||||||
auto
|
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
|
void
|
||||||
touch (detail::aged_container_iterator <
|
touch (detail::aged_container_iterator <is_const, Iterator, Base> pos)
|
||||||
is_const, Iterator, Base> const& pos)
|
|
||||||
{
|
{
|
||||||
touch (pos, clock().now());
|
touch (pos, clock().now());
|
||||||
}
|
}
|
||||||
@@ -1176,10 +1196,12 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
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
|
void
|
||||||
touch (detail::aged_container_iterator <
|
touch (detail::aged_container_iterator <
|
||||||
is_const, Iterator, Base> const& pos,
|
is_const, Iterator, Base> pos,
|
||||||
typename clock_type::time_point const& now);
|
typename clock_type::time_point const& now);
|
||||||
|
|
||||||
template <bool maybe_propagate = std::allocator_traits <
|
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>
|
template <bool maybe_multi, class... Args>
|
||||||
auto
|
auto
|
||||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
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,
|
typename std::enable_if <! maybe_multi,
|
||||||
std::pair <iterator, bool>>::type
|
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,
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||||
class Duration, class Compare, class Allocator>
|
class Duration, class Compare, class Allocator>
|
||||||
template <bool is_const, class Iterator, class Base>
|
template <bool is_const, class Iterator, class Base, class>
|
||||||
auto
|
detail::aged_container_iterator <false, Iterator, Base>
|
||||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||||
erase (detail::aged_container_iterator <
|
erase (detail::aged_container_iterator <is_const, Iterator, Base> pos)
|
||||||
is_const, Iterator, Base> const& pos) ->
|
|
||||||
detail::aged_container_iterator <false, Iterator, Base>
|
|
||||||
{
|
{
|
||||||
auto iter (pos.iterator());
|
unlink_and_delete_element(&*((pos++).iterator()));
|
||||||
auto p (&*iter++);
|
|
||||||
unlink_and_delete_element (p);
|
|
||||||
return detail::aged_container_iterator <
|
return detail::aged_container_iterator <
|
||||||
false, Iterator, Base> (iter);
|
false, Iterator, Base> (pos.iterator());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||||
class Duration, class Compare, class Allocator>
|
class Duration, class Compare, class Allocator>
|
||||||
template <bool is_const, class Iterator, class Base>
|
template <bool is_const, class Iterator, class Base, class>
|
||||||
auto
|
detail::aged_container_iterator <false, Iterator, Base>
|
||||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||||
erase (detail::aged_container_iterator <
|
erase (detail::aged_container_iterator <is_const, Iterator, Base> first,
|
||||||
is_const, Iterator, Base> first,
|
detail::aged_container_iterator <is_const, Iterator, Base> last)
|
||||||
detail::aged_container_iterator <
|
|
||||||
is_const, Iterator, Base> const& last) ->
|
|
||||||
detail::aged_container_iterator <false, Iterator, Base>
|
|
||||||
{
|
{
|
||||||
for (; first != last;)
|
for (; first != last;)
|
||||||
{
|
unlink_and_delete_element(&*((first++).iterator()));
|
||||||
auto p (&*first++);
|
|
||||||
unlink_and_delete_element (p);
|
|
||||||
}
|
|
||||||
return detail::aged_container_iterator <
|
return detail::aged_container_iterator <
|
||||||
false, Iterator, Base> (first.iterator());
|
false, Iterator, Base> (first.iterator());
|
||||||
}
|
}
|
||||||
@@ -1839,11 +1852,11 @@ operator== (
|
|||||||
|
|
||||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
||||||
class Duration, class Compare, class Allocator>
|
class Duration, class Compare, class Allocator>
|
||||||
template <bool is_const, class Iterator, class Base>
|
template <bool is_const, class Iterator, class Base, class>
|
||||||
void
|
void
|
||||||
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
aged_ordered_container <IsMulti, IsMap, Key, T, Duration, Compare, Allocator>::
|
||||||
touch (detail::aged_container_iterator <
|
touch (detail::aged_container_iterator <
|
||||||
is_const, Iterator, Base> const& pos,
|
is_const, Iterator, Base> pos,
|
||||||
typename clock_type::time_point const& now)
|
typename clock_type::time_point const& now)
|
||||||
{
|
{
|
||||||
auto& e (*pos.iterator());
|
auto& e (*pos.iterator());
|
||||||
|
|||||||
@@ -584,13 +584,14 @@ private:
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
void delete_element (element* p)
|
void delete_element (element const* p)
|
||||||
{
|
{
|
||||||
ElementAllocatorTraits::destroy (m_config.alloc(), 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.erase (
|
||||||
chronological.list.iterator_to (*p));
|
chronological.list.iterator_to (*p));
|
||||||
@@ -609,12 +610,14 @@ public:
|
|||||||
typedef typename std::allocator_traits <
|
typedef typename std::allocator_traits <
|
||||||
Allocator>::const_pointer const_pointer;
|
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;
|
typename cont_type::iterator> iterator;
|
||||||
typedef detail::aged_container_iterator <true,
|
typedef detail::aged_container_iterator <true,
|
||||||
typename cont_type::iterator> const_iterator;
|
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;
|
typename cont_type::local_iterator> local_iterator;
|
||||||
typedef detail::aged_container_iterator <true,
|
typedef detail::aged_container_iterator <true,
|
||||||
typename cont_type::local_iterator> const_local_iterator;
|
typename cont_type::local_iterator> const_local_iterator;
|
||||||
@@ -631,11 +634,13 @@ public:
|
|||||||
class chronological_t
|
class chronological_t
|
||||||
{
|
{
|
||||||
public:
|
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;
|
typename list_type::iterator> iterator;
|
||||||
typedef detail::aged_container_iterator <true,
|
typedef detail::aged_container_iterator <true,
|
||||||
typename list_type::iterator> const_iterator;
|
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;
|
typename list_type::reverse_iterator> reverse_iterator;
|
||||||
typedef detail::aged_container_iterator <true,
|
typedef detail::aged_container_iterator <true,
|
||||||
typename list_type::reverse_iterator> const_reverse_iterator;
|
typename list_type::reverse_iterator> const_reverse_iterator;
|
||||||
@@ -1021,7 +1026,7 @@ public:
|
|||||||
template <bool maybe_multi = IsMulti>
|
template <bool maybe_multi = IsMulti>
|
||||||
typename std::enable_if <maybe_multi,
|
typename std::enable_if <maybe_multi,
|
||||||
iterator>::type
|
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
|
// VFALCO TODO The hint could be used to let
|
||||||
// the client order equal ranges
|
// the client order equal ranges
|
||||||
@@ -1043,7 +1048,7 @@ public:
|
|||||||
template <bool maybe_multi = IsMulti>
|
template <bool maybe_multi = IsMulti>
|
||||||
typename std::enable_if <maybe_multi,
|
typename std::enable_if <maybe_multi,
|
||||||
iterator>::type
|
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
|
// VFALCO TODO The hint could be used to let
|
||||||
// the client order equal ranges
|
// the client order equal ranges
|
||||||
@@ -1083,7 +1088,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class InputIt>
|
template <class InputIt>
|
||||||
void insert (InputIt first, InputIt const& last)
|
void insert (InputIt first, InputIt last)
|
||||||
{
|
{
|
||||||
insert (first, last,
|
insert (first, last,
|
||||||
typename std::iterator_traits <
|
typename std::iterator_traits <
|
||||||
@@ -1113,7 +1118,7 @@ public:
|
|||||||
// set, map
|
// set, map
|
||||||
template <bool maybe_multi = IsMulti, class... Args>
|
template <bool maybe_multi = IsMulti, class... Args>
|
||||||
auto
|
auto
|
||||||
emplace_hint (const_iterator const& /*hint*/, Args&&... args) ->
|
emplace_hint (const_iterator /*hint*/, Args&&... args) ->
|
||||||
typename std::enable_if <! maybe_multi,
|
typename std::enable_if <! maybe_multi,
|
||||||
std::pair <iterator, bool>>::type;
|
std::pair <iterator, bool>>::type;
|
||||||
|
|
||||||
@@ -1121,7 +1126,7 @@ public:
|
|||||||
template <bool maybe_multi = IsMulti, class... Args>
|
template <bool maybe_multi = IsMulti, class... Args>
|
||||||
typename std::enable_if <maybe_multi,
|
typename std::enable_if <maybe_multi,
|
||||||
iterator>::type
|
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
|
// VFALCO TODO The hint could be used for multi, to let
|
||||||
// the client order equal ranges
|
// the client order equal ranges
|
||||||
@@ -1132,14 +1137,14 @@ public:
|
|||||||
template <bool is_const, class Iterator, class Base>
|
template <bool is_const, class Iterator, class Base>
|
||||||
detail::aged_container_iterator <false, Iterator, Base>
|
detail::aged_container_iterator <false, Iterator, Base>
|
||||||
erase (detail::aged_container_iterator <
|
erase (detail::aged_container_iterator <
|
||||||
is_const, Iterator, Base> const& pos);
|
is_const, Iterator, Base> pos);
|
||||||
|
|
||||||
template <bool is_const, class Iterator, class Base>
|
template <bool is_const, class Iterator, class Base>
|
||||||
detail::aged_container_iterator <false, Iterator, Base>
|
detail::aged_container_iterator <false, Iterator, Base>
|
||||||
erase (detail::aged_container_iterator <
|
erase (detail::aged_container_iterator <
|
||||||
is_const, Iterator, Base> first,
|
is_const, Iterator, Base> first,
|
||||||
detail::aged_container_iterator <
|
detail::aged_container_iterator <
|
||||||
is_const, Iterator, Base> const& last);
|
is_const, Iterator, Base> last);
|
||||||
|
|
||||||
template <class K>
|
template <class K>
|
||||||
auto
|
auto
|
||||||
@@ -1152,7 +1157,7 @@ public:
|
|||||||
template <bool is_const, class Iterator, class Base>
|
template <bool is_const, class Iterator, class Base>
|
||||||
void
|
void
|
||||||
touch (detail::aged_container_iterator <
|
touch (detail::aged_container_iterator <
|
||||||
is_const, Iterator, Base> const& pos)
|
is_const, Iterator, Base> pos)
|
||||||
{
|
{
|
||||||
touch (pos, clock().now());
|
touch (pos, clock().now());
|
||||||
}
|
}
|
||||||
@@ -1349,24 +1354,11 @@ public:
|
|||||||
class OtherAllocator,
|
class OtherAllocator,
|
||||||
bool maybe_multi = IsMulti
|
bool maybe_multi = IsMulti
|
||||||
>
|
>
|
||||||
typename std::enable_if <! maybe_multi,
|
typename std::enable_if <! maybe_multi, bool>::type
|
||||||
bool>::type
|
|
||||||
operator== (
|
operator== (
|
||||||
aged_unordered_container <false, OtherIsMap,
|
aged_unordered_container <false, OtherIsMap,
|
||||||
OtherKey, OtherT, OtherDuration, OtherHash, KeyEqual,
|
OtherKey, OtherT, OtherDuration, OtherHash, KeyEqual,
|
||||||
OtherAllocator> const& other) const
|
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 <
|
template <
|
||||||
bool OtherIsMap,
|
bool OtherIsMap,
|
||||||
@@ -1377,35 +1369,11 @@ public:
|
|||||||
class OtherAllocator,
|
class OtherAllocator,
|
||||||
bool maybe_multi = IsMulti
|
bool maybe_multi = IsMulti
|
||||||
>
|
>
|
||||||
typename std::enable_if <maybe_multi,
|
typename std::enable_if <maybe_multi, bool>::type
|
||||||
bool>::type
|
|
||||||
operator== (
|
operator== (
|
||||||
aged_unordered_container <true, OtherIsMap,
|
aged_unordered_container <true, OtherIsMap,
|
||||||
OtherKey, OtherT, OtherDuration, OtherHash, KeyEqual,
|
OtherKey, OtherT, OtherDuration, OtherHash, KeyEqual,
|
||||||
OtherAllocator> const& other) const
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <
|
template <
|
||||||
bool OtherIsMulti,
|
bool OtherIsMulti,
|
||||||
@@ -1456,7 +1424,7 @@ private:
|
|||||||
|
|
||||||
template <class InputIt>
|
template <class InputIt>
|
||||||
void
|
void
|
||||||
insert_unchecked (InputIt first, InputIt const& last)
|
insert_unchecked (InputIt first, InputIt last)
|
||||||
{
|
{
|
||||||
for (; first != last; ++first)
|
for (; first != last; ++first)
|
||||||
insert_unchecked (*first);
|
insert_unchecked (*first);
|
||||||
@@ -1464,7 +1432,7 @@ private:
|
|||||||
|
|
||||||
template <class InputIt>
|
template <class InputIt>
|
||||||
void
|
void
|
||||||
insert (InputIt first, InputIt const& last,
|
insert (InputIt first, InputIt last,
|
||||||
std::input_iterator_tag)
|
std::input_iterator_tag)
|
||||||
{
|
{
|
||||||
for (; first != last; ++first)
|
for (; first != last; ++first)
|
||||||
@@ -1473,7 +1441,7 @@ private:
|
|||||||
|
|
||||||
template <class InputIt>
|
template <class InputIt>
|
||||||
void
|
void
|
||||||
insert (InputIt first, InputIt const& last,
|
insert (InputIt first, InputIt last,
|
||||||
std::random_access_iterator_tag)
|
std::random_access_iterator_tag)
|
||||||
{
|
{
|
||||||
auto const n (std::distance (first, last));
|
auto const n (std::distance (first, last));
|
||||||
@@ -1484,7 +1452,7 @@ private:
|
|||||||
template <bool is_const, class Iterator, class Base>
|
template <bool is_const, class Iterator, class Base>
|
||||||
void
|
void
|
||||||
touch (detail::aged_container_iterator <
|
touch (detail::aged_container_iterator <
|
||||||
is_const, Iterator, Base> const& pos,
|
is_const, Iterator, Base> pos,
|
||||||
typename clock_type::time_point const& now)
|
typename clock_type::time_point const& now)
|
||||||
{
|
{
|
||||||
auto& e (*pos.iterator());
|
auto& e (*pos.iterator());
|
||||||
@@ -2268,7 +2236,7 @@ template <bool maybe_multi, class... Args>
|
|||||||
auto
|
auto
|
||||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||||
Hash, KeyEqual, Allocator>::
|
Hash, KeyEqual, Allocator>::
|
||||||
emplace_hint (const_iterator const& /*hint*/, Args&&... args) ->
|
emplace_hint (const_iterator /*hint*/, Args&&... args) ->
|
||||||
typename std::enable_if <! maybe_multi,
|
typename std::enable_if <! maybe_multi,
|
||||||
std::pair <iterator, bool>>::type
|
std::pair <iterator, bool>>::type
|
||||||
{
|
{
|
||||||
@@ -2298,13 +2266,11 @@ detail::aged_container_iterator <false, Iterator, Base>
|
|||||||
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
||||||
Hash, KeyEqual, Allocator>::
|
Hash, KeyEqual, Allocator>::
|
||||||
erase (detail::aged_container_iterator <
|
erase (detail::aged_container_iterator <
|
||||||
is_const, Iterator, Base> const& pos)
|
is_const, Iterator, Base> pos)
|
||||||
{
|
{
|
||||||
auto iter (pos.iterator());
|
unlink_and_delete_element(&*((pos++).iterator()));
|
||||||
auto p (&*iter++);
|
|
||||||
unlink_and_delete_element (p);
|
|
||||||
return detail::aged_container_iterator <
|
return detail::aged_container_iterator <
|
||||||
false, Iterator, Base> (iter);
|
false, Iterator, Base> (pos.iterator());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <bool IsMulti, bool IsMap, class Key, class T,
|
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 <
|
erase (detail::aged_container_iterator <
|
||||||
is_const, Iterator, Base> first,
|
is_const, Iterator, Base> first,
|
||||||
detail::aged_container_iterator <
|
detail::aged_container_iterator <
|
||||||
is_const, Iterator, Base> const& last)
|
is_const, Iterator, Base> last)
|
||||||
{
|
{
|
||||||
size_type n (0);
|
for (; first != last;)
|
||||||
for (; first != last; ++n)
|
unlink_and_delete_element(&*((first++).iterator()));
|
||||||
{
|
|
||||||
auto p (&*first++);
|
|
||||||
unlink_and_delete_element (p);
|
|
||||||
}
|
|
||||||
return detail::aged_container_iterator <
|
return detail::aged_container_iterator <
|
||||||
false, Iterator, Base> (first.iterator());
|
false, Iterator, Base> (first.iterator());
|
||||||
}
|
}
|
||||||
@@ -2387,6 +2350,79 @@ touch (K const& k) ->
|
|||||||
return n;
|
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
|
// 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>
|
template <class Container, class Values>
|
||||||
void checkInsertCopy (Container& c, Values const& v);
|
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
|
// ordered
|
||||||
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
||||||
typename std::enable_if <! IsUnordered>::type
|
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
|
// Modifiers
|
||||||
@@ -1232,9 +1431,12 @@ testChronological ()
|
|||||||
c.chronological.cbegin(), c.chronological.cend(),
|
c.chronological.cbegin(), c.chronological.cend(),
|
||||||
v.begin(), v.end(), equal_value <Traits> ()));
|
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());
|
expect (found != c.cend());
|
||||||
if (found == c.cend())
|
if (found == c.cend())
|
||||||
return;
|
return;
|
||||||
@@ -1243,7 +1445,30 @@ testChronological ()
|
|||||||
|
|
||||||
expect (std::equal (
|
expect (std::equal (
|
||||||
c.chronological.cbegin(), c.chronological.cend(),
|
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
|
// Container-wide comparison
|
||||||
@@ -1378,9 +1867,13 @@ testMaybeUnorderedMultiMap ()
|
|||||||
testConstructRange <IsUnordered, IsMulti, IsMap> ();
|
testConstructRange <IsUnordered, IsMulti, IsMap> ();
|
||||||
testConstructInitList <IsUnordered, IsMulti, IsMap> ();
|
testConstructInitList <IsUnordered, IsMulti, IsMap> ();
|
||||||
testCopyMove <IsUnordered, IsMulti, IsMap> ();
|
testCopyMove <IsUnordered, IsMulti, IsMap> ();
|
||||||
|
testIterator <IsUnordered, IsMulti, IsMap> ();
|
||||||
|
testReverseIterator <IsUnordered, IsMulti, IsMap> ();
|
||||||
testModifiers <IsUnordered, IsMulti, IsMap> ();
|
testModifiers <IsUnordered, IsMulti, IsMap> ();
|
||||||
testChronological <IsUnordered, IsMulti, IsMap> ();
|
testChronological <IsUnordered, IsMulti, IsMap> ();
|
||||||
testArrayCreate <IsUnordered, IsMulti, IsMap> ();
|
testArrayCreate <IsUnordered, IsMulti, IsMap> ();
|
||||||
|
testElementErase <IsUnordered, IsMulti, IsMap> ();
|
||||||
|
testRangeErase <IsUnordered, IsMulti, IsMap> ();
|
||||||
testCompare <IsUnordered, IsMulti, IsMap> ();
|
testCompare <IsUnordered, IsMulti, IsMap> ();
|
||||||
testObservers <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_multiset,container,beast);
|
||||||
BEAST_DEFINE_TESTSUITE(aged_unordered_multimap,container,beast);
|
BEAST_DEFINE_TESTSUITE(aged_unordered_multimap,container,beast);
|
||||||
|
|
||||||
}
|
} // namespace beast
|
||||||
|
|||||||
Reference in New Issue
Block a user