mirror of
https://github.com/XRPLF/rippled.git
synced 2026-04-29 15:37:57 +00:00
This change fixes the suite names all around the test files, to make them match to the folder name in which this test files are located. Also, the RCL test files are relocated to the consensus folder, because they are testing consensus functionality.
1949 lines
52 KiB
C++
1949 lines
52 KiB
C++
//------------------------------------------------------------------------------
|
|
/*
|
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
|
|
|
Permission to use, copy, modify, and/or distribute this software for any
|
|
purpose with or without fee is hereby granted, provided that the above
|
|
copyright notice and this permission notice appear in all copies.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
//==============================================================================
|
|
|
|
#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;
|
|
}
|
|
|
|
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
|