mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-20 11:05:54 +00:00
- Added unit tests for element erase - Added unit tests for range erase - Added unit tests for touch - Added unit tests for iterators and reverse_iterators - Un-inlined operator== for unordered containers - Fixed minor problems with ordered_container erase() - Made ordered_container... - erase (reverse_iterator pos) not compile - erase (reverse_iterator first, reverse_iterator last) not compile - touch (reverse iterator pos) not compile - Verified that ordered container... - insert() already rejects reverse_iterator - emplace_hint() already rejects reverse_iterator - Made set/multiset iterators const Regarding the set/multiset iterators, see section 1.5 of http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2913.pdf as pointed out by Vinnie.
2011 lines
56 KiB
C++
2011 lines
56 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 <beast/chrono/manual_clock.h>
|
|
#include <beast/unit_test/suite.h>
|
|
|
|
#include <beast/container/aged_set.h>
|
|
#include <beast/container/aged_map.h>
|
|
#include <beast/container/aged_multiset.h>
|
|
#include <beast/container/aged_multimap.h>
|
|
#include <beast/container/aged_unordered_set.h>
|
|
#include <beast/container/aged_unordered_map.h>
|
|
#include <beast/container/aged_unordered_multiset.h>
|
|
#include <beast/container/aged_unordered_multimap.h>
|
|
|
|
#include <vector>
|
|
#include <list>
|
|
|
|
#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
|
|
{
|
|
typedef T value_type;
|
|
|
|
//typedef propagate_on_container_swap : std::true_type::type;
|
|
|
|
template <class U>
|
|
struct rebind
|
|
{
|
|
typedef AllocT <U> other;
|
|
};
|
|
|
|
explicit AllocT (int)
|
|
{
|
|
}
|
|
|
|
AllocT (AllocT const&)
|
|
{
|
|
}
|
|
|
|
template <class U>
|
|
AllocT (AllocT <U> const&)
|
|
{
|
|
}
|
|
|
|
template <class U>
|
|
bool operator== (AllocT <U> const&) const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
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:
|
|
typedef std::less <typename Base::Key> Comp;
|
|
typedef CompT <typename Base::Key> MyComp;
|
|
|
|
protected:
|
|
static std::string name_ordered_part()
|
|
{
|
|
return "";
|
|
}
|
|
};
|
|
|
|
// unordered
|
|
template <class Base>
|
|
class MaybeUnordered <Base, true> : public Base
|
|
{
|
|
public:
|
|
typedef std::hash <typename Base::Key> Hash;
|
|
typedef std::equal_to <typename Base::Key> Equal;
|
|
typedef HashT <typename Base::Key> MyHash;
|
|
typedef EqualT <typename Base::Key> MyEqual;
|
|
|
|
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:
|
|
typedef void T;
|
|
typedef typename Base::Key Value;
|
|
typedef std::vector <Value> Values;
|
|
|
|
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:
|
|
typedef int T;
|
|
typedef std::pair <typename Base::Key, T> Value;
|
|
typedef std::vector <Value> Values;
|
|
|
|
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::Dur, 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::Dur,
|
|
Hash, KeyEqual, Allocator>;
|
|
};
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
struct TestTraitsBase
|
|
{
|
|
typedef std::string Key;
|
|
typedef std::chrono::seconds Dur;
|
|
typedef manual_clock <Dur> Clock;
|
|
};
|
|
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
struct TestTraitsHelper
|
|
: MaybeUnordered <MaybeMulti <MaybeMap <
|
|
TestTraitsBase, IsMap>, IsMulti>, IsUnordered>
|
|
{
|
|
private:
|
|
typedef MaybeUnordered <MaybeMulti <MaybeMap <
|
|
TestTraitsBase, IsMap>, IsMulti>, IsUnordered> Base;
|
|
|
|
public:
|
|
using typename Base::Key;
|
|
|
|
typedef std::integral_constant <bool, IsUnordered> is_unordered;
|
|
typedef std::integral_constant <bool, IsMulti> is_multi;
|
|
typedef std::integral_constant <bool, IsMap> is_map;
|
|
|
|
typedef std::allocator <typename Base::Value> Alloc;
|
|
typedef AllocT <typename Base::Value> MyAlloc;
|
|
|
|
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::list <typename Cont::value_type>
|
|
make_list (Cont const& c)
|
|
{
|
|
return std::list <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())
|
|
{
|
|
expect (c.empty());
|
|
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)
|
|
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)
|
|
{
|
|
typedef typename std::remove_reference <C>::type Cont;
|
|
typedef TestTraits <
|
|
Cont::is_unordered::value,
|
|
Cont::is_multi::value,
|
|
Cont::is_map::value
|
|
> Traits;
|
|
typedef typename Cont::size_type 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);
|
|
}));
|
|
expect (match != v.end());
|
|
expect (key_eq (Traits::extract (*iter),
|
|
Traits::extract (*match)));
|
|
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)
|
|
{
|
|
typedef typename std::remove_reference <C>::type Cont;
|
|
typedef TestTraits <
|
|
Cont::is_unordered::value,
|
|
Cont::is_multi::value,
|
|
Cont::is_map::value
|
|
> Traits;
|
|
typedef typename Cont::size_type size_type;
|
|
|
|
expect (c.size() == v.size());
|
|
expect (size_type (std::distance (
|
|
c.begin(), c.end())) == v.size());
|
|
expect (size_type (std::distance (
|
|
c.cbegin(), c.cend())) == v.size());
|
|
expect (size_type (std::distance (
|
|
c.chronological.begin(), c.chronological.end())) == v.size());
|
|
expect (size_type (std::distance (
|
|
c.chronological.cbegin(), c.chronological.cend())) == v.size());
|
|
expect (size_type (std::distance (
|
|
c.chronological.rbegin(), c.chronological.rend())) == v.size());
|
|
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)
|
|
{
|
|
typedef TestTraits <
|
|
Cont::is_unordered::value,
|
|
Cont::is_multi::value,
|
|
Cont::is_map::value
|
|
> Traits;
|
|
typedef typename Traits::Values 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 ()
|
|
{
|
|
typedef TestTraits <IsUnordered, IsMulti, IsMap> Traits;
|
|
typedef typename Traits::Value Value;
|
|
typedef typename Traits::Key Key;
|
|
typedef typename Traits::T T;
|
|
typedef typename Traits::Dur Dur;
|
|
typedef typename Traits::Comp Comp;
|
|
typedef typename Traits::Alloc Alloc;
|
|
typedef typename Traits::MyComp MyComp;
|
|
typedef typename Traits::MyAlloc MyAlloc;
|
|
typename Traits::Clock 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 ()
|
|
{
|
|
typedef TestTraits <IsUnordered, IsMulti, IsMap> Traits;
|
|
typedef typename Traits::Value Value;
|
|
typedef typename Traits::Key Key;
|
|
typedef typename Traits::T T;
|
|
typedef typename Traits::Dur Dur;
|
|
typedef typename Traits::Hash Hash;
|
|
typedef typename Traits::Equal Equal;
|
|
typedef typename Traits::Alloc Alloc;
|
|
typedef typename Traits::MyHash MyHash;
|
|
typedef typename Traits::MyEqual MyEqual;
|
|
typedef typename Traits::MyAlloc MyAlloc;
|
|
typename Traits::Clock 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 ()
|
|
{
|
|
typedef TestTraits <IsUnordered, IsMulti, IsMap> Traits;
|
|
typedef typename Traits::Value Value;
|
|
typedef typename Traits::Key Key;
|
|
typedef typename Traits::T T;
|
|
typedef typename Traits::Dur Dur;
|
|
typedef typename Traits::Comp Comp;
|
|
typedef typename Traits::Alloc Alloc;
|
|
typedef typename Traits::MyComp MyComp;
|
|
typedef typename Traits::MyAlloc MyAlloc;
|
|
typename Traits::Clock 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 ()
|
|
{
|
|
typedef TestTraits <IsUnordered, IsMulti, IsMap> Traits;
|
|
typedef typename Traits::Value Value;
|
|
typedef typename Traits::Key Key;
|
|
typedef typename Traits::T T;
|
|
typedef typename Traits::Dur Dur;
|
|
typedef typename Traits::Hash Hash;
|
|
typedef typename Traits::Equal Equal;
|
|
typedef typename Traits::Alloc Alloc;
|
|
typedef typename Traits::MyHash MyHash;
|
|
typedef typename Traits::MyEqual MyEqual;
|
|
typedef typename Traits::MyAlloc MyAlloc;
|
|
typename Traits::Clock 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 ()
|
|
{
|
|
typedef TestTraits <IsUnordered, IsMulti, IsMap> Traits;
|
|
typedef typename Traits::Value Value;
|
|
typedef typename Traits::Key Key;
|
|
typedef typename Traits::T T;
|
|
typedef typename Traits::Dur Dur;
|
|
typedef typename Traits::Comp Comp;
|
|
typedef typename Traits::Alloc Alloc;
|
|
typedef typename Traits::MyComp MyComp;
|
|
typedef typename Traits::MyAlloc MyAlloc;
|
|
typename Traits::Clock 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 ()
|
|
{
|
|
typedef TestTraits <IsUnordered, IsMulti, IsMap> Traits;
|
|
typedef typename Traits::Value Value;
|
|
typedef typename Traits::Key Key;
|
|
typedef typename Traits::T T;
|
|
typedef typename Traits::Dur Dur;
|
|
typedef typename Traits::Hash Hash;
|
|
typedef typename Traits::Equal Equal;
|
|
typedef typename Traits::Alloc Alloc;
|
|
typedef typename Traits::MyHash MyHash;
|
|
typedef typename Traits::MyEqual MyEqual;
|
|
typedef typename Traits::MyAlloc MyAlloc;
|
|
typename Traits::Clock 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 ()
|
|
{
|
|
typedef TestTraits <IsUnordered, IsMulti, IsMap> Traits;
|
|
typedef typename Traits::Value Value;
|
|
typedef typename Traits::Alloc Alloc;
|
|
typename Traits::Clock clock;
|
|
auto const v (Traits::values());
|
|
|
|
//testcase (Traits::name() + " 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);
|
|
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);
|
|
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);
|
|
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()
|
|
{
|
|
typedef TestTraits <IsUnordered, IsMulti, IsMap> Traits;
|
|
typedef typename Traits::Value Value;
|
|
typedef typename Traits::Alloc Alloc;
|
|
typename Traits::Clock clock;
|
|
auto const v (Traits::values());
|
|
|
|
//testcase (Traits::name() + " iterators");
|
|
testcase ("iterator");
|
|
|
|
typename Traits::template Cont <> c {clock};
|
|
|
|
using iterator = decltype (c.begin());
|
|
using const_iterator = decltype (c.cbegin());
|
|
|
|
// Should be able to construct or assign an iterator from an iterator.
|
|
iterator nnIt_0 {c.begin()};
|
|
iterator nnIt_1 {nnIt_0};
|
|
expect (nnIt_0 == nnIt_1, "iterator constructor failed");
|
|
iterator nnIt_2;
|
|
nnIt_2 = nnIt_1;
|
|
expect (nnIt_1 == nnIt_2, "iterator assignment failed");
|
|
|
|
// Should be able to construct or assign a const_iterator from a
|
|
// const_iterator.
|
|
const_iterator ccIt_0 {c.cbegin()};
|
|
const_iterator ccIt_1 {ccIt_0};
|
|
expect (ccIt_0 == ccIt_1, "const_iterator constructor failed");
|
|
const_iterator ccIt_2;
|
|
ccIt_2 = ccIt_1;
|
|
expect (ccIt_1 == ccIt_2, "const_iterator assignment failed");
|
|
|
|
// Comparison between iterator and const_iterator is okay
|
|
expect (nnIt_0 == ccIt_0,
|
|
"Comparing an iterator to a const_iterator failed");
|
|
expect (ccIt_1 == nnIt_1,
|
|
"Comparing a const_iterator to an iterator failed");
|
|
|
|
// Should be able to construct a const_iterator from an iterator.
|
|
const_iterator ncIt_3 {c.begin()};
|
|
const_iterator ncIt_4 {nnIt_0};
|
|
expect (ncIt_3 == ncIt_4,
|
|
"const_iterator construction from iterator failed");
|
|
const_iterator ncIt_5;
|
|
ncIt_5 = nnIt_2;
|
|
expect (ncIt_5 == ncIt_4,
|
|
"const_iterator assignment from iterator failed");
|
|
|
|
// None of these should compile because they construct or assign to a
|
|
// non-const iterator with a const_iterator.
|
|
|
|
// iterator cnIt_0 {c.cbegin()};
|
|
|
|
// iterator cnIt_1 {ccIt_0};
|
|
|
|
// iterator cnIt_2;
|
|
// cnIt_2 = ccIt_2;
|
|
}
|
|
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
typename std::enable_if <! IsUnordered>::type
|
|
aged_associative_container_test_base::
|
|
testReverseIterator()
|
|
{
|
|
typedef TestTraits <IsUnordered, IsMulti, IsMap> Traits;
|
|
typedef typename Traits::Value Value;
|
|
typedef typename Traits::Alloc Alloc;
|
|
typename Traits::Clock clock;
|
|
auto const v (Traits::values());
|
|
|
|
//testcase (Traits::name() + " reverse_iterators");
|
|
testcase ("reverse_iterator");
|
|
|
|
typename Traits::template Cont <> c {clock};
|
|
|
|
using iterator = decltype (c.begin());
|
|
using const_iterator = decltype (c.cbegin());
|
|
using reverse_iterator = decltype (c.rbegin());
|
|
using const_reverse_iterator = decltype (c.crbegin());
|
|
|
|
// Naming decoder ring
|
|
// constructed from ------+ +----- constructed type
|
|
// /\/\ -- character pairs
|
|
// xAyBit
|
|
// r (reverse) or f (forward)--^-^
|
|
// ^-^------ C (const) or N (non-const)
|
|
|
|
// Should be able to construct or assign a reverse_iterator from a
|
|
// reverse_iterator.
|
|
reverse_iterator rNrNit_0 {c.rbegin()};
|
|
reverse_iterator rNrNit_1 {rNrNit_0};
|
|
expect (rNrNit_0 == rNrNit_1, "reverse_iterator constructor failed");
|
|
reverse_iterator xXrNit_2;
|
|
xXrNit_2 = rNrNit_1;
|
|
expect (rNrNit_1 == xXrNit_2, "reverse_iterator assignment failed");
|
|
|
|
// Should be able to construct or assign a const_reverse_iterator from a
|
|
// const_reverse_iterator
|
|
const_reverse_iterator rCrCit_0 {c.crbegin()};
|
|
const_reverse_iterator rCrCit_1 {rCrCit_0};
|
|
expect (rCrCit_0 == rCrCit_1, "reverse_iterator constructor failed");
|
|
const_reverse_iterator xXrCit_2;
|
|
xXrCit_2 = rCrCit_1;
|
|
expect (rCrCit_1 == xXrCit_2, "reverse_iterator assignment failed");
|
|
|
|
// Comparison between reverse_iterator and const_reverse_iterator is okay
|
|
expect (rNrNit_0 == rCrCit_0,
|
|
"Comparing an iterator to a const_iterator failed");
|
|
expect (rCrCit_1 == rNrNit_1,
|
|
"Comparing a const_iterator to an iterator failed");
|
|
|
|
// Should be able to construct or assign a const_reverse_iterator from a
|
|
// reverse_iterator
|
|
const_reverse_iterator rNrCit_0 {c.rbegin()};
|
|
const_reverse_iterator rNrCit_1 {rNrNit_0};
|
|
expect (rNrCit_0 == rNrCit_1,
|
|
"const_reverse_iterator construction from reverse_iterator failed");
|
|
xXrCit_2 = rNrNit_1;
|
|
expect (rNrCit_1 == xXrCit_2,
|
|
"const_reverse_iterator assignment from reverse_iterator failed");
|
|
|
|
// The standard allows these conversions:
|
|
// o reverse_iterator is explicitly constructible from iterator.
|
|
// o const_reverse_iterator is explicitly constructible from const_iterator.
|
|
// Should be able to construct or assign reverse_iterators from
|
|
// non-reverse iterators.
|
|
reverse_iterator fNrNit_0 {c.begin()};
|
|
const_reverse_iterator fNrCit_0 {c.begin()};
|
|
expect (fNrNit_0 == fNrCit_0,
|
|
"reverse_iterator construction from iterator failed");
|
|
const_reverse_iterator fCrCit_0 {c.cbegin()};
|
|
expect (fNrCit_0 == fCrCit_0,
|
|
"const_reverse_iterator construction from const_iterator failed");
|
|
|
|
// None of these should compile because they construct a non-reverse
|
|
// iterator from a reverse_iterator.
|
|
// iterator rNfNit_0 {c.rbegin()};
|
|
// const_iterator rNfCit_0 {c.rbegin()};
|
|
// const_iterator rCfCit_0 {c.crbegin()};
|
|
|
|
// You should not be able to assign an iterator to a reverse_iterator or
|
|
// vise-versa. So the following lines should not compile.
|
|
iterator xXfNit_0;
|
|
// xXfNit_0 = xXrNit_2;
|
|
// xXrNit_2 = xXfNit_0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
// Modifiers
|
|
//
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
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()
|
|
{
|
|
typedef TestTraits <IsUnordered, IsMulti, IsMap> Traits;
|
|
typename Traits::Clock 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 ()
|
|
{
|
|
typedef TestTraits <IsUnordered, IsMulti, IsMap> Traits;
|
|
typedef typename Traits::Value Value;
|
|
typename Traits::Clock clock;
|
|
auto const v (Traits::values());
|
|
|
|
//testcase (Traits::name() + " chronological");
|
|
testcase ("chronological");
|
|
|
|
typename Traits::template Cont <> c (
|
|
v.begin(), v.end(), clock);
|
|
|
|
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)));
|
|
|
|
expect (found != c.cend());
|
|
if (found == c.cend())
|
|
return;
|
|
c.touch (found);
|
|
}
|
|
|
|
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)));
|
|
|
|
expect (found != c.cend());
|
|
if (found == c.cend())
|
|
return;
|
|
c.touch (found);
|
|
}
|
|
|
|
expect (std::equal (
|
|
c.chronological.cbegin(), c.chronological.cend(),
|
|
v.cbegin(), v.cend(), equal_value <Traits> ()));
|
|
|
|
{
|
|
// Because touch (reverse_iterator pos) is not allowed, the following
|
|
// lines should not compile for any aged_container type.
|
|
// c.touch (c.rbegin());
|
|
// c.touch (c.crbegin());
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
// 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()
|
|
{
|
|
typedef TestTraits <IsUnordered, IsMulti, IsMap> Traits;
|
|
typename Traits::Clock 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.
|
|
typedef TestTraitsBase::Clock Clock;
|
|
Clock& clk (dynamic_cast <Clock&> (c.clock ()));
|
|
clk.set (0);
|
|
|
|
Values rev (values);
|
|
std::sort (rev.begin (), rev.end ());
|
|
std::reverse (rev.begin (), rev.end ());
|
|
for (auto& v : rev)
|
|
{
|
|
// Add values in reverse order so they are reversed chronologically.
|
|
++clk;
|
|
c.insert (v);
|
|
}
|
|
}
|
|
|
|
// Get one iterator before endIter. We have to use operator++ because you
|
|
// cannot use operator-- with unordered container iterators.
|
|
template <class Iter>
|
|
Iter
|
|
aged_associative_container_test_base::
|
|
nextToEndIter (Iter beginIter, Iter const endIter)
|
|
{
|
|
if (beginIter == endIter)
|
|
{
|
|
fail ("Internal test failure. Cannot advance beginIter");
|
|
return beginIter;
|
|
}
|
|
|
|
//
|
|
Iter nextToEnd = beginIter;
|
|
do
|
|
{
|
|
nextToEnd = beginIter++;
|
|
} while (beginIter != endIter);
|
|
return nextToEnd;
|
|
}
|
|
|
|
// Implementation for the element erase tests
|
|
//
|
|
// This test accepts:
|
|
// o the container from which we will erase elements
|
|
// o iterators into that container defining the range of the erase
|
|
//
|
|
// This implementation does not declare a pass, since it wants to allow
|
|
// the caller to examine the size of the container and the returned iterator
|
|
//
|
|
// Note that this test works on the aged_associative containers because an
|
|
// erase only invalidates references and iterators to the erased element
|
|
// (see 23.2.4/13). Therefore the passed-in end iterator stays valid through
|
|
// the whole test.
|
|
template <class Container, class Iter>
|
|
bool aged_associative_container_test_base::
|
|
doElementErase (Container& c, Iter const beginItr, Iter const endItr)
|
|
{
|
|
auto it (beginItr);
|
|
size_t count = c.size();
|
|
while (it != endItr)
|
|
{
|
|
auto expectIt = it;
|
|
++expectIt;
|
|
it = c.erase (it);
|
|
|
|
if (it != expectIt)
|
|
{
|
|
fail ("Unexpected returned iterator from element erase");
|
|
return false;
|
|
}
|
|
|
|
--count;
|
|
if (count != c.size())
|
|
{
|
|
fail ("Failed to erase element");
|
|
return false;
|
|
}
|
|
|
|
if (c.empty ())
|
|
{
|
|
if (it != endItr)
|
|
{
|
|
fail ("Erase of last element didn't produce end");
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
// Erase of individual elements
|
|
//
|
|
//------------------------------------------------------------------------------
|
|
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
void
|
|
aged_associative_container_test_base::
|
|
testElementErase ()
|
|
{
|
|
typedef TestTraits <IsUnordered, IsMulti, IsMap> Traits;
|
|
|
|
//testcase (Traits::name() + " element erase"
|
|
testcase ("element erase");
|
|
|
|
// Make and fill the container
|
|
typename Traits::Clock ck;
|
|
typename Traits::template Cont <> c {ck};
|
|
reverseFillAgedContainer (c, Traits::values());
|
|
|
|
{
|
|
// Test standard iterators
|
|
auto tempContainer (c);
|
|
if (! doElementErase (tempContainer,
|
|
tempContainer.cbegin(), tempContainer.cend()))
|
|
return; // Test failed
|
|
|
|
expect (tempContainer.empty(), "Failed to erase all elements");
|
|
pass();
|
|
}
|
|
{
|
|
// Test chronological iterators
|
|
auto tempContainer (c);
|
|
auto& chron (tempContainer.chronological);
|
|
if (! doElementErase (tempContainer, chron.begin(), chron.end()))
|
|
return; // Test failed
|
|
|
|
expect (tempContainer.empty(),
|
|
"Failed to chronologically erase all elements");
|
|
pass();
|
|
}
|
|
{
|
|
// Test standard iterator partial erase
|
|
auto tempContainer (c);
|
|
expect (tempContainer.size() > 2,
|
|
"Internal failure. Container too small.");
|
|
if (! doElementErase (tempContainer, ++tempContainer.begin(),
|
|
nextToEndIter (tempContainer.begin(), tempContainer.end())))
|
|
return; // Test failed
|
|
|
|
expect (tempContainer.size() == 2,
|
|
"Failed to erase expected number of elements");
|
|
pass();
|
|
}
|
|
{
|
|
// Test chronological iterator partial erase
|
|
auto tempContainer (c);
|
|
expect (tempContainer.size() > 2,
|
|
"Internal failure. Container too small.");
|
|
auto& chron (tempContainer.chronological);
|
|
if (! doElementErase (tempContainer, ++chron.begin(),
|
|
nextToEndIter (chron.begin(), chron.end())))
|
|
return; // Test failed
|
|
|
|
expect (tempContainer.size() == 2,
|
|
"Failed to chronologically erase expected number of elements");
|
|
pass();
|
|
}
|
|
{
|
|
auto tempContainer (c);
|
|
expect (tempContainer.size() > 4,
|
|
"Internal failure. Container too small.");
|
|
// erase(reverse_iterator) is not allowed. None of the following
|
|
// should compile for any aged_container type.
|
|
// c.erase (c.rbegin());
|
|
// c.erase (c.crbegin());
|
|
// c.erase(c.rbegin(), ++c.rbegin());
|
|
// c.erase(c.crbegin(), ++c.crbegin());
|
|
}
|
|
}
|
|
|
|
// Implementation for the range erase tests
|
|
//
|
|
// This test accepts:
|
|
//
|
|
// o A container with more than 2 elements and
|
|
// o An object to ask for begin() and end() iterators in the passed container
|
|
//
|
|
// This peculiar interface allows either the container itself to be passed as
|
|
// the second argument or the container's "chronological" element. Both
|
|
// sources of iterators need to be tested on the container.
|
|
//
|
|
// The test locates iterators such that a range-based delete leaves the first
|
|
// and last elements in the container. It then validates that the container
|
|
// ended up with the expected contents.
|
|
//
|
|
template <class Container, class BeginEndSrc>
|
|
void
|
|
aged_associative_container_test_base::
|
|
doRangeErase (Container& c, BeginEndSrc const& beginEndSrc)
|
|
{
|
|
expect (c.size () > 2,
|
|
"Internal test failure. Container must have more than 2 elements");
|
|
auto itBeginPlusOne (beginEndSrc.begin ());
|
|
auto const valueFront = *itBeginPlusOne;
|
|
++itBeginPlusOne;
|
|
|
|
// Get one iterator before end()
|
|
auto itBack (nextToEndIter (itBeginPlusOne, beginEndSrc.end ()));
|
|
auto const valueBack = *itBack;
|
|
|
|
// Erase all elements but first and last
|
|
auto const retIter = c.erase (itBeginPlusOne, itBack);
|
|
|
|
expect (c.size() == 2,
|
|
"Unexpected size for range-erased container");
|
|
|
|
expect (valueFront == *(beginEndSrc.begin()),
|
|
"Unexpected first element in range-erased container");
|
|
|
|
expect (valueBack == *(++beginEndSrc.begin()),
|
|
"Unexpected last element in range-erased container");
|
|
|
|
expect (retIter == (++beginEndSrc.begin()),
|
|
"Unexpected return iterator from erase");
|
|
|
|
pass ();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
// Erase range of elements
|
|
//
|
|
//------------------------------------------------------------------------------
|
|
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
void
|
|
aged_associative_container_test_base::
|
|
testRangeErase ()
|
|
{
|
|
typedef TestTraits <IsUnordered, IsMulti, IsMap> Traits;
|
|
|
|
//testcase (Traits::name() + " element erase"
|
|
testcase ("range erase");
|
|
|
|
// Make and fill the container
|
|
typename Traits::Clock ck;
|
|
typename Traits::template Cont <> c {ck};
|
|
reverseFillAgedContainer (c, Traits::values());
|
|
|
|
// Not bothering to test range erase with reverse iterators.
|
|
{
|
|
auto tempContainer (c);
|
|
doRangeErase (tempContainer, tempContainer);
|
|
}
|
|
{
|
|
auto tempContainer (c);
|
|
doRangeErase (tempContainer, tempContainer.chronological);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
// Container-wide comparison
|
|
//
|
|
//------------------------------------------------------------------------------
|
|
|
|
// ordered
|
|
template <bool IsUnordered, bool IsMulti, bool IsMap>
|
|
typename std::enable_if <! IsUnordered>::type
|
|
aged_associative_container_test_base::
|
|
testCompare ()
|
|
{
|
|
typedef TestTraits <IsUnordered, IsMulti, IsMap> Traits;
|
|
typedef typename Traits::Value Value;
|
|
typename Traits::Clock 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()
|
|
{
|
|
typedef TestTraits <IsUnordered, IsMulti, IsMap> Traits;
|
|
typename Traits::Clock 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()
|
|
{
|
|
typedef TestTraits <IsUnordered, IsMulti, IsMap> Traits;
|
|
typename Traits::Clock 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 ()
|
|
{
|
|
typedef TestTraits <IsUnordered, IsMulti, IsMap> Traits;
|
|
|
|
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
|
|
|
|
typedef std::string Key;
|
|
typedef int T;
|
|
|
|
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 ()
|
|
{
|
|
testMaybeUnorderedMultiMap <false, false, false>();
|
|
}
|
|
};
|
|
|
|
class aged_map_test : public aged_associative_container_test_base
|
|
{
|
|
public:
|
|
void run ()
|
|
{
|
|
testMaybeUnorderedMultiMap <false, false, true>();
|
|
}
|
|
};
|
|
|
|
class aged_multiset_test : public aged_associative_container_test_base
|
|
{
|
|
public:
|
|
void run ()
|
|
{
|
|
testMaybeUnorderedMultiMap <false, true, false>();
|
|
}
|
|
};
|
|
|
|
class aged_multimap_test : public aged_associative_container_test_base
|
|
{
|
|
public:
|
|
void run ()
|
|
{
|
|
testMaybeUnorderedMultiMap <false, true, true>();
|
|
}
|
|
};
|
|
|
|
|
|
class aged_unordered_set_test : public aged_associative_container_test_base
|
|
{
|
|
public:
|
|
void run ()
|
|
{
|
|
testMaybeUnorderedMultiMap <true, false, false>();
|
|
}
|
|
};
|
|
|
|
class aged_unordered_map_test : public aged_associative_container_test_base
|
|
{
|
|
public:
|
|
void run ()
|
|
{
|
|
testMaybeUnorderedMultiMap <true, false, true>();
|
|
}
|
|
};
|
|
|
|
class aged_unordered_multiset_test : public aged_associative_container_test_base
|
|
{
|
|
public:
|
|
void run ()
|
|
{
|
|
testMaybeUnorderedMultiMap <true, true, false>();
|
|
}
|
|
};
|
|
|
|
class aged_unordered_multimap_test : public aged_associative_container_test_base
|
|
{
|
|
public:
|
|
void run ()
|
|
{
|
|
testMaybeUnorderedMultiMap <true, true, true>();
|
|
}
|
|
};
|
|
|
|
BEAST_DEFINE_TESTSUITE(aged_set,container,beast);
|
|
BEAST_DEFINE_TESTSUITE(aged_map,container,beast);
|
|
BEAST_DEFINE_TESTSUITE(aged_multiset,container,beast);
|
|
BEAST_DEFINE_TESTSUITE(aged_multimap,container,beast);
|
|
BEAST_DEFINE_TESTSUITE(aged_unordered_set,container,beast);
|
|
BEAST_DEFINE_TESTSUITE(aged_unordered_map,container,beast);
|
|
BEAST_DEFINE_TESTSUITE(aged_unordered_multiset,container,beast);
|
|
BEAST_DEFINE_TESTSUITE(aged_unordered_multimap,container,beast);
|
|
|
|
} // namespace beast
|