mirror of
https://github.com/XRPLF/rippled.git
synced 2026-04-29 15:37:57 +00:00
1864 lines
51 KiB
C++
1864 lines
51 KiB
C++
#include <xrpl/beast/clock/manual_clock.h>
|
|
#include <xrpl/beast/container/aged_map.h>
|
|
#include <xrpl/beast/container/aged_multimap.h>
|
|
#include <xrpl/beast/container/aged_multiset.h>
|
|
#include <xrpl/beast/container/aged_set.h>
|
|
#include <xrpl/beast/container/aged_unordered_map.h>
|
|
#include <xrpl/beast/container/aged_unordered_multimap.h>
|
|
#include <xrpl/beast/container/aged_unordered_multiset.h>
|
|
#include <xrpl/beast/container/aged_unordered_set.h>
|
|
#include <xrpl/beast/unit_test.h>
|
|
|
|
#include <list>
|
|
#include <vector>
|
|
|
|
#ifndef BEAST_AGED_UNORDERED_NO_ALLOC_DEFAULTCTOR
|
|
#ifdef _MSC_VER
|
|
#define BEAST_AGED_UNORDERED_NO_ALLOC_DEFAULTCTOR 0
|
|
#else
|
|
#define BEAST_AGED_UNORDERED_NO_ALLOC_DEFAULTCTOR 1
|
|
#endif
|
|
#endif
|
|
|
|
#ifndef BEAST_CONTAINER_EXTRACT_NOREF
|
|
#ifdef _MSC_VER
|
|
#define BEAST_CONTAINER_EXTRACT_NOREF 1
|
|
#else
|
|
#define BEAST_CONTAINER_EXTRACT_NOREF 1
|
|
#endif
|
|
#endif
|
|
|
|
namespace beast {
|
|
|
|
class aged_associative_container_test_base : public unit_test::suite
|
|
{
|
|
public:
|
|
template <class T>
|
|
struct CompT
|
|
{
|
|
explicit CompT(int)
|
|
{
|
|
}
|
|
|
|
CompT(CompT const&)
|
|
{
|
|
}
|
|
|
|
bool
|
|
operator()(T const& lhs, T const& rhs) const
|
|
{
|
|
return m_less(lhs, rhs);
|
|
}
|
|
|
|
private:
|
|
CompT() = delete;
|
|
std::less<T> m_less;
|
|
};
|
|
|
|
template <class T>
|
|
class HashT
|
|
{
|
|
public:
|
|
explicit HashT(int)
|
|
{
|
|
}
|
|
|
|
std::size_t
|
|
operator()(T const& t) const
|
|
{
|
|
return m_hash(t);
|
|
}
|
|
|
|
private:
|
|
HashT() = delete;
|
|
std::hash<T> m_hash;
|
|
};
|
|
|
|
template <class T>
|
|
struct EqualT
|
|
{
|
|
public:
|
|
explicit EqualT(int)
|
|
{
|
|
}
|
|
|
|
bool
|
|
operator()(T const& lhs, T const& rhs) const
|
|
{
|
|
return m_eq(lhs, rhs);
|
|
}
|
|
|
|
private:
|
|
EqualT() = delete;
|
|
std::equal_to<T> m_eq;
|
|
};
|
|
|
|
template <class T>
|
|
struct AllocT
|
|
{
|
|
using value_type = T;
|
|
|
|
// using std::true_type::type = propagate_on_container_swap :;
|
|
|
|
template <class U>
|
|
struct rebind
|
|
{
|
|
using other = AllocT<U>;
|
|
};
|
|
|
|
explicit AllocT(int)
|
|
{
|
|
}
|
|
|
|
AllocT(AllocT const&) = default;
|
|
|
|
template <class U>
|
|
AllocT(AllocT<U> const&)
|
|
{
|
|
}
|
|
|
|
template <class U>
|
|
bool
|
|
operator==(AllocT<U> const&) const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
template <class U>
|
|
bool
|
|
operator!=(AllocT<U> const& o) const
|
|
{
|
|
return !(*this == o);
|
|
}
|
|
|
|
T*
|
|
allocate(std::size_t n, T const* = 0)
|
|
{
|
|
return static_cast<T*>(::operator new(n * sizeof(T)));
|
|
}
|
|
|
|
void
|
|
deallocate(T* p, std::size_t)
|
|
{
|
|
::operator delete(p);
|
|
}
|
|
|
|
#if !BEAST_AGED_UNORDERED_NO_ALLOC_DEFAULTCTOR
|
|
AllocT()
|
|
{
|
|
}
|
|
#else
|
|
private:
|
|
AllocT() = delete;
|
|
#endif
|
|
};
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// ordered
|
|
template <class Base, bool IsUnordered>
|
|
class MaybeUnordered : public Base
|
|
{
|
|
public:
|
|
using Comp = std::less<typename Base::Key>;
|
|
using MyComp = CompT<typename Base::Key>;
|
|
|
|
protected:
|
|
static std::string
|
|
name_ordered_part()
|
|
{
|
|
return "";
|
|
}
|
|
};
|
|
|
|
// unordered
|
|
template <class Base>
|
|
class MaybeUnordered<Base, true> : public Base
|
|
{
|
|
public:
|
|
using Hash = std::hash<typename Base::Key>;
|
|
using Equal = std::equal_to<typename Base::Key>;
|
|
using MyHash = HashT<typename Base::Key>;
|
|
using MyEqual = EqualT<typename Base::Key>;
|
|
|
|
protected:
|
|
static std::string
|
|
name_ordered_part()
|
|
{
|
|
return "unordered_";
|
|
}
|
|
};
|
|
|
|
// unique
|
|
template <class Base, bool IsMulti>
|
|
class MaybeMulti : public Base
|
|
{
|
|
public:
|
|
protected:
|
|
static std::string
|
|
name_multi_part()
|
|
{
|
|
return "";
|
|
}
|
|
};
|
|
|
|
// multi
|
|
template <class Base>
|
|
class MaybeMulti<Base, true> : public Base
|
|
{
|
|
public:
|
|
protected:
|
|
static std::string
|
|
name_multi_part()
|
|
{
|
|
return "multi";
|
|
}
|
|
};
|
|
|
|
// set
|
|
template <class Base, bool IsMap>
|
|
class MaybeMap : public Base
|
|
{
|
|
public:
|
|
using T = void;
|
|
using Value = typename Base::Key;
|
|
using Values = std::vector<Value>;
|
|
|
|
static typename Base::Key const&
|
|
extract(Value const& value)
|
|
{
|
|
return value; // NOLINT(bugprone-return-const-ref-from-parameter)
|
|
}
|
|
|
|
static Values
|
|
values()
|
|
{
|
|
Values v{
|
|
"apple",
|
|
"banana",
|
|
"cherry",
|
|
"grape",
|
|
"orange",
|
|
};
|
|
return v;
|
|
}
|
|
|
|
protected:
|
|
static std::string
|
|
name_map_part()
|
|
{
|
|
return "set";
|
|
}
|
|
};
|
|
|
|
// map
|
|
template <class Base>
|
|
class MaybeMap<Base, true> : public Base
|
|
{
|
|
public:
|
|
using T = int;
|
|
using Value = std::pair<typename Base::Key, T>;
|
|
using Values = std::vector<Value>;
|
|
|
|
static typename Base::Key const&
|
|
extract(Value const& value)
|
|
{
|
|
return value.first;
|
|
}
|
|
|
|
static Values
|
|
values()
|
|
{
|
|
Values v{
|
|
std::make_pair("apple", 1),
|
|
std::make_pair("banana", 2),
|
|
std::make_pair("cherry", 3),
|
|
std::make_pair("grape", 4),
|
|
std::make_pair("orange", 5)};
|
|
return v;
|
|
}
|
|
|
|
protected:
|
|
static std::string
|
|
name_map_part()
|
|
{
|
|
return "map";
|
|
}
|
|
};
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// ordered
|
|
template <class Base, bool IsUnordered = Base::is_unordered::value>
|
|
struct ContType
|
|
{
|
|
template <
|
|
class Compare = std::less<typename Base::Key>,
|
|
class Allocator = std::allocator<typename Base::Value>>
|
|
using Cont = detail::aged_ordered_container<
|
|
Base::is_multi::value,
|
|
Base::is_map::value,
|
|
typename Base::Key,
|
|
typename Base::T,
|
|
typename Base::Clock,
|
|
Compare,
|
|
Allocator>;
|
|
};
|
|
|
|
// unordered
|
|
template <class Base>
|
|
struct ContType<Base, true>
|
|
{
|
|
template <
|
|
class Hash = std::hash<typename Base::Key>,
|
|
class KeyEqual = std::equal_to<typename Base::Key>,
|
|
class Allocator = std::allocator<typename Base::Value>>
|
|
using Cont = detail::aged_unordered_container<
|
|
Base::is_multi::value,
|
|
Base::is_map::value,
|
|
typename Base::Key,
|
|
typename Base::T,
|
|
typename Base::Clock,
|
|
Hash,
|
|
KeyEqual,
|
|
Allocator>;
|
|
};
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
struct TestTraitsBase
|
|
{
|
|
using Key = std::string;
|
|
using Clock = std::chrono::steady_clock;
|
|
using ManualClock = manual_clock<Clock>;
|
|
};
|
|
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
struct TestTraitsHelper
|
|
: MaybeUnordered<MaybeMulti<MaybeMap<TestTraitsBase, IsMap>, IsMulti>, IsUnordered>
|
|
{
|
|
private:
|
|
using Base =
|
|
MaybeUnordered<MaybeMulti<MaybeMap<TestTraitsBase, IsMap>, IsMulti>, IsUnordered>;
|
|
|
|
public:
|
|
using typename Base::Key;
|
|
|
|
using is_unordered = std::integral_constant<bool, IsUnordered>;
|
|
using is_multi = std::integral_constant<bool, IsMulti>;
|
|
using is_map = std::integral_constant<bool, IsMap>;
|
|
|
|
using Alloc = std::allocator<typename Base::Value>;
|
|
using MyAlloc = AllocT<typename Base::Value>;
|
|
|
|
static std::string
|
|
name()
|
|
{
|
|
return std::string("aged_") + Base::name_ordered_part() + Base::name_multi_part() +
|
|
Base::name_map_part();
|
|
}
|
|
};
|
|
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
struct TestTraits : TestTraitsHelper<IsUnordered, IsMulti, IsMap>,
|
|
ContType<TestTraitsHelper<IsUnordered, IsMulti, IsMap>>
|
|
{
|
|
};
|
|
|
|
template <class Cont>
|
|
static std::string
|
|
name(Cont const&)
|
|
{
|
|
return TestTraits<Cont::is_unordered, Cont::is_multi, Cont::is_map>::name();
|
|
}
|
|
|
|
template <class Traits>
|
|
struct equal_value
|
|
{
|
|
bool
|
|
operator()(typename Traits::Value const& lhs, typename Traits::Value const& rhs)
|
|
{
|
|
return Traits::extract(lhs) == Traits::extract(rhs);
|
|
}
|
|
};
|
|
|
|
template <class Cont>
|
|
static std::vector<typename Cont::value_type>
|
|
make_list(Cont const& c)
|
|
{
|
|
return std::vector<typename Cont::value_type>(c.begin(), c.end());
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
template <class Container, class Values>
|
|
typename std::enable_if<Container::is_map::value && !Container::is_multi::value>::type
|
|
checkMapContents(Container& c, Values const& v);
|
|
|
|
template <class Container, class Values>
|
|
typename std::enable_if<!(Container::is_map::value && !Container::is_multi::value)>::type
|
|
checkMapContents(Container, Values const&)
|
|
{
|
|
}
|
|
|
|
// unordered
|
|
template <class C, class Values>
|
|
typename std::enable_if<std::remove_reference<C>::type::is_unordered::value>::type
|
|
checkUnorderedContentsRefRef(C&& c, Values const& v);
|
|
|
|
template <class C, class Values>
|
|
typename std::enable_if<!std::remove_reference<C>::type::is_unordered::value>::type
|
|
checkUnorderedContentsRefRef(C&&, Values const&)
|
|
{
|
|
}
|
|
|
|
template <class C, class Values>
|
|
void
|
|
checkContentsRefRef(C&& c, Values const& v);
|
|
|
|
template <class Cont, class Values>
|
|
void
|
|
checkContents(Cont& c, Values const& v);
|
|
|
|
template <class Cont>
|
|
void
|
|
checkContents(Cont& c);
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// ordered
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
typename std::enable_if<!IsUnordered>::type
|
|
testConstructEmpty();
|
|
|
|
// unordered
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
typename std::enable_if<IsUnordered>::type
|
|
testConstructEmpty();
|
|
|
|
// ordered
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
typename std::enable_if<!IsUnordered>::type
|
|
testConstructRange();
|
|
|
|
// unordered
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
typename std::enable_if<IsUnordered>::type
|
|
testConstructRange();
|
|
|
|
// ordered
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
typename std::enable_if<!IsUnordered>::type
|
|
testConstructInitList();
|
|
|
|
// unordered
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
typename std::enable_if<IsUnordered>::type
|
|
testConstructInitList();
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
void
|
|
testCopyMove();
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
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);
|
|
|
|
template <class Container, class Values>
|
|
void
|
|
checkInsertMove(Container& c, Values const& v);
|
|
|
|
template <class Container, class Values>
|
|
void
|
|
checkInsertHintCopy(Container& c, Values const& v);
|
|
|
|
template <class Container, class Values>
|
|
void
|
|
checkInsertHintMove(Container& c, Values const& v);
|
|
|
|
template <class Container, class Values>
|
|
void
|
|
checkEmplace(Container& c, Values const& v);
|
|
|
|
template <class Container, class Values>
|
|
void
|
|
checkEmplaceHint(Container& c, Values const& v);
|
|
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
void
|
|
testModifiers();
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
void
|
|
testChronological();
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// map, unordered_map
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
typename std::enable_if<IsMap && !IsMulti>::type
|
|
testArrayCreate();
|
|
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
typename std::enable_if<!(IsMap && !IsMulti)>::type
|
|
testArrayCreate()
|
|
{
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// 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
|
|
testCompare();
|
|
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
typename std::enable_if<IsUnordered>::type
|
|
testCompare()
|
|
{
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// ordered
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
typename std::enable_if<!IsUnordered>::type
|
|
testObservers();
|
|
|
|
// unordered
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
typename std::enable_if<IsUnordered>::type
|
|
testObservers();
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
void
|
|
testMaybeUnorderedMultiMap();
|
|
|
|
template <bool IsUnordered, bool IsMulti>
|
|
void
|
|
testMaybeUnorderedMulti();
|
|
|
|
template <bool IsUnordered>
|
|
void
|
|
testMaybeUnordered();
|
|
};
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// Check contents via at() and operator[]
|
|
// map, unordered_map
|
|
template <class Container, class Values>
|
|
typename std::enable_if<Container::is_map::value && !Container::is_multi::value>::type
|
|
aged_associative_container_test_base::checkMapContents(Container& c, Values const& v)
|
|
{
|
|
if (v.empty())
|
|
{
|
|
BEAST_EXPECT(c.empty());
|
|
BEAST_EXPECT(c.size() == 0);
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
// Make sure no exception is thrown
|
|
for (auto const& e : v)
|
|
c.at(e.first);
|
|
for (auto const& e : v)
|
|
BEAST_EXPECT(c.operator[](e.first) == e.second);
|
|
}
|
|
catch (std::out_of_range const&)
|
|
{
|
|
fail("caught exception");
|
|
}
|
|
}
|
|
|
|
// unordered
|
|
template <class C, class Values>
|
|
typename std::enable_if<std::remove_reference<C>::type::is_unordered::value>::type
|
|
aged_associative_container_test_base::checkUnorderedContentsRefRef(C&& c, Values const& v)
|
|
{
|
|
using Cont = typename std::remove_reference<C>::type;
|
|
using Traits =
|
|
TestTraits<Cont::is_unordered::value, Cont::is_multi::value, Cont::is_map::value>;
|
|
using size_type = typename Cont::size_type;
|
|
auto const hash(c.hash_function());
|
|
auto const key_eq(c.key_eq());
|
|
for (size_type i(0); i < c.bucket_count(); ++i)
|
|
{
|
|
auto const last(c.end(i));
|
|
for (auto iter(c.begin(i)); iter != last; ++iter)
|
|
{
|
|
auto const match(
|
|
std::find_if(v.begin(), v.end(), [iter](typename Values::value_type const& e) {
|
|
return Traits::extract(*iter) == Traits::extract(e);
|
|
}));
|
|
BEAST_EXPECT(match != v.end());
|
|
BEAST_EXPECT(key_eq(Traits::extract(*iter), Traits::extract(*match)));
|
|
BEAST_EXPECT(hash(Traits::extract(*iter)) == hash(Traits::extract(*match)));
|
|
}
|
|
}
|
|
}
|
|
|
|
template <class C, class Values>
|
|
void
|
|
aged_associative_container_test_base::checkContentsRefRef(C&& c, Values const& v)
|
|
{
|
|
using Cont = typename std::remove_reference<C>::type;
|
|
using size_type = typename Cont::size_type;
|
|
|
|
BEAST_EXPECT(c.size() == v.size());
|
|
BEAST_EXPECT(size_type(std::distance(c.begin(), c.end())) == v.size());
|
|
BEAST_EXPECT(size_type(std::distance(c.cbegin(), c.cend())) == v.size());
|
|
BEAST_EXPECT(
|
|
size_type(std::distance(c.chronological.begin(), c.chronological.end())) == v.size());
|
|
BEAST_EXPECT(
|
|
size_type(std::distance(c.chronological.cbegin(), c.chronological.cend())) == v.size());
|
|
BEAST_EXPECT(
|
|
size_type(std::distance(c.chronological.rbegin(), c.chronological.rend())) == v.size());
|
|
BEAST_EXPECT(
|
|
size_type(std::distance(c.chronological.crbegin(), c.chronological.crend())) == v.size());
|
|
|
|
checkUnorderedContentsRefRef(c, v);
|
|
}
|
|
|
|
template <class Cont, class Values>
|
|
void
|
|
aged_associative_container_test_base::checkContents(Cont& c, Values const& v)
|
|
{
|
|
checkContentsRefRef(c, v);
|
|
checkContentsRefRef(const_cast<Cont const&>(c), v);
|
|
checkMapContents(c, v);
|
|
}
|
|
|
|
template <class Cont>
|
|
void
|
|
aged_associative_container_test_base::checkContents(Cont& c)
|
|
{
|
|
using Traits =
|
|
TestTraits<Cont::is_unordered::value, Cont::is_multi::value, Cont::is_map::value>;
|
|
using Values = typename Traits::Values;
|
|
checkContents(c, Values());
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
// Construction
|
|
//
|
|
//------------------------------------------------------------------------------
|
|
|
|
// ordered
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
typename std::enable_if<!IsUnordered>::type
|
|
aged_associative_container_test_base::testConstructEmpty()
|
|
{
|
|
using Traits = TestTraits<IsUnordered, IsMulti, IsMap>;
|
|
using Comp = typename Traits::Comp;
|
|
using Alloc = typename Traits::Alloc;
|
|
using MyComp = typename Traits::MyComp;
|
|
using MyAlloc = typename Traits::MyAlloc;
|
|
typename Traits::ManualClock clock;
|
|
|
|
// testcase (Traits::name() + " empty");
|
|
testcase("empty");
|
|
|
|
{
|
|
typename Traits::template Cont<Comp, Alloc> c(clock);
|
|
checkContents(c);
|
|
}
|
|
|
|
{
|
|
typename Traits::template Cont<MyComp, Alloc> c(clock, MyComp(1));
|
|
checkContents(c);
|
|
}
|
|
|
|
{
|
|
typename Traits::template Cont<Comp, MyAlloc> c(clock, MyAlloc(1));
|
|
checkContents(c);
|
|
}
|
|
|
|
{
|
|
typename Traits::template Cont<MyComp, MyAlloc> c(clock, MyComp(1), MyAlloc(1));
|
|
checkContents(c);
|
|
}
|
|
}
|
|
|
|
// unordered
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
typename std::enable_if<IsUnordered>::type
|
|
aged_associative_container_test_base::testConstructEmpty()
|
|
{
|
|
using Traits = TestTraits<IsUnordered, IsMulti, IsMap>;
|
|
using Hash = typename Traits::Hash;
|
|
using Equal = typename Traits::Equal;
|
|
using Alloc = typename Traits::Alloc;
|
|
using MyHash = typename Traits::MyHash;
|
|
using MyEqual = typename Traits::MyEqual;
|
|
using MyAlloc = typename Traits::MyAlloc;
|
|
typename Traits::ManualClock clock;
|
|
|
|
// testcase (Traits::name() + " empty");
|
|
testcase("empty");
|
|
{
|
|
typename Traits::template Cont<Hash, Equal, Alloc> c(clock);
|
|
checkContents(c);
|
|
}
|
|
|
|
{
|
|
typename Traits::template Cont<MyHash, Equal, Alloc> c(clock, MyHash(1));
|
|
checkContents(c);
|
|
}
|
|
|
|
{
|
|
typename Traits::template Cont<Hash, MyEqual, Alloc> c(clock, MyEqual(1));
|
|
checkContents(c);
|
|
}
|
|
|
|
{
|
|
typename Traits::template Cont<Hash, Equal, MyAlloc> c(clock, MyAlloc(1));
|
|
checkContents(c);
|
|
}
|
|
|
|
{
|
|
typename Traits::template Cont<MyHash, MyEqual, Alloc> c(clock, MyHash(1), MyEqual(1));
|
|
checkContents(c);
|
|
}
|
|
|
|
{
|
|
typename Traits::template Cont<MyHash, Equal, MyAlloc> c(clock, MyHash(1), MyAlloc(1));
|
|
checkContents(c);
|
|
}
|
|
|
|
{
|
|
typename Traits::template Cont<Hash, MyEqual, MyAlloc> c(clock, MyEqual(1), MyAlloc(1));
|
|
checkContents(c);
|
|
}
|
|
|
|
{
|
|
typename Traits::template Cont<MyHash, MyEqual, MyAlloc> c(
|
|
clock, MyHash(1), MyEqual(1), MyAlloc(1));
|
|
checkContents(c);
|
|
}
|
|
}
|
|
|
|
// ordered
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
typename std::enable_if<!IsUnordered>::type
|
|
aged_associative_container_test_base::testConstructRange()
|
|
{
|
|
using Traits = TestTraits<IsUnordered, IsMulti, IsMap>;
|
|
using Comp = typename Traits::Comp;
|
|
using Alloc = typename Traits::Alloc;
|
|
using MyComp = typename Traits::MyComp;
|
|
using MyAlloc = typename Traits::MyAlloc;
|
|
typename Traits::ManualClock clock;
|
|
auto const v(Traits::values());
|
|
|
|
// testcase (Traits::name() + " range");
|
|
testcase("range");
|
|
|
|
{
|
|
typename Traits::template Cont<Comp, Alloc> c(v.begin(), v.end(), clock);
|
|
checkContents(c, v);
|
|
}
|
|
|
|
{
|
|
typename Traits::template Cont<MyComp, Alloc> c(v.begin(), v.end(), clock, MyComp(1));
|
|
checkContents(c, v);
|
|
}
|
|
|
|
{
|
|
typename Traits::template Cont<Comp, MyAlloc> c(v.begin(), v.end(), clock, MyAlloc(1));
|
|
checkContents(c, v);
|
|
}
|
|
|
|
{
|
|
typename Traits::template Cont<MyComp, MyAlloc> c(
|
|
v.begin(), v.end(), clock, MyComp(1), MyAlloc(1));
|
|
checkContents(c, v);
|
|
}
|
|
|
|
// swap
|
|
|
|
{
|
|
typename Traits::template Cont<Comp, Alloc> c1(v.begin(), v.end(), clock);
|
|
typename Traits::template Cont<Comp, Alloc> c2(clock);
|
|
std::swap(c1, c2);
|
|
checkContents(c2, v);
|
|
}
|
|
}
|
|
|
|
// unordered
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
typename std::enable_if<IsUnordered>::type
|
|
aged_associative_container_test_base::testConstructRange()
|
|
{
|
|
using Traits = TestTraits<IsUnordered, IsMulti, IsMap>;
|
|
using Hash = typename Traits::Hash;
|
|
using Equal = typename Traits::Equal;
|
|
using Alloc = typename Traits::Alloc;
|
|
using MyHash = typename Traits::MyHash;
|
|
using MyEqual = typename Traits::MyEqual;
|
|
using MyAlloc = typename Traits::MyAlloc;
|
|
typename Traits::ManualClock clock;
|
|
auto const v(Traits::values());
|
|
|
|
// testcase (Traits::name() + " range");
|
|
testcase("range");
|
|
|
|
{
|
|
typename Traits::template Cont<Hash, Equal, Alloc> c(v.begin(), v.end(), clock);
|
|
checkContents(c, v);
|
|
}
|
|
|
|
{
|
|
typename Traits::template Cont<MyHash, Equal, Alloc> c(
|
|
v.begin(), v.end(), clock, MyHash(1));
|
|
checkContents(c, v);
|
|
}
|
|
|
|
{
|
|
typename Traits::template Cont<Hash, MyEqual, Alloc> c(
|
|
v.begin(), v.end(), clock, MyEqual(1));
|
|
checkContents(c, v);
|
|
}
|
|
|
|
{
|
|
typename Traits::template Cont<Hash, Equal, MyAlloc> c(
|
|
v.begin(), v.end(), clock, MyAlloc(1));
|
|
checkContents(c, v);
|
|
}
|
|
|
|
{
|
|
typename Traits::template Cont<MyHash, MyEqual, Alloc> c(
|
|
v.begin(), v.end(), clock, MyHash(1), MyEqual(1));
|
|
checkContents(c, v);
|
|
}
|
|
|
|
{
|
|
typename Traits::template Cont<MyHash, Equal, MyAlloc> c(
|
|
v.begin(), v.end(), clock, MyHash(1), MyAlloc(1));
|
|
checkContents(c, v);
|
|
}
|
|
|
|
{
|
|
typename Traits::template Cont<Hash, MyEqual, MyAlloc> c(
|
|
v.begin(), v.end(), clock, MyEqual(1), MyAlloc(1));
|
|
checkContents(c, v);
|
|
}
|
|
|
|
{
|
|
typename Traits::template Cont<MyHash, MyEqual, MyAlloc> c(
|
|
v.begin(), v.end(), clock, MyHash(1), MyEqual(1), MyAlloc(1));
|
|
checkContents(c, v);
|
|
}
|
|
}
|
|
|
|
// ordered
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
typename std::enable_if<!IsUnordered>::type
|
|
aged_associative_container_test_base::testConstructInitList()
|
|
{
|
|
using Traits = TestTraits<IsUnordered, IsMulti, IsMap>;
|
|
typename Traits::ManualClock clock;
|
|
|
|
// testcase (Traits::name() + " init-list");
|
|
testcase("init-list");
|
|
|
|
// VFALCO TODO
|
|
|
|
pass();
|
|
}
|
|
|
|
// unordered
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
typename std::enable_if<IsUnordered>::type
|
|
aged_associative_container_test_base::testConstructInitList()
|
|
{
|
|
using Traits = TestTraits<IsUnordered, IsMulti, IsMap>;
|
|
typename Traits::ManualClock clock;
|
|
|
|
// testcase (Traits::name() + " init-list");
|
|
testcase("init-list");
|
|
|
|
// VFALCO TODO
|
|
pass();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
// Copy/Move construction and assign
|
|
//
|
|
//------------------------------------------------------------------------------
|
|
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
void
|
|
aged_associative_container_test_base::testCopyMove()
|
|
{
|
|
using Traits = TestTraits<IsUnordered, IsMulti, IsMap>;
|
|
using Alloc = typename Traits::Alloc;
|
|
typename Traits::ManualClock clock;
|
|
auto const v(Traits::values());
|
|
|
|
// testcase (Traits::name() + " copy/move");
|
|
testcase("copy/move");
|
|
|
|
// copy
|
|
|
|
{
|
|
typename Traits::template Cont<> c(v.begin(), v.end(), clock);
|
|
typename Traits::template Cont<> c2(c);
|
|
checkContents(c, v);
|
|
checkContents(c2, v);
|
|
BEAST_EXPECT(c == c2);
|
|
unexpected(c != c2);
|
|
}
|
|
|
|
{
|
|
typename Traits::template Cont<> c(v.begin(), v.end(), clock);
|
|
typename Traits::template Cont<> c2(c, Alloc());
|
|
checkContents(c, v);
|
|
checkContents(c2, v);
|
|
BEAST_EXPECT(c == c2);
|
|
unexpected(c != c2);
|
|
}
|
|
|
|
{
|
|
typename Traits::template Cont<> c(v.begin(), v.end(), clock);
|
|
typename Traits::template Cont<> c2(clock);
|
|
c2 = c;
|
|
checkContents(c, v);
|
|
checkContents(c2, v);
|
|
BEAST_EXPECT(c == c2);
|
|
unexpected(c != c2);
|
|
}
|
|
|
|
// move
|
|
|
|
{
|
|
typename Traits::template Cont<> c(v.begin(), v.end(), clock);
|
|
typename Traits::template Cont<> c2(std::move(c));
|
|
checkContents(c2, v);
|
|
}
|
|
|
|
{
|
|
typename Traits::template Cont<> c(v.begin(), v.end(), clock);
|
|
typename Traits::template Cont<> c2(std::move(c), Alloc());
|
|
checkContents(c2, v);
|
|
}
|
|
|
|
{
|
|
typename Traits::template Cont<> c(v.begin(), v.end(), clock);
|
|
typename Traits::template Cont<> c2(clock);
|
|
c2 = std::move(c);
|
|
checkContents(c2, v);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
// Iterator construction and assignment
|
|
//
|
|
//------------------------------------------------------------------------------
|
|
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
void
|
|
aged_associative_container_test_base::testIterator()
|
|
{
|
|
using Traits = TestTraits<IsUnordered, IsMulti, IsMap>;
|
|
typename Traits::ManualClock 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};
|
|
BEAST_EXPECT(nnIt_0 == nnIt_1);
|
|
iterator nnIt_2;
|
|
nnIt_2 = nnIt_1;
|
|
BEAST_EXPECT(nnIt_1 == nnIt_2);
|
|
|
|
// 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};
|
|
BEAST_EXPECT(ccIt_0 == ccIt_1);
|
|
const_iterator ccIt_2;
|
|
ccIt_2 = ccIt_1;
|
|
BEAST_EXPECT(ccIt_1 == ccIt_2);
|
|
|
|
// Comparison between iterator and const_iterator is okay
|
|
BEAST_EXPECT(nnIt_0 == ccIt_0);
|
|
BEAST_EXPECT(ccIt_1 == nnIt_1);
|
|
|
|
// Should be able to construct a const_iterator from an iterator.
|
|
const_iterator ncIt_3{c.begin()};
|
|
const_iterator ncIt_4{nnIt_0};
|
|
BEAST_EXPECT(ncIt_3 == ncIt_4);
|
|
const_iterator ncIt_5;
|
|
ncIt_5 = nnIt_2;
|
|
BEAST_EXPECT(ncIt_5 == ncIt_4);
|
|
|
|
// 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()
|
|
{
|
|
using Traits = TestTraits<IsUnordered, IsMulti, IsMap>;
|
|
typename Traits::ManualClock 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 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};
|
|
BEAST_EXPECT(rNrNit_0 == rNrNit_1);
|
|
reverse_iterator xXrNit_2;
|
|
xXrNit_2 = rNrNit_1;
|
|
BEAST_EXPECT(rNrNit_1 == xXrNit_2);
|
|
|
|
// 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};
|
|
BEAST_EXPECT(rCrCit_0 == rCrCit_1);
|
|
const_reverse_iterator xXrCit_2;
|
|
xXrCit_2 = rCrCit_1;
|
|
BEAST_EXPECT(rCrCit_1 == xXrCit_2);
|
|
|
|
// Comparison between reverse_iterator and const_reverse_iterator is okay
|
|
BEAST_EXPECT(rNrNit_0 == rCrCit_0);
|
|
BEAST_EXPECT(rCrCit_1 == rNrNit_1);
|
|
|
|
// 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};
|
|
BEAST_EXPECT(rNrCit_0 == rNrCit_1);
|
|
xXrCit_2 = rNrNit_1;
|
|
BEAST_EXPECT(rNrCit_1 == xXrCit_2);
|
|
|
|
// 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()};
|
|
BEAST_EXPECT(fNrNit_0 == fNrCit_0);
|
|
const_reverse_iterator fCrCit_0{c.cbegin()};
|
|
BEAST_EXPECT(fNrCit_0 == fCrCit_0);
|
|
|
|
// 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
|
|
//
|
|
//------------------------------------------------------------------------------
|
|
|
|
template <class Container, class Values>
|
|
void
|
|
aged_associative_container_test_base::checkInsertCopy(Container& c, Values const& v)
|
|
{
|
|
for (auto const& e : v)
|
|
c.insert(e);
|
|
checkContents(c, v);
|
|
}
|
|
|
|
template <class Container, class Values>
|
|
void
|
|
aged_associative_container_test_base::checkInsertMove(Container& c, Values const& v)
|
|
{
|
|
Values v2(v);
|
|
for (auto& e : v2)
|
|
c.insert(std::move(e));
|
|
checkContents(c, v);
|
|
}
|
|
|
|
template <class Container, class Values>
|
|
void
|
|
aged_associative_container_test_base::checkInsertHintCopy(Container& c, Values const& v)
|
|
{
|
|
for (auto const& e : v)
|
|
c.insert(c.cend(), e);
|
|
checkContents(c, v);
|
|
}
|
|
|
|
template <class Container, class Values>
|
|
void
|
|
aged_associative_container_test_base::checkInsertHintMove(Container& c, Values const& v)
|
|
{
|
|
Values v2(v);
|
|
for (auto& e : v2)
|
|
c.insert(c.cend(), std::move(e));
|
|
checkContents(c, v);
|
|
}
|
|
|
|
template <class Container, class Values>
|
|
void
|
|
aged_associative_container_test_base::checkEmplace(Container& c, Values const& v)
|
|
{
|
|
for (auto const& e : v)
|
|
c.emplace(e);
|
|
checkContents(c, v);
|
|
}
|
|
|
|
template <class Container, class Values>
|
|
void
|
|
aged_associative_container_test_base::checkEmplaceHint(Container& c, Values const& v)
|
|
{
|
|
for (auto const& e : v)
|
|
c.emplace_hint(c.cend(), e);
|
|
checkContents(c, v);
|
|
}
|
|
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
void
|
|
aged_associative_container_test_base::testModifiers()
|
|
{
|
|
using Traits = TestTraits<IsUnordered, IsMulti, IsMap>;
|
|
typename Traits::ManualClock clock;
|
|
auto const v(Traits::values());
|
|
auto const l(make_list(v));
|
|
|
|
// testcase (Traits::name() + " modify");
|
|
testcase("modify");
|
|
|
|
{
|
|
typename Traits::template Cont<> c(clock);
|
|
checkInsertCopy(c, v);
|
|
}
|
|
|
|
{
|
|
typename Traits::template Cont<> c(clock);
|
|
checkInsertCopy(c, l);
|
|
}
|
|
|
|
{
|
|
typename Traits::template Cont<> c(clock);
|
|
checkInsertMove(c, v);
|
|
}
|
|
|
|
{
|
|
typename Traits::template Cont<> c(clock);
|
|
checkInsertMove(c, l);
|
|
}
|
|
|
|
{
|
|
typename Traits::template Cont<> c(clock);
|
|
checkInsertHintCopy(c, v);
|
|
}
|
|
|
|
{
|
|
typename Traits::template Cont<> c(clock);
|
|
checkInsertHintCopy(c, l);
|
|
}
|
|
|
|
{
|
|
typename Traits::template Cont<> c(clock);
|
|
checkInsertHintMove(c, v);
|
|
}
|
|
|
|
{
|
|
typename Traits::template Cont<> c(clock);
|
|
checkInsertHintMove(c, l);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
// Chronological ordering
|
|
//
|
|
//------------------------------------------------------------------------------
|
|
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
void
|
|
aged_associative_container_test_base::testChronological()
|
|
{
|
|
using Traits = TestTraits<IsUnordered, IsMulti, IsMap>;
|
|
typename Traits::ManualClock clock;
|
|
auto const v(Traits::values());
|
|
|
|
// testcase (Traits::name() + " chronological");
|
|
testcase("chronological");
|
|
|
|
typename Traits::template Cont<> c(v.begin(), v.end(), clock);
|
|
|
|
BEAST_EXPECT(
|
|
std::equal(
|
|
c.chronological.cbegin(),
|
|
c.chronological.cend(),
|
|
v.begin(),
|
|
v.end(),
|
|
equal_value<Traits>()));
|
|
|
|
// Test touch() with a non-const iterator.
|
|
for (auto iter(v.crbegin()); iter != v.crend(); ++iter)
|
|
{
|
|
using iterator = typename decltype(c)::iterator;
|
|
iterator found(c.find(Traits::extract(*iter)));
|
|
|
|
BEAST_EXPECT(found != c.cend());
|
|
if (found == c.cend())
|
|
return;
|
|
c.touch(found);
|
|
}
|
|
|
|
BEAST_EXPECT(
|
|
std::equal(
|
|
c.chronological.cbegin(),
|
|
c.chronological.cend(),
|
|
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)));
|
|
|
|
BEAST_EXPECT(found != c.cend());
|
|
if (found == c.cend())
|
|
return;
|
|
c.touch(found);
|
|
}
|
|
|
|
BEAST_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());
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
// Element creation via operator[]
|
|
//
|
|
//------------------------------------------------------------------------------
|
|
|
|
// map, unordered_map
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
typename std::enable_if<IsMap && !IsMulti>::type
|
|
aged_associative_container_test_base::testArrayCreate()
|
|
{
|
|
using Traits = TestTraits<IsUnordered, IsMulti, IsMap>;
|
|
typename Traits::ManualClock clock;
|
|
auto v(Traits::values());
|
|
|
|
// testcase (Traits::name() + " array create");
|
|
testcase("array create");
|
|
|
|
{
|
|
// Copy construct key
|
|
typename Traits::template Cont<> c(clock);
|
|
for (auto e : v)
|
|
c[e.first] = e.second;
|
|
checkContents(c, v);
|
|
}
|
|
|
|
{
|
|
// Move construct key
|
|
typename Traits::template Cont<> c(clock);
|
|
for (auto e : v)
|
|
c[std::move(e.first)] = e.second;
|
|
checkContents(c, v);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
// 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.
|
|
// VFALCO NOTE This is sketchy
|
|
using ManualClock = TestTraitsBase::ManualClock;
|
|
ManualClock& clk(dynamic_cast<ManualClock&>(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()
|
|
{
|
|
using Traits = TestTraits<IsUnordered, IsMulti, IsMap>;
|
|
|
|
// testcase (Traits::name() + " element erase"
|
|
testcase("element erase");
|
|
|
|
// Make and fill the container
|
|
typename Traits::ManualClock clock;
|
|
typename Traits::template Cont<> c{clock};
|
|
reverseFillAgedContainer(c, Traits::values());
|
|
|
|
{
|
|
// Test standard iterators
|
|
auto tempContainer(c);
|
|
if (!doElementErase(tempContainer, tempContainer.cbegin(), tempContainer.cend()))
|
|
return; // Test failed
|
|
|
|
BEAST_EXPECT(tempContainer.empty());
|
|
pass();
|
|
}
|
|
{
|
|
// Test chronological iterators
|
|
auto tempContainer(c);
|
|
auto& chron(tempContainer.chronological);
|
|
if (!doElementErase(tempContainer, chron.begin(), chron.end()))
|
|
return; // Test failed
|
|
|
|
BEAST_EXPECT(tempContainer.empty());
|
|
pass();
|
|
}
|
|
{
|
|
// Test standard iterator partial erase
|
|
auto tempContainer(c);
|
|
BEAST_EXPECT(tempContainer.size() > 2);
|
|
if (!doElementErase(
|
|
tempContainer,
|
|
++tempContainer.begin(),
|
|
nextToEndIter(tempContainer.begin(), tempContainer.end())))
|
|
return; // Test failed
|
|
|
|
BEAST_EXPECT(tempContainer.size() == 2);
|
|
pass();
|
|
}
|
|
{
|
|
// Test chronological iterator partial erase
|
|
auto tempContainer(c);
|
|
BEAST_EXPECT(tempContainer.size() > 2);
|
|
auto& chron(tempContainer.chronological);
|
|
if (!doElementErase(
|
|
tempContainer, ++chron.begin(), nextToEndIter(chron.begin(), chron.end())))
|
|
return; // Test failed
|
|
|
|
BEAST_EXPECT(tempContainer.size() == 2);
|
|
pass();
|
|
}
|
|
{
|
|
auto tempContainer(c);
|
|
BEAST_EXPECT(tempContainer.size() > 4);
|
|
// 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)
|
|
{
|
|
BEAST_EXPECT(c.size() > 2);
|
|
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);
|
|
|
|
BEAST_EXPECT(c.size() == 2);
|
|
BEAST_EXPECT(valueFront == *(beginEndSrc.begin()));
|
|
BEAST_EXPECT(valueBack == *(++beginEndSrc.begin()));
|
|
BEAST_EXPECT(retIter == (++beginEndSrc.begin()));
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
// Erase range of elements
|
|
//
|
|
//------------------------------------------------------------------------------
|
|
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
void
|
|
aged_associative_container_test_base::testRangeErase()
|
|
{
|
|
using Traits = TestTraits<IsUnordered, IsMulti, IsMap>;
|
|
|
|
// testcase (Traits::name() + " element erase"
|
|
testcase("range erase");
|
|
|
|
// Make and fill the container
|
|
typename Traits::ManualClock clock;
|
|
typename Traits::template Cont<> c{clock};
|
|
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
|
|
//
|
|
//------------------------------------------------------------------------------
|
|
|
|
// ordered
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
typename std::enable_if<!IsUnordered>::type
|
|
aged_associative_container_test_base::testCompare()
|
|
{
|
|
using Traits = TestTraits<IsUnordered, IsMulti, IsMap>;
|
|
typename Traits::ManualClock clock;
|
|
auto const v(Traits::values());
|
|
|
|
// testcase (Traits::name() + " array create");
|
|
testcase("array create");
|
|
|
|
typename Traits::template Cont<> c1(v.begin(), v.end(), clock);
|
|
|
|
typename Traits::template Cont<> c2(v.begin(), v.end(), clock);
|
|
c2.erase(c2.cbegin());
|
|
|
|
expect(c1 != c2);
|
|
unexpected(c1 == c2);
|
|
expect(c1 < c2);
|
|
expect(c1 <= c2);
|
|
unexpected(c1 > c2);
|
|
unexpected(c1 >= c2);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
// Observers
|
|
//
|
|
//------------------------------------------------------------------------------
|
|
|
|
// ordered
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
typename std::enable_if<!IsUnordered>::type
|
|
aged_associative_container_test_base::testObservers()
|
|
{
|
|
using Traits = TestTraits<IsUnordered, IsMulti, IsMap>;
|
|
typename Traits::ManualClock clock;
|
|
|
|
// testcase (Traits::name() + " observers");
|
|
testcase("observers");
|
|
|
|
typename Traits::template Cont<> c(clock);
|
|
c.key_comp();
|
|
c.value_comp();
|
|
|
|
pass();
|
|
}
|
|
|
|
// unordered
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
typename std::enable_if<IsUnordered>::type
|
|
aged_associative_container_test_base::testObservers()
|
|
{
|
|
using Traits = TestTraits<IsUnordered, IsMulti, IsMap>;
|
|
typename Traits::ManualClock clock;
|
|
|
|
// testcase (Traits::name() + " observers");
|
|
testcase("observers");
|
|
|
|
typename Traits::template Cont<> c(clock);
|
|
c.hash_function();
|
|
c.key_eq();
|
|
|
|
pass();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
// Matrix
|
|
//
|
|
//------------------------------------------------------------------------------
|
|
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
void
|
|
aged_associative_container_test_base::testMaybeUnorderedMultiMap()
|
|
{
|
|
testConstructEmpty<IsUnordered, IsMulti, IsMap>();
|
|
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>();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
class aged_set_test : public aged_associative_container_test_base
|
|
{
|
|
public:
|
|
// Compile time checks
|
|
|
|
using Key = std::string;
|
|
using T = int;
|
|
|
|
static_assert(
|
|
std::is_same<aged_set<Key>, detail::aged_ordered_container<false, false, Key, void>>::value,
|
|
"bad alias: aged_set");
|
|
|
|
static_assert(
|
|
std::is_same<aged_multiset<Key>, detail::aged_ordered_container<true, false, Key, void>>::
|
|
value,
|
|
"bad alias: aged_multiset");
|
|
|
|
static_assert(
|
|
std::is_same<aged_map<Key, T>, detail::aged_ordered_container<false, true, Key, T>>::value,
|
|
"bad alias: aged_map");
|
|
|
|
static_assert(
|
|
std::is_same<aged_multimap<Key, T>, detail::aged_ordered_container<true, true, Key, T>>::
|
|
value,
|
|
"bad alias: aged_multimap");
|
|
|
|
static_assert(
|
|
std::is_same<
|
|
aged_unordered_set<Key>,
|
|
detail::aged_unordered_container<false, false, Key, void>>::value,
|
|
"bad alias: aged_unordered_set");
|
|
|
|
static_assert(
|
|
std::is_same<
|
|
aged_unordered_multiset<Key>,
|
|
detail::aged_unordered_container<true, false, Key, void>>::value,
|
|
"bad alias: aged_unordered_multiset");
|
|
|
|
static_assert(
|
|
std::is_same<
|
|
aged_unordered_map<Key, T>,
|
|
detail::aged_unordered_container<false, true, Key, T>>::value,
|
|
"bad alias: aged_unordered_map");
|
|
|
|
static_assert(
|
|
std::is_same<
|
|
aged_unordered_multimap<Key, T>,
|
|
detail::aged_unordered_container<true, true, Key, T>>::value,
|
|
"bad alias: aged_unordered_multimap");
|
|
|
|
void
|
|
run() override
|
|
{
|
|
testMaybeUnorderedMultiMap<false, false, false>();
|
|
}
|
|
};
|
|
|
|
class aged_map_test : public aged_associative_container_test_base
|
|
{
|
|
public:
|
|
void
|
|
run() override
|
|
{
|
|
testMaybeUnorderedMultiMap<false, false, true>();
|
|
}
|
|
};
|
|
|
|
class aged_multiset_test : public aged_associative_container_test_base
|
|
{
|
|
public:
|
|
void
|
|
run() override
|
|
{
|
|
testMaybeUnorderedMultiMap<false, true, false>();
|
|
}
|
|
};
|
|
|
|
class aged_multimap_test : public aged_associative_container_test_base
|
|
{
|
|
public:
|
|
void
|
|
run() override
|
|
{
|
|
testMaybeUnorderedMultiMap<false, true, true>();
|
|
}
|
|
};
|
|
|
|
class aged_unordered_set_test : public aged_associative_container_test_base
|
|
{
|
|
public:
|
|
void
|
|
run() override
|
|
{
|
|
testMaybeUnorderedMultiMap<true, false, false>();
|
|
}
|
|
};
|
|
|
|
class aged_unordered_map_test : public aged_associative_container_test_base
|
|
{
|
|
public:
|
|
void
|
|
run() override
|
|
{
|
|
testMaybeUnorderedMultiMap<true, false, true>();
|
|
}
|
|
};
|
|
|
|
class aged_unordered_multiset_test : public aged_associative_container_test_base
|
|
{
|
|
public:
|
|
void
|
|
run() override
|
|
{
|
|
testMaybeUnorderedMultiMap<true, true, false>();
|
|
}
|
|
};
|
|
|
|
class aged_unordered_multimap_test : public aged_associative_container_test_base
|
|
{
|
|
public:
|
|
void
|
|
run() override
|
|
{
|
|
testMaybeUnorderedMultiMap<true, true, true>();
|
|
}
|
|
};
|
|
|
|
BEAST_DEFINE_TESTSUITE(aged_set, beast, beast);
|
|
BEAST_DEFINE_TESTSUITE(aged_map, beast, beast);
|
|
BEAST_DEFINE_TESTSUITE(aged_multiset, beast, beast);
|
|
BEAST_DEFINE_TESTSUITE(aged_multimap, beast, beast);
|
|
BEAST_DEFINE_TESTSUITE(aged_unordered_set, beast, beast);
|
|
BEAST_DEFINE_TESTSUITE(aged_unordered_map, beast, beast);
|
|
BEAST_DEFINE_TESTSUITE(aged_unordered_multiset, beast, beast);
|
|
BEAST_DEFINE_TESTSUITE(aged_unordered_multimap, beast, beast);
|
|
|
|
} // namespace beast
|