AnimTestbed/3rdparty/ozz-animation/test/base/containers/intrusive_list_tests.cc

1652 lines
46 KiB
C++

//----------------------------------------------------------------------------//
// //
// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
// and distributed under the MIT License (MIT). //
// //
// Copyright (c) Guillaume Blanc //
// //
// Permission is hereby granted, free of charge, to any person obtaining a //
// copy of this software and associated documentation files (the "Software"), //
// to deal in the Software without restriction, including without limitation //
// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
// and/or sell copies of the Software, and to permit persons to whom the //
// Software is furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in //
// all copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
// DEALINGS IN THE SOFTWARE. //
// //
//----------------------------------------------------------------------------//
#include "ozz/base/containers/intrusive_list.h"
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4127) // constant conditional expression
#endif // _MSC_VER
#include <list>
#ifdef _MSC_VER
#pragma warning(pop)
#endif // _MSC_VER
#include <algorithm>
#include <functional>
#include "gtest/gtest.h"
#include "ozz/base/gtest_helper.h"
// using-declaration of IntrusiveList type and its options
using ozz::containers::IntrusiveList;
using ozz::containers::Option;
// Test whether assertion compliance tests can be ran on the container specified
// as template argument.
// The default implementation allows to run all tests.
template <typename _Ty>
struct TestAssertCompliance {
enum { kValue = 1 };
};
// Check compiler settings for std/crt debug level availability.
#if defined(_MSC_VER)
#define HAS_STD_ASSERTION 1 // Win32 std lib has debug option.
#elif defined(__GNUC__) && defined(_GLIBCXX_DEBUG)
#define HAS_STD_ASSERTION 1 // _GLIBCXX_DEBUG enables GCC Libc debug option.
#else
#define HAS_STD_ASSERTION 0 // Disabled by default.
#endif
// Specializes for std::list, according to compilation settings.
template <typename _Ty>
struct TestAssertCompliance<std::list<_Ty>> {
enum { kValue = HAS_STD_ASSERTION };
};
// Defines a test object that inherits from IntrusiveList::Hook in order to be
// listed by an IntrusiveList.
// Every instance is assigned a value (obtained for a global instance counter)
// used for instance sorting and comparison.
template <typename _Options0 = Option<>>
class TestObj1 : public IntrusiveList<TestObj1<_Options0>, _Options0>::Hook {
public:
// Constructs a TestObj1 and increments global TestObj1 counter.
TestObj1() : instance_(s_instance_counter_++) {}
// Does not copy the Node itself, just maintains the assigned instance number.
TestObj1(
TestObj1 const& _r) // NOLINT cannot be explicit as used by std::list
: IntrusiveList<TestObj1<_Options0>, _Options0>::Hook(),
instance_(_r.instance_) {}
// Implements comparison operators.
bool operator==(TestObj1 const& _r) const {
return instance_ == _r.instance_;
}
bool operator<(TestObj1 const& _r) const { return instance_ < _r.instance_; }
bool operator>(TestObj1 const& _r) const { return instance_ > _r.instance_; }
private:
// Disallows assignment operator.
void operator=(TestObj1 const& _r);
// Assigned instance value.
const int instance_;
// TestObj1 instance counter.
static int s_instance_counter_;
};
template <typename _Options0>
int TestObj1<_Options0>::s_instance_counter_ = 0;
// Defines a test object that inherits from TestObj1 in order to be listed by
// two IntrusiveList at a time.
template <typename _Options1, typename _Options2>
class TestObj2
: public TestObj1<_Options1>,
public IntrusiveList<TestObj2<_Options1, _Options2>, _Options2>::Hook {
public:
// Constructs a default TestObj2.
TestObj2() {}
// Does not copy the Node itself, just maintains the assigned instance number.
explicit TestObj2(TestObj2 const& _r)
: TestObj1<_Options1>(_r),
IntrusiveList<TestObj2<_Options1, _Options2>, _Options2>::Hook() {}
};
// Applies the _Test function to some std::list<> and Intrusive<> types.
template <template <typename> class _Test>
void BindTypes() {
// std::list
_Test<std::list<TestObj1<>>>()();
// kAuto link mode
typedef Option<ozz::containers::LinkMode::kAuto, 0> _OptionsAuto0;
typedef TestObj1<_OptionsAuto0> AutoTestObj0;
_Test<IntrusiveList<AutoTestObj0, _OptionsAuto0>>()();
// kSafe link mode
typedef Option<ozz::containers::LinkMode::kSafe, 0> _OptionsSafe0;
typedef TestObj1<_OptionsSafe0> SafeTestObj0;
_Test<IntrusiveList<SafeTestObj0, _OptionsSafe0>>()();
// kUnsafe link mode
typedef Option<ozz::containers::LinkMode::kUnsafe, 0> _OptionsUnsafe0;
typedef TestObj1<_OptionsUnsafe0> UnsafeTestObj0;
_Test<IntrusiveList<UnsafeTestObj0, _OptionsUnsafe0>>()();
// Auto link mode and safe link mode of a single object in two different
// lists.
typedef Option<ozz::containers::LinkMode::kSafe, 1> _OptionsSafe1;
typedef TestObj2<_OptionsAuto0, _OptionsSafe1> LocalTestObj01;
_Test<IntrusiveList<LocalTestObj01, _OptionsSafe1>>()();
}
// Tests compliance with "front" push/pop function specifications.
template <typename _List>
struct CompliancePushPopFront {
void operator()() {
typename _List::value_type first;
typename _List::value_type second;
_List l;
const _List& r_const_l = l;
if (void(0), TestAssertCompliance<_List>::kValue) {
EXPECT_ASSERTION(l.front(), "");
EXPECT_ASSERTION(r_const_l.front(), "");
EXPECT_ASSERTION(l.back(), "");
EXPECT_ASSERTION(r_const_l.back(), "");
}
l.push_front(first);
EXPECT_TRUE(l.size() == 1 && l.front() == first && l.back() == first);
EXPECT_TRUE(r_const_l.size() == 1 && r_const_l.front() == first &&
r_const_l.back() == first);
l.push_front(second);
EXPECT_TRUE(l.size() == 2 && l.front() == second && l.back() == first);
l.pop_front();
EXPECT_TRUE(l.size() == 1 && l.front() == first && l.back() == first);
l.clear();
}
};
TEST(CompliancePushPopFront, IntrusiveList) {
BindTypes<CompliancePushPopFront>();
}
// Tests compliance with "back" push/pop function specifications.
template <typename _List>
struct CompliancePushPopBack {
void operator()() {
typename _List::value_type first;
typename _List::value_type second;
_List l;
const _List& r_const_l = l;
l.push_back(first);
EXPECT_TRUE(l.size() == 1 && l.front() == first && l.back() == first);
EXPECT_TRUE(r_const_l.size() == 1 && r_const_l.front() == first &&
r_const_l.back() == first);
l.push_back(second);
EXPECT_TRUE(l.size() == 2 && l.front() == first && l.back() == second);
l.pop_back();
EXPECT_TRUE(l.size() == 1 && l.front() == first && l.back() == first);
l.clear();
}
};
TEST(CompliancePushPopBack, IntrusiveList) {
BindTypes<CompliancePushPopBack>();
}
// Tests compliance of mixed "front" and "back" push/pop.
template <typename _List>
struct CompliancePushPopMixed {
void operator()() {
typename _List::value_type first;
typename _List::value_type second;
typename _List::value_type third;
_List l;
l.push_back(first);
EXPECT_TRUE(l.size() == 1 && l.front() == first && l.back() == first);
l.push_front(second);
EXPECT_TRUE(l.size() == 2 && l.front() == second && l.back() == first);
l.push_front(third);
EXPECT_TRUE(l.size() == 3 && l.front() == third && l.back() == first);
l.pop_back();
EXPECT_TRUE(l.size() == 2 && l.front() == third && l.back() == second);
l.pop_front();
EXPECT_TRUE(l.size() == 1 && l.front() == second && l.back() == second);
l.clear();
}
};
TEST(CompliancePushPopMixed, IntrusiveList) {
BindTypes<CompliancePushPopMixed>();
}
// Tests compliance with std::list begin iterator specifications.
template <typename _List>
struct ComplianceBegin {
void operator()() {
typename _List::value_type first;
typename _List::value_type second;
typename _List::value_type third;
_List l;
const _List& r_const_l = l;
EXPECT_TRUE(l.begin() == l.end());
l.push_back(first);
l.push_back(second);
l.push_back(third);
{
typename _List::iterator it = l.begin();
EXPECT_TRUE(*it == first);
}
{
typename _List::const_iterator const_iter = r_const_l.begin();
EXPECT_TRUE(*const_iter == first);
}
{
typename _List::const_iterator const_iter(l.begin());
EXPECT_TRUE(*const_iter == first);
}
{
typename _List::iterator it = l.begin();
EXPECT_TRUE(*it == first);
++it;
EXPECT_TRUE(*it == second);
++it;
EXPECT_TRUE(*it == third);
++it;
EXPECT_TRUE(it == l.end());
}
{
typename _List::const_iterator it = r_const_l.begin();
EXPECT_TRUE(*it == first);
++it;
EXPECT_TRUE(*it == second);
++it;
EXPECT_TRUE(*it == third);
++it;
EXPECT_TRUE(it == r_const_l.end());
}
l.clear();
}
};
TEST(ComplianceBegin, IntrusiveList) { BindTypes<ComplianceBegin>(); }
// Tests compliance of std::list end iterator specifications.
template <typename _List>
struct ComplianceEnd {
void operator()() {
typename _List::value_type first;
typename _List::value_type second;
typename _List::value_type third;
_List l;
const _List& r_const_l = l;
EXPECT_TRUE(l.begin() == l.end());
EXPECT_TRUE(r_const_l.begin() == r_const_l.end());
l.push_back(first);
l.push_back(second);
l.push_back(third);
EXPECT_TRUE(l.begin() != l.end());
EXPECT_TRUE(r_const_l.begin() != r_const_l.end());
{
typename _List::iterator it = l.end();
EXPECT_TRUE(*--it == third);
}
{
typename _List::const_iterator const_iter = r_const_l.end();
EXPECT_TRUE(*--const_iter == third);
}
{
typename _List::const_iterator const_iter = l.end();
EXPECT_TRUE(*--const_iter == third);
}
{
typename _List::iterator it = l.end();
it--;
EXPECT_TRUE(*it == third);
it--;
EXPECT_TRUE(*it == second);
it--;
EXPECT_TRUE(*it == first && it == l.begin());
}
{
typename _List::const_iterator it = r_const_l.end();
it--;
EXPECT_TRUE(*it == third);
it--;
EXPECT_TRUE(*it == second);
it--;
EXPECT_TRUE(*it == first && it == r_const_l.begin());
}
l.clear();
}
};
TEST(ComplianceEnd, IntrusiveList) { BindTypes<ComplianceEnd>(); }
// Tests compliance with std::list typedefs.
template <typename _List>
struct ComplianceTypedef {
void operator()() {
typename _List::value_type first;
typename _List::value_type second;
_List l;
const _List& r_const_l = l;
l.push_front(first);
l.push_back(second);
typename _List::const_iterator const_iter = r_const_l.begin();
EXPECT_TRUE(*const_iter == first);
typename _List::iterator it = l.begin();
EXPECT_TRUE(*it == first);
typename _List::const_reverse_iterator const_rev_iter = r_const_l.rbegin();
EXPECT_TRUE(*const_rev_iter == second);
typename _List::reverse_iterator rev_iter = l.rbegin();
EXPECT_TRUE(*rev_iter == second);
typename _List::const_pointer const_p = &r_const_l.front();
EXPECT_TRUE(*const_p == first);
typename _List::pointer p = &l.front();
EXPECT_TRUE(*p == first);
typename _List::const_reference const_r = r_const_l.front();
EXPECT_TRUE(const_r == first);
typename _List::reference r = l.front();
EXPECT_TRUE(r == first);
typename _List::difference_type diff =
std::count(l.begin(), l.end(), first);
EXPECT_EQ(diff, 1);
typename _List::size_type size = l.size();
EXPECT_EQ(size, 2u);
l.clear();
}
};
TEST(ComplianceTypedef, IntrusiveList) { BindTypes<ComplianceTypedef>(); }
// Tests compliance of std::list iterator specifications.
template <typename _List>
struct ComplianceIterator {
void operator()() {
typename _List::value_type first;
_List l1, l2;
l1.push_front(first);
const _List& rcosnt_l1 = l1;
// Test operators
EXPECT_TRUE(l1.begin() != l1.end());
EXPECT_TRUE(l1.begin()++ == l1.begin());
EXPECT_TRUE(++l1.begin() == l1.end());
EXPECT_TRUE(rcosnt_l1.begin() != rcosnt_l1.end());
EXPECT_TRUE(rcosnt_l1.begin()++ == rcosnt_l1.begin());
EXPECT_TRUE(++rcosnt_l1.begin() == rcosnt_l1.end());
EXPECT_TRUE(l1.begin() != rcosnt_l1.end());
EXPECT_TRUE(++l1.begin() == l1.end());
EXPECT_TRUE(l1.begin() != l1.end());
EXPECT_TRUE(++l1.begin() == l1.end());
// Dereference iterator
{
typename _List::reference r11 = *l1.begin();
EXPECT_TRUE(r11 == first);
typename _List::const_reference r12 = *rcosnt_l1.begin();
EXPECT_TRUE(r12 == first);
}
// Test copy
{
typename _List::iterator it = l1.begin();
typename _List::iterator assign_it = it;
EXPECT_TRUE(assign_it == it);
typename _List::iterator copy_it = it;
EXPECT_TRUE(copy_it == it);
}
if (void(0), TestAssertCompliance<_List>::kValue) {
// Test comparing iterators of different lists
EXPECT_ASSERTION(void(typename _List::iterator() == l1.begin()), "");
EXPECT_ASSERTION(void(typename _List::const_iterator() == l1.begin()),
"");
EXPECT_ASSERTION(
void(l1.begin() != static_cast<const _List&>(l2).begin()), "");
EXPECT_ASSERTION(void(l1.end() != static_cast<const _List&>(l2).end()),
"");
EXPECT_ASSERTION(void(rcosnt_l1.begin() != l2.begin()), "");
EXPECT_ASSERTION(void(rcosnt_l1.end() != l2.end()), "");
// Test iterators bound cases
EXPECT_ASSERTION(--l1.begin(), "");
EXPECT_ASSERTION(l1.begin()--, "");
EXPECT_ASSERTION(--rcosnt_l1.begin(), "");
EXPECT_ASSERTION(rcosnt_l1.begin()--, "");
EXPECT_ASSERTION(++rcosnt_l1.end(), "");
EXPECT_ASSERTION(rcosnt_l1.end()++, "");
EXPECT_ASSERTION(++rcosnt_l1.end(), "");
EXPECT_ASSERTION(rcosnt_l1.end()++, "");
// Dereferencing an invalid iterator
EXPECT_ASSERTION(*typename _List::iterator(), "");
EXPECT_ASSERTION(*typename _List::const_iterator(), "");
EXPECT_ASSERTION(*typename _List::reverse_iterator(), "");
EXPECT_ASSERTION(*typename _List::const_reverse_iterator(), "");
EXPECT_ASSERTION(*l1.end(), "");
EXPECT_ASSERTION(*rcosnt_l1.end(), "");
EXPECT_ASSERTION(*l1.rend(), "");
EXPECT_ASSERTION(*rcosnt_l1.rend(), "");
}
// Test iterator std functions
{
typename _List::iterator it = l1.begin();
std::advance(it, 1);
EXPECT_TRUE(it == l1.end());
std::advance(it, -1);
EXPECT_TRUE(it == l1.begin());
if (void(0), TestAssertCompliance<_List>::kValue) {
EXPECT_ASSERTION(std::advance(it, 2), "");
}
}
{ EXPECT_EQ(std::distance(l1.begin(), l1.end()), 1); }
l1.clear();
l2.clear();
}
};
TEST(ComplianceIterator, IntrusiveList) { BindTypes<ComplianceIterator>(); }
// Tests compliance with "rbegin" function specifications.
template <typename _List>
struct ComplianceRBegin {
void operator()() {
typename _List::value_type first;
typename _List::value_type second;
typename _List::value_type third;
_List l;
const _List& rcosnt_l = l;
EXPECT_TRUE(l.rbegin() == l.rend());
l.push_back(first);
l.push_back(second);
l.push_back(third);
EXPECT_TRUE(l.rbegin() != l.rend());
// rbegin should be at the back of the list
{
typename _List::reverse_iterator rev_iter = l.rbegin();
EXPECT_TRUE(*rev_iter == third);
}
// Iterate in reverse order
{
typename _List::const_reverse_iterator const_rev_iter = l.rbegin();
EXPECT_TRUE(*const_rev_iter == third);
++const_rev_iter;
EXPECT_TRUE(*const_rev_iter == second);
++const_rev_iter;
EXPECT_TRUE(*const_rev_iter == first);
++const_rev_iter;
EXPECT_TRUE(const_rev_iter == rcosnt_l.rend());
if (void(0), TestAssertCompliance<_List>::kValue) {
EXPECT_ASSERTION(++const_rev_iter, ""); // Cannot increment beyond rend
}
}
l.clear();
}
};
TEST(ComplianceRBegin, IntrusiveList) { BindTypes<ComplianceRBegin>(); }
// Tests compliance with "rend" function specifications.
template <typename _List>
struct ComplianceREnd {
void operator()() {
typename _List::value_type first;
typename _List::value_type second;
typename _List::value_type third;
_List l;
const _List& rcosnt_l = l;
EXPECT_TRUE(l.rbegin() == l.rend());
l.push_back(first);
l.push_back(second);
l.push_back(third);
EXPECT_TRUE(l.rbegin() != l.rend());
// rend should be at the front of the list
{
typename _List::reverse_iterator rev_iter = l.rend();
if (void(0), TestAssertCompliance<_List>::kValue) {
EXPECT_ASSERTION(*rev_iter, "");
}
--rev_iter;
EXPECT_TRUE(*rev_iter == first);
}
// Iterate in reverse order
{
typename _List::const_reverse_iterator const_rev_iter = l.rend();
--const_rev_iter;
EXPECT_TRUE(*const_rev_iter == first);
--const_rev_iter;
EXPECT_TRUE(*const_rev_iter == second);
--const_rev_iter;
EXPECT_TRUE(*const_rev_iter == third);
EXPECT_TRUE(const_rev_iter == rcosnt_l.rbegin());
// Cannot increment below rbegin
if (void(0), TestAssertCompliance<_List>::kValue) {
EXPECT_ASSERTION(--const_rev_iter, "");
}
}
l.clear();
}
};
TEST(ComplianceREnd, IntrusiveList) { BindTypes<ComplianceREnd>(); }
// Tests compliance with clear/empty specifications.
template <typename _List>
struct ComplianceClearEmpty {
void operator()() {
typename _List::value_type first;
_List l;
EXPECT_TRUE(l.begin() == l.end());
l.push_back(first);
EXPECT_TRUE(l.begin() != l.end());
EXPECT_TRUE(l.size() == 1 && !l.empty());
l.clear();
EXPECT_TRUE(l.size() == 0 && l.empty());
EXPECT_TRUE(l.begin() == l.end());
}
};
TEST(ComplianceClearEmpty, IntrusiveList) { BindTypes<ComplianceClearEmpty>(); }
// Tests compliance with "remove" function specifications.
template <typename _List>
struct ComplianceRemove {
void operator()() {
typename _List::value_type first;
typename _List::value_type second;
typename _List::value_type third;
typename _List::value_type fourth;
_List l;
l.push_back(first);
l.push_back(second);
l.push_back(third);
l.push_back(fourth);
l.remove(first);
EXPECT_EQ(l.size(), 3u);
EXPECT_TRUE(l.front() == second && l.back() == fourth);
l.remove(third);
EXPECT_EQ(l.size(), 2u);
EXPECT_TRUE(l.front() == second && l.back() == fourth);
l.clear();
}
};
TEST(ComplianceRemove, IntrusiveList) { BindTypes<ComplianceRemove>(); }
// Implements a functor used to test "remove_if" function.
template <typename _List>
class is_to_be_removed {
public:
explicit is_to_be_removed(int _which) : which_(_which) {}
bool operator()(typename _List::const_reference) { return which_-- == 0; }
private:
void operator=(const is_to_be_removed&);
int which_;
};
// Tests compliance with "remove_if" function specifications.
template <typename _List>
struct ComplianceRemoveIf {
void operator()() {
typename _List::value_type first;
typename _List::value_type second;
typename _List::value_type third;
_List l;
l.push_back(first);
l.push_back(second);
l.push_back(third);
l.remove_if(is_to_be_removed<_List>(1));
EXPECT_EQ(l.size(), 2u);
EXPECT_TRUE(l.front() == first && l.back() == third);
l.clear();
}
};
TEST(ComplianceRemoveIf, IntrusiveList) { BindTypes<ComplianceRemoveIf>(); }
// Tests compliance with "erase" function specifications.
template <typename _List>
struct ComplianceErase {
void operator()() {
typename _List::value_type first;
typename _List::value_type second;
typename _List::value_type third;
typename _List::value_type fourth;
typename _List::value_type fifth;
typename _List::value_type sixth;
_List l;
l.push_back(first);
l.push_back(second);
l.push_back(third);
l.push_back(fourth);
l.push_back(fifth);
l.push_back(sixth);
// Bad range
if (void(0), TestAssertCompliance<_List>::kValue) {
_List l2;
EXPECT_ASSERTION(l.erase(l2.begin(), l.begin()), "");
EXPECT_ASSERTION(l.erase(++l.begin(), l.begin()), "");
}
// Erases first element
{
typename _List::iterator ret_it = l.erase(l.begin());
EXPECT_TRUE(ret_it == l.begin() && l.front() == second);
}
// Erases all elements but the first
{
typename _List::iterator ret_it = l.erase(++l.begin(), l.end());
EXPECT_TRUE(ret_it == l.end() && l.front() == second);
}
l.clear();
}
};
TEST(ComplianceErase, IntrusiveList) { BindTypes<ComplianceErase>(); }
// Tests compliance with "insert" function specifications.
template <typename _List>
struct ComplianceInsert {
void operator()() {
typename _List::value_type first;
typename _List::value_type second;
typename _List::value_type third;
typename _List::value_type fourth;
typename _List::value_type fifth;
typename _List::value_type sixth;
_List l;
l.push_back(first);
l.push_back(third);
{
l.insert(++l.begin(), second);
EXPECT_TRUE(*++l.begin() == second);
}
{
l.insert(l.end(), fourth);
EXPECT_TRUE(*--l.end() == fourth);
}
l.clear();
}
};
TEST(ComplianceInsert, IntrusiveList) { BindTypes<ComplianceInsert>(); }
// Tests compliance with "reverse" function specifications.
template <typename _List>
struct ComplianceReverse {
void operator()() {
typename _List::value_type first;
typename _List::value_type second;
typename _List::value_type third;
_List l;
l.reverse(); // Reverse empty list
EXPECT_TRUE(l.empty());
l.push_back(first);
l.reverse(); // Reverse 1 element list
EXPECT_EQ(l.size(), 1u);
{
typename _List::const_iterator const_iter = l.begin();
EXPECT_TRUE(*const_iter == first);
}
l.push_back(second);
l.reverse(); // Reverse list of 2 elements
EXPECT_EQ(l.size(), 2u);
{
typename _List::const_iterator const_iter = l.begin();
EXPECT_TRUE(*const_iter == second);
++const_iter;
EXPECT_TRUE(*const_iter == first);
}
l.reverse(); // back to original order
l.push_back(third);
l.reverse(); // Reverse list of 3 elements
EXPECT_EQ(l.size(), 3u);
{
typename _List::const_iterator const_iter = l.begin();
EXPECT_TRUE(*const_iter == third);
++const_iter;
EXPECT_TRUE(*const_iter == second);
++const_iter;
EXPECT_TRUE(*const_iter == first);
++const_iter;
EXPECT_TRUE(const_iter == l.end());
}
l.clear();
}
};
TEST(ComplianceReverse, IntrusiveList) { BindTypes<ComplianceReverse>(); }
// Tests compliance with "splice" function specifications.
template <typename _List>
struct ComplianceSplice {
void operator()() {
typename _List::value_type first;
typename _List::value_type second;
typename _List::value_type third;
typename _List::value_type fourth;
typename _List::value_type fifth;
typename _List::value_type sixth;
typename _List::value_type seventh;
typename _List::value_type eighth;
typename _List::value_type ninth;
typename _List::value_type tenth;
typename _List::value_type eleventh;
typename _List::value_type twelfth;
typename _List::value_type thirteenth;
_List l1;
l1.push_back(first);
l1.push_back(second);
_List l2;
l2.push_back(third);
l2.push_back(fourth);
l2.push_back(fifth);
_List l3;
l3.push_back(sixth);
l3.push_back(seventh);
_List l4;
l4.push_back(eighth);
l4.push_back(ninth);
l4.push_back(tenth);
_List l5;
l5.push_back(eleventh);
l5.push_back(twelfth);
l5.push_back(thirteenth);
_List l_empty;
// Bad range
if (void(0), TestAssertCompliance<_List>::kValue) {
EXPECT_ASSERTION(l4.splice(l4.begin(), l5, l4.begin()), "");
EXPECT_ASSERTION(l4.splice(l4.begin(), l5, l4.begin(), l5.end()), "");
EXPECT_ASSERTION(l4.splice(l4.begin(), l5, l5.end(), --l5.end()), "");
}
// Splices l1 just after the first element of l2
l2.splice(++l2.begin(), l1);
assert(l1.empty() && l2.size() == 5);
{
typename _List::const_iterator const_iter = l2.begin();
EXPECT_TRUE(*const_iter == third);
++const_iter;
EXPECT_TRUE(*const_iter == first);
++const_iter;
EXPECT_TRUE(*const_iter == second);
++const_iter;
EXPECT_TRUE(*const_iter == fourth);
++const_iter;
EXPECT_TRUE(*const_iter == fifth);
++const_iter;
EXPECT_TRUE(const_iter == l2.end());
}
// Splices l2 with an empty list
l2.splice(l2.begin(), l_empty);
EXPECT_EQ(l2.size(), 5u);
{
typename _List::const_iterator const_iter = l2.begin();
EXPECT_TRUE(*const_iter == third);
++const_iter;
EXPECT_TRUE(*const_iter == first);
++const_iter;
EXPECT_TRUE(*const_iter == second);
++const_iter;
EXPECT_TRUE(*const_iter == fourth);
++const_iter;
EXPECT_TRUE(*const_iter == fifth);
++const_iter;
EXPECT_TRUE(const_iter == l2.end());
}
// Splices l3 (starting at the second element) just after the first
// element of l2
l2.splice(++l2.begin(), l3, ++l3.begin(), l3.end());
EXPECT_TRUE(l3.size() == 1 && l2.size() == 6);
{
typename _List::const_iterator const_iter = l3.begin();
EXPECT_TRUE(*const_iter == sixth);
}
{
typename _List::const_iterator const_iter = l2.begin();
EXPECT_TRUE(*const_iter == third);
++const_iter;
EXPECT_TRUE(*const_iter == seventh);
++const_iter;
EXPECT_TRUE(*const_iter == first);
++const_iter;
EXPECT_TRUE(*const_iter == second);
++const_iter;
EXPECT_TRUE(*const_iter == fourth);
++const_iter;
EXPECT_TRUE(*const_iter == fifth);
++const_iter;
EXPECT_TRUE(const_iter == l2.end());
}
// Splices all l4 except the last element at the beginning of l2
l2.splice(l2.begin(), l4, l4.begin(), --l4.end());
EXPECT_TRUE(l4.size() == 1 && l2.size() == 8);
{
typename _List::const_iterator const_iter = l4.begin();
EXPECT_TRUE(*const_iter == tenth);
}
{
typename _List::const_iterator const_iter = l2.begin();
EXPECT_TRUE(*const_iter == eighth);
++const_iter;
EXPECT_TRUE(*const_iter == ninth);
++const_iter;
EXPECT_TRUE(*const_iter == third);
++const_iter;
EXPECT_TRUE(*const_iter == seventh);
++const_iter;
EXPECT_TRUE(*const_iter == first);
++const_iter;
EXPECT_TRUE(*const_iter == second);
++const_iter;
EXPECT_TRUE(*const_iter == fourth);
++const_iter;
EXPECT_TRUE(*const_iter == fifth);
++const_iter;
EXPECT_TRUE(const_iter == l2.end());
}
// Splices no element from l5
l4.splice(l4.begin(), l5, ++l5.begin(), ++l5.begin());
EXPECT_TRUE(l4.size() == 1 && l5.size() == 3);
{
typename _List::const_iterator const_iter = l4.begin();
EXPECT_TRUE(*const_iter == tenth);
++const_iter;
EXPECT_TRUE(const_iter == l4.end());
}
{
typename _List::const_iterator const_iter = l5.begin();
EXPECT_TRUE(*const_iter == eleventh);
++const_iter;
EXPECT_TRUE(*const_iter == twelfth);
++const_iter;
EXPECT_TRUE(*const_iter == thirteenth);
++const_iter;
EXPECT_TRUE(const_iter == l5.end());
}
// Self splicing of a single element
l5.splice(l5.begin(), l5, ++l5.begin());
EXPECT_EQ(l5.size(), 3u);
{
typename _List::const_iterator const_iter = l5.begin();
EXPECT_TRUE(*const_iter == twelfth);
++const_iter;
EXPECT_TRUE(*const_iter == eleventh);
++const_iter;
EXPECT_TRUE(*const_iter == thirteenth);
++const_iter;
EXPECT_TRUE(const_iter == l5.end());
}
// Self splicing of multiple elements
l5.splice(l5.begin(), l5, ++l5.begin(), l5.end());
EXPECT_EQ(l5.size(), 3u);
{
typename _List::const_iterator const_iter = l5.begin();
EXPECT_TRUE(*const_iter == eleventh);
++const_iter;
EXPECT_TRUE(*const_iter == thirteenth);
++const_iter;
EXPECT_TRUE(*const_iter == twelfth);
++const_iter;
EXPECT_TRUE(const_iter == l5.end());
}
// Self splicing of multiple elements
l5.splice(--l5.end(), l5, l5.begin(), --l5.end());
EXPECT_EQ(l5.size(), 3u);
{
typename _List::const_iterator const_iter = l5.begin();
EXPECT_TRUE(*const_iter == eleventh);
++const_iter;
EXPECT_TRUE(*const_iter == thirteenth);
++const_iter;
EXPECT_TRUE(*const_iter == twelfth);
++const_iter;
EXPECT_TRUE(const_iter == l5.end());
}
l1.clear();
l2.clear();
l3.clear();
l4.clear();
l5.clear();
}
};
TEST(ComplianceSplice, IntrusiveList) { BindTypes<ComplianceSplice>(); }
// Tests compliance with "swap" function specifications.
template <typename _List>
struct ComplianceSwap {
void operator()() {
typename _List::value_type first;
typename _List::value_type second;
typename _List::value_type third;
typename _List::value_type fourth;
typename _List::value_type fifth;
typename _List::value_type sixth;
typename _List::value_type seventh;
_List l1;
l1.push_back(first);
l1.push_back(second);
_List l2;
l2.push_back(third);
l2.push_back(fourth);
l2.push_back(fifth);
_List l3;
l3.push_back(sixth);
l3.push_back(seventh);
// Swap with itself
l1.swap(l1);
EXPECT_EQ(l1.size(), 2u);
{
typename _List::const_iterator const_iter = l1.begin();
EXPECT_TRUE(*const_iter == first);
++const_iter;
EXPECT_TRUE(*const_iter == second);
++const_iter;
EXPECT_TRUE(const_iter == l1.end());
}
// Uses list swap function
l1.swap(l2);
EXPECT_TRUE(l1.size() == 3 && l2.size() == 2);
{
typename _List::const_iterator const_iter = l1.begin();
EXPECT_TRUE(*const_iter == third);
++const_iter;
EXPECT_TRUE(*const_iter == fourth);
++const_iter;
EXPECT_TRUE(*const_iter == fifth);
++const_iter;
EXPECT_TRUE(const_iter == l1.end());
}
{
typename _List::const_iterator const_iter = l2.begin();
EXPECT_TRUE(*const_iter == first);
++const_iter;
EXPECT_TRUE(*const_iter == second);
++const_iter;
EXPECT_TRUE(const_iter == l2.end());
}
// uses std::swap
swap(l3, l2);
{
typename _List::const_iterator const_iter = l3.begin();
EXPECT_TRUE(*const_iter == first);
++const_iter;
EXPECT_TRUE(*const_iter == second);
++const_iter;
EXPECT_TRUE(const_iter == l3.end());
}
{
typename _List::const_iterator const_iter = l2.begin();
EXPECT_TRUE(*const_iter == sixth);
++const_iter;
EXPECT_TRUE(*const_iter == seventh);
++const_iter;
EXPECT_TRUE(const_iter == l2.end());
}
l1.clear();
l2.clear();
l3.clear();
}
};
TEST(ComplianceSwap, IntrusiveList) { BindTypes<ComplianceSwap>(); }
// Tests compliance with "sort" function specifications.
template <typename _List>
struct ComplianceSort {
void operator()() {
typename _List::value_type first;
typename _List::value_type second;
typename _List::value_type third;
typename _List::value_type fourth;
typename _List::value_type fifth;
typename _List::value_type sixth;
_List l;
// Sort an empty list
l.sort();
l.push_back(sixth);
// Sort list of 1 element
l.sort();
// Sort a list of 2 elements
l.push_back(second);
l.sort();
l.push_back(third);
l.push_back(fourth);
l.push_back(fifth);
l.push_back(first);
for (int i = 0; i < 2; i++) { // Sort twice the same list
l.sort();
{
typename _List::const_iterator const_iter = l.begin();
EXPECT_TRUE(*const_iter == first);
++const_iter;
EXPECT_TRUE(*const_iter == second);
++const_iter;
EXPECT_TRUE(*const_iter == third);
++const_iter;
EXPECT_TRUE(*const_iter == fourth);
++const_iter;
EXPECT_TRUE(*const_iter == fifth);
++const_iter;
EXPECT_TRUE(*const_iter == sixth);
}
}
l.sort(std::greater<typename _List::value_type>());
{
typename _List::const_iterator const_iter = l.begin();
EXPECT_TRUE(*const_iter == sixth);
++const_iter;
EXPECT_TRUE(*const_iter == fifth);
++const_iter;
EXPECT_TRUE(*const_iter == fourth);
++const_iter;
EXPECT_TRUE(*const_iter == third);
++const_iter;
EXPECT_TRUE(*const_iter == second);
++const_iter;
EXPECT_TRUE(*const_iter == first);
}
l.clear();
}
};
TEST(ComplianceSort, IntrusiveList) { BindTypes<ComplianceSort>(); }
// Tests compliance with "merge" function specifications.
template <typename _List>
struct ComplianceMerge {
void operator()() {
typename _List::value_type first;
typename _List::value_type second;
typename _List::value_type third;
typename _List::value_type fourth;
typename _List::value_type fifth;
typename _List::value_type sixth;
{
_List l1;
l1.push_back(second);
l1.push_back(fourth);
_List l2;
l2.push_back(first);
l2.push_back(third);
l1.merge(l2);
EXPECT_TRUE(l1.size() == 4 && l2.empty());
{
typename _List::const_iterator const_iter = l1.begin();
EXPECT_TRUE(*const_iter == first);
++const_iter;
EXPECT_TRUE(*const_iter == second);
++const_iter;
EXPECT_TRUE(*const_iter == third);
++const_iter;
EXPECT_TRUE(*const_iter == fourth);
}
l1.clear();
l2.clear();
}
{
_List l1;
l1.push_back(second);
l1.push_back(fourth);
_List l2;
l2.push_back(third);
l1.merge(l2);
EXPECT_TRUE(l1.size() == 3 && l2.empty());
{
typename _List::const_iterator const_iter = l1.begin();
EXPECT_TRUE(*const_iter == second);
++const_iter;
EXPECT_TRUE(*const_iter == third);
++const_iter;
EXPECT_TRUE(*const_iter == fourth);
}
l1.clear();
l2.clear();
}
{
_List l1;
l1.push_back(second);
l1.push_back(third);
_List l2;
l2.push_back(fourth);
l1.merge(l2);
EXPECT_TRUE(l1.size() == 3 && l2.empty());
{
typename _List::const_iterator const_iter = l1.begin();
EXPECT_TRUE(*const_iter == second);
++const_iter;
EXPECT_TRUE(*const_iter == third);
++const_iter;
EXPECT_TRUE(*const_iter == fourth);
}
l1.clear();
l2.clear();
}
{
_List l1;
l1.push_back(second);
_List l2;
l2.push_back(third);
l2.push_back(fourth);
l1.merge(l2);
EXPECT_TRUE(l1.size() == 3 && l2.empty());
{
typename _List::const_iterator const_iter = l1.begin();
EXPECT_TRUE(*const_iter == second);
++const_iter;
EXPECT_TRUE(*const_iter == third);
++const_iter;
EXPECT_TRUE(*const_iter == fourth);
}
l1.clear();
l2.clear();
}
{
_List l1;
l1.push_back(first);
l1.push_back(fourth);
_List l2;
l2.push_back(second);
l2.push_back(third);
l1.merge(l2);
EXPECT_TRUE(l1.size() == 4 && l2.empty());
{
typename _List::const_iterator const_iter = l1.begin();
EXPECT_TRUE(*const_iter == first);
++const_iter;
EXPECT_TRUE(*const_iter == second);
++const_iter;
EXPECT_TRUE(*const_iter == third);
++const_iter;
EXPECT_TRUE(*const_iter == fourth);
}
l1.clear();
l2.clear();
}
{
_List l1;
l1.push_back(first);
l1.push_back(fourth);
_List l2;
l2.push_back(second);
l2.push_back(third);
l1.merge(l2, std::less<typename _List::value_type>());
EXPECT_TRUE(l1.size() == 4 && l2.empty());
{
typename _List::const_iterator const_iter = l1.begin();
EXPECT_TRUE(*const_iter == first);
++const_iter;
EXPECT_TRUE(*const_iter == second);
++const_iter;
EXPECT_TRUE(*const_iter == third);
++const_iter;
EXPECT_TRUE(*const_iter == fourth);
}
l1.clear();
l2.clear();
}
{
_List l1;
l1.push_back(third);
l1.push_back(sixth);
_List l2;
l2.push_back(second);
l2.push_back(fourth);
_List l3;
l3.push_back(first);
l3.push_back(fifth);
l1.merge(l1); // Self merge
EXPECT_EQ(l1.size(), 2u);
// Merge l1 into l2 in (default) ascending order, l1 and l2 are sorted
l2.merge(l1);
EXPECT_TRUE(l1.empty() && l2.size() == 4u);
{
typename _List::const_iterator const_iter = l2.begin();
EXPECT_TRUE(*const_iter == second);
++const_iter;
EXPECT_TRUE(*const_iter == third);
++const_iter;
EXPECT_TRUE(*const_iter == fourth);
++const_iter;
EXPECT_TRUE(*const_iter == sixth);
}
// l2 and l3 are not sorted "greater"
if (void(0), TestAssertCompliance<_List>::kValue) {
EXPECT_ASSERTION(
l2.merge(l3, std::greater<typename _List::value_type>()), "");
}
// So sort l2
l2.sort(std::greater<typename _List::value_type>());
// l3 is still not sorted "greater"
if (void(0), TestAssertCompliance<_List>::kValue) {
EXPECT_ASSERTION(
l2.merge(l3, std::greater<typename _List::value_type>()), "");
}
// So sort l3
l3.sort(std::greater<typename _List::value_type>());
// l2 and l3 are sorted now
l2.merge(l3, std::greater<typename _List::value_type>());
EXPECT_TRUE(l3.empty() && l2.size() == 6);
{
typename _List::const_iterator const_iter = l2.begin();
EXPECT_TRUE(*const_iter == sixth);
++const_iter;
EXPECT_TRUE(*const_iter == fifth);
++const_iter;
EXPECT_TRUE(*const_iter == fourth);
++const_iter;
EXPECT_TRUE(*const_iter == third);
++const_iter;
EXPECT_TRUE(*const_iter == second);
++const_iter;
EXPECT_TRUE(*const_iter == first);
}
l1.clear();
l2.clear();
l3.clear();
}
}
};
TEST(ComplianceMerge, IntrusiveList) { BindTypes<ComplianceMerge>(); }
// Always return the boolean _b.
template <typename _T, bool _b>
bool Always(_T) {
return _b;
}
// Counts the number of time a functor is called
template <typename _List>
class Count {
public:
Count() : num_(0) {}
void operator()(typename _List::const_reference) { ++num_; }
int num_;
};
// Tests complicance with std::list comparison operators.
template <typename _List>
struct ComplianceComparisonOperator {
void operator()() {
typename _List::value_type first;
typename _List::value_type second;
typename _List::value_type third;
typename _List::value_type fourth;
typename _List::value_type fifth;
typename _List::value_type sixth;
typename _List::value_type first_less(first);
typename _List::value_type second_less(second);
typename _List::value_type third_less(third);
typename _List::value_type first_copy(first);
typename _List::value_type second_copy(second);
typename _List::value_type third_copy(third);
_List l1;
l1.push_back(first);
l1.push_back(second);
l1.push_back(third);
_List l1_less;
l1_less.push_back(first_less);
l1_less.push_back(second_less);
_List l1_copy;
l1_copy.push_back(first_copy);
l1_copy.push_back(second_copy);
l1_copy.push_back(third_copy);
_List l2;
l2.push_back(fourth);
l2.push_back(fifth);
EXPECT_TRUE(l1 == l1);
EXPECT_TRUE(l1 == l1_copy);
EXPECT_TRUE(l1_copy == l1);
EXPECT_TRUE(l1 != l2);
EXPECT_TRUE(l1 != l1_less);
EXPECT_TRUE(l1_less != l1);
EXPECT_TRUE(l1 <= l1);
EXPECT_TRUE(l1 >= l1);
EXPECT_TRUE(l1 < l2);
EXPECT_FALSE(l2 < l1);
EXPECT_FALSE(l1 < l1_copy);
EXPECT_TRUE(l1_less < l1);
EXPECT_TRUE(l1 <= l2);
EXPECT_TRUE(l1 <= l2);
EXPECT_TRUE(l1 <= l1_copy);
EXPECT_TRUE(l1_less <= l1);
EXPECT_TRUE(l1 > l1_less);
EXPECT_FALSE(l1 > l1_copy);
EXPECT_FALSE(l1 > l2);
EXPECT_FALSE(l1 >= l2);
EXPECT_TRUE(l1 >= l1_less);
EXPECT_TRUE(l1 >= l1_copy);
l1.clear();
l2.clear();
l1_less.clear();
l1_copy.clear();
}
};
TEST(ComplianceOperator, IntrusiveList) {
BindTypes<ComplianceComparisonOperator>();
}
// Tests compliance with std::list algorithms.
template <typename _List>
struct ComplianceAlgorithm {
void operator()() {
typename _List::value_type first;
typename _List::value_type second;
typename _List::value_type third;
typename _List::value_type fourth;
typename _List::value_type fifth;
typename _List::value_type sixth;
_List l1;
l1.push_back(first);
l1.push_back(second);
_List l2;
l2.push_back(third);
l2.push_back(fourth);
l2.push_back(fifth);
l2.push_back(sixth);
// Count algorithms
EXPECT_EQ(std::count(l1.begin(), l1.end(), second), 1);
EXPECT_EQ(std::count_if(l1.begin(), l1.end(),
Always<typename _List::const_reference, false>),
0);
EXPECT_EQ(std::count_if(l1.begin(), l1.end(),
Always<typename _List::const_reference, true>),
2);
// Iteration
Count<_List> res = std::for_each(l1.begin(), l1.end(), Count<_List>());
EXPECT_EQ(res.num_, 2);
l1.clear();
l2.clear();
}
};
TEST(ComplianceAlgorithm, IntrusiveList) { BindTypes<ComplianceAlgorithm>(); }
// Tests IntrusiveList kSafe linkMode specific behavior.
TEST(SafeLink, IntrusiveList) {
typedef Option<ozz::containers::LinkMode::kSafe> LocalOptions;
typedef TestObj1<LocalOptions> LocalTestObj;
typedef IntrusiveList<LocalTestObj, LocalOptions> List;
LocalTestObj obj;
EXPECT_FALSE(obj.is_linked());
{ // Test link state
List l, other;
#ifndef NDEBUG
EXPECT_FALSE(obj.debug_is_linked_in(l));
#endif // NDEBUG
l.push_front(obj);
EXPECT_TRUE(obj.is_linked());
#ifndef NDEBUG
EXPECT_TRUE(obj.debug_is_linked_in(l));
EXPECT_FALSE(obj.debug_is_linked_in(other));
#endif // NDEBUG
// Cannot be pushed twice
EXPECT_ASSERTION(l.push_front(obj), "");
l.pop_front();
EXPECT_TRUE(!obj.is_linked());
// Cannot be unlinked while not linked
EXPECT_ASSERTION(obj.unlink(), "");
}
// Destroy the list before the hook
EXPECT_ASSERTION(List().push_front(obj), "");
{ // Destroy the hook before the list
List l;
LocalTestObj obj2;
l.push_front(obj2);
EXPECT_ASSERTION(obj2.~LocalTestObj(), "");
obj2.unlink();
}
}
// Tests IntrusiveList kAuto linkMode specific behavior.
TEST(AutoLink, IntrusiveList) {
typedef Option<ozz::containers::LinkMode::kAuto> LocalOptions;
typedef TestObj1<LocalOptions> LocalTestObj;
typedef IntrusiveList<LocalTestObj, LocalOptions> List;
LocalTestObj obj;
EXPECT_TRUE(!obj.is_linked());
{ // Test link state
List l, other;
#ifndef NDEBUG
EXPECT_TRUE(!obj.debug_is_linked_in(l));
#endif // NDEBUG
l.push_front(obj);
EXPECT_TRUE(obj.is_linked());
#ifndef NDEBUG
EXPECT_TRUE(obj.debug_is_linked_in(l));
EXPECT_TRUE(!obj.debug_is_linked_in(other));
#endif // NDEBUG
// Cannot be pushed twice
EXPECT_ASSERTION(l.push_front(obj), "");
l.pop_front();
EXPECT_TRUE(!obj.is_linked());
// Cannot be unlinked while not linked
EXPECT_ASSERTION(obj.unlink(), "");
}
{ // Destroy the list before the hook
List l;
l.push_front(obj);
}
EXPECT_TRUE(!obj.is_linked());
{ // Destroy the hook before the list
List l;
{
LocalTestObj obj2;
l.push_front(obj2);
}
EXPECT_TRUE(l.empty());
}
}
// Tests IntrusiveList kUnsafe linkMode specific behavior.
TEST(UnsafeLink, IntrusiveList) {
typedef Option<ozz::containers::LinkMode::kUnsafe> LocalOptions;
typedef TestObj1<LocalOptions> LocalTestObj;
typedef IntrusiveList<LocalTestObj, LocalOptions> List;
LocalTestObj obj;
EXPECT_TRUE(!obj.is_linked());
{ // Test link state
List l, other;
#ifndef NDEBUG
EXPECT_TRUE(!obj.debug_is_linked_in(l));
#endif // NDEBUG
l.push_front(obj);
EXPECT_TRUE(obj.is_linked());
#ifndef NDEBUG
EXPECT_TRUE(obj.debug_is_linked_in(l));
EXPECT_TRUE(!obj.debug_is_linked_in(other));
#endif // NDEBUG
// Cannot be pushed twice
EXPECT_ASSERTION(l.push_front(obj), "");
l.pop_front();
EXPECT_TRUE(!obj.is_linked());
// Cannot be unlinked while not linked
EXPECT_ASSERTION(obj.unlink(), "");
}
{ // Destroy the list before the hook
List l;
l.push_front(obj);
} // obj is in a undefined state now
{ // Destroy the hook before the list
List l;
{
LocalTestObj obj2;
l.push_front(obj2);
} // l is in a undefined state now
}
}