418 lines
12 KiB
C++
418 lines
12 KiB
C++
/*=============================================================================
|
|
|
|
This file is part of FLINT.
|
|
|
|
FLINT is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
FLINT is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with FLINT; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
=============================================================================*/
|
|
/******************************************************************************
|
|
|
|
Copyright (C) 2013 Tom Bachmann
|
|
|
|
******************************************************************************/
|
|
|
|
#include <set>
|
|
|
|
#include "flintxx/test/helpers.h"
|
|
#include "flintxx/tuple.h"
|
|
#include "flintxx/mp.h"
|
|
|
|
using namespace flint;
|
|
using namespace mp;
|
|
using namespace traits;
|
|
|
|
void
|
|
test_make()
|
|
{
|
|
typedef make_tuple<int, char, int> make3;
|
|
typedef make_tuple<int, char> make2;
|
|
typedef make_tuple<int> make1;
|
|
|
|
tassert((equal_types<
|
|
make3::type,
|
|
tuple<int, tuple<char, tuple<int, empty_tuple> > >
|
|
>::val));
|
|
tassert((equal_types<
|
|
make2::type,
|
|
tuple<int, tuple<char, empty_tuple> >
|
|
>::val));
|
|
tassert((equal_types<make1::type, tuple<int, empty_tuple> >::val));
|
|
tassert(make3::type::len == 3);
|
|
tassert(make2::type::len == 2);
|
|
tassert(make1::type::len == 1);
|
|
|
|
make3::type tup = make3::make(1, 'b', 3);
|
|
tassert(tup.head == 1);
|
|
tassert(tup.tail.head == 'b');
|
|
tassert(tup.tail.tail.head == 3);
|
|
tup.first() = 2;
|
|
tassert(tup.head == 2);
|
|
tassert(tup.second() == 'b');
|
|
|
|
make2::type pair = make2::make(1, 'b');
|
|
tassert(pair.first() == 1);
|
|
tassert(pair.second() == 'b');
|
|
|
|
make1::type singleton = make1::make(1);
|
|
tassert(singleton.first() == 1);
|
|
|
|
typedef make_tuple<const int&, const int&> makeref;
|
|
tassert((equal_types<makeref::type::head_t, const int&>::val));
|
|
int a = 4;
|
|
makeref::type reftup = makeref::make(a, a);
|
|
tassert(reftup.head == 4);
|
|
a = 5;
|
|
tassert(reftup.second() == 5);
|
|
}
|
|
|
|
template<int i, bool default_ctor = false>
|
|
struct type_n
|
|
{
|
|
int payload;
|
|
type_n(int p) : payload(p) {};
|
|
};
|
|
template<int i>
|
|
struct type_n<i, true>
|
|
{
|
|
int payload;
|
|
type_n(int p) : payload(p) {};
|
|
type_n() {};
|
|
};
|
|
|
|
void
|
|
test_back()
|
|
{
|
|
typedef type_n<0> A;
|
|
typedef type_n<1> B;
|
|
typedef type_n<2> C;
|
|
typedef type_n<3> D;
|
|
|
|
typedef make_tuple<A, B, C> make3;
|
|
typedef make_tuple<A*, B*, C*> make3p;
|
|
typedef make_tuple<B, C> make2A;
|
|
typedef make_tuple<A, C> make2B;
|
|
|
|
typedef back_tuple<make3p::type, void> backvoid;
|
|
typedef back_tuple<make3p::type, D> backD;
|
|
typedef back_tuple<make3p::type, A> backA;
|
|
typedef back_tuple<make3p::type, B> backB;
|
|
|
|
tassert((equal_types<backvoid::type, make3::type>::val));
|
|
tassert((equal_types<backD::type, make3::type>::val));
|
|
tassert((equal_types<backA::type, make2A::type>::val));
|
|
tassert((equal_types<backB::type, make2B::type>::val));
|
|
|
|
make3::type backing = make3::make(1, 2, 3);
|
|
make3p::type pointers;
|
|
backvoid::init(pointers, backing, 0);
|
|
tassert(pointers.first()->payload == 1);
|
|
backing.second() = 4;
|
|
tassert(pointers.second()->payload == 4);
|
|
|
|
A ret = 4;
|
|
make2A::type backing2 = make2A::make(1, 2);
|
|
backA::init(pointers, backing2, &ret);
|
|
tassert(pointers.first()->payload == 4);
|
|
tassert(pointers.second()->payload == 1);
|
|
ret.payload = 5;
|
|
backing2.head.payload = 6;
|
|
tassert(pointers.first()->payload == 5);
|
|
tassert(pointers.second()->payload == 6);
|
|
|
|
// Test some corner cases.
|
|
tassert((equal_types<back_tuple<empty_tuple>::type, empty_tuple>::val));
|
|
typedef tuple<int*, empty_tuple> tup1_t;
|
|
tassert((equal_types<back_tuple<tup1_t, int>::type, empty_tuple>::val));
|
|
}
|
|
|
|
void
|
|
test_concat()
|
|
{
|
|
typedef type_n<0> A;
|
|
typedef type_n<1> B;
|
|
typedef type_n<2> C;
|
|
typedef type_n<3> D;
|
|
typedef type_n<4> E;
|
|
|
|
typedef make_tuple<A, B, C> make1st;
|
|
typedef make_tuple<D, E> make2nd;
|
|
|
|
typedef concat_tuple<make1st::type, make2nd::type> concater;
|
|
tassert((equal_types<
|
|
concater::type,
|
|
tuple<A, tuple<B, tuple<C, make2nd::type> > >
|
|
>::val));
|
|
|
|
concater::type concated = concater::type(0,
|
|
tuple<B, tuple<C, make2nd::type> >(1,
|
|
tuple<C, make2nd::type>(2, make2nd::make(3, 4))));
|
|
make2nd::type second = concater::get_second(concated);
|
|
tassert(second.first().payload == 3);
|
|
tassert(second.second().payload == 4);
|
|
make1st::type first = concater::get_first(concated);
|
|
tassert(first.first().payload == 0);
|
|
tassert(first.second().payload == 1);
|
|
tassert(first.tail.second().payload == 2);
|
|
|
|
first.first().payload = 17;
|
|
second.first().payload = 18;
|
|
concated = concater::doit(first, second);
|
|
tassert(concated.first().payload == 17);
|
|
tassert(concated.tail.tail.tail.head.payload == 18);
|
|
|
|
// Test a few corner cases.
|
|
tassert((equal_types<
|
|
concat_tuple<empty_tuple, empty_tuple>::type,
|
|
empty_tuple
|
|
>::val));
|
|
typedef tuple<int, empty_tuple> tup1_t;
|
|
tassert((equal_types<
|
|
concat_tuple<tup1_t, empty_tuple>::type,
|
|
tup1_t
|
|
>::val));
|
|
tassert((equal_types<
|
|
concat_tuple<empty_tuple, tup1_t>::type,
|
|
tup1_t
|
|
>::val));
|
|
}
|
|
|
|
namespace flint{
|
|
namespace detail
|
|
{
|
|
template<class T>
|
|
struct fillit
|
|
{
|
|
static void doit(T& t, int start)
|
|
{
|
|
t.head.payload = start;
|
|
detail::fillit<typename T::tail_t>::doit(t.tail, ++start);
|
|
}
|
|
};
|
|
|
|
template<>
|
|
struct fillit<empty_tuple>
|
|
{
|
|
static void doit(empty_tuple e, int start)
|
|
{
|
|
}
|
|
};
|
|
|
|
template<class T>
|
|
struct values
|
|
{
|
|
static void doit(const T& t, std::set<int>& values)
|
|
{
|
|
values.insert(t.head.payload);
|
|
detail::values<typename T::tail_t>::doit(t.tail, values);
|
|
}
|
|
};
|
|
|
|
template<>
|
|
struct values<empty_tuple>
|
|
{
|
|
static void doit(empty_tuple e, std::set<int>& values)
|
|
{
|
|
}
|
|
};
|
|
}
|
|
}
|
|
|
|
template<class T>
|
|
void fillit(T& t, int start = 1)
|
|
{
|
|
detail::fillit<T>::doit(t, start);
|
|
}
|
|
|
|
template<class T>
|
|
std::set<int> values(const T& t)
|
|
{
|
|
std::set<int> ret;
|
|
detail::values<T>::doit(t, ret);
|
|
return ret;
|
|
}
|
|
|
|
void
|
|
test_merge()
|
|
{
|
|
typedef type_n<0, true> A;
|
|
typedef type_n<1, true> B;
|
|
typedef type_n<2, true> C;
|
|
typedef type_n<3, true> D;
|
|
typedef type_n<4, true> E;
|
|
|
|
// Test that merging tuples <T1, T2, T3> and <U1, U2>
|
|
// yields something of length n, and that the constitutents can be
|
|
// recovered. Also do other order.
|
|
#define TEST32n(T1, T2, T3, U1, U2, n) \
|
|
{ \
|
|
typedef make_tuple<T1, T2, T3> m1; \
|
|
typedef make_tuple<U1, U2> m2; \
|
|
typedef merge_tuple<m1::type, m2::type> merge1; \
|
|
typedef merge_tuple<m2::type, m1::type> merge2; \
|
|
tassert(merge1::type::len == n); \
|
|
tassert(merge2::type::len == n); \
|
|
merge1::type merged1; \
|
|
{ \
|
|
fillit(merged1); \
|
|
m1::type n1 = merge1::get_first(merged1); \
|
|
m2::type n2 = merge1::get_second(merged1); \
|
|
std::set<int> vals1 = values(n1), vals2 = values(n2); \
|
|
vals1.insert(vals2.begin(), vals2.end()); \
|
|
tassert(vals1.size() == n); \
|
|
} \
|
|
merge2::type merged2; \
|
|
{ \
|
|
fillit(merged2); \
|
|
m2::type n2 = merge2::get_first(merged2); \
|
|
m1::type n1 = merge2::get_second(merged2); \
|
|
std::set<int> vals1 = values(n1), vals2 = values(n2); \
|
|
vals1.insert(vals2.begin(), vals2.end()); \
|
|
tassert(vals1.size() == n); \
|
|
} \
|
|
}
|
|
|
|
TEST32n(A, B, C, A, B, 3);
|
|
TEST32n(A, B, C, B, A, 3);
|
|
TEST32n(A, B, C, A, C, 3);
|
|
TEST32n(A, B, C, C, A, 3);
|
|
TEST32n(A, B, C, C, B, 3);
|
|
TEST32n(A, B, C, B, C, 3);
|
|
TEST32n(A, A, A, A, A, 3);
|
|
|
|
TEST32n(A, B, C, A, D, 4);
|
|
TEST32n(A, B, C, B, D, 4);
|
|
TEST32n(A, B, C, C, D, 4);
|
|
TEST32n(A, B, C, D, A, 4);
|
|
TEST32n(A, B, C, D, B, 4);
|
|
TEST32n(A, B, C, D, C, 4);
|
|
TEST32n(A, A, A, A, B, 4);
|
|
|
|
TEST32n(A, B, C, D, E, 5);
|
|
TEST32n(A, A, A, B, B, 5);
|
|
|
|
typedef merge_tuple<empty_tuple, empty_tuple> emptymerge;
|
|
tassert((equal_types<emptymerge::type, empty_tuple>::val));
|
|
|
|
typedef merge_tuple<make_tuple<A, A>::type, empty_tuple> anothermerge;
|
|
tassert(anothermerge::type::len == 2);
|
|
}
|
|
|
|
void
|
|
test_traits()
|
|
{
|
|
tassert((is_homogeneous_tuple<make_tuple<int, int, int>::type, int>::val
|
|
== true));
|
|
tassert((is_homogeneous_tuple<make_tuple<int, char, int>::type, int>::val
|
|
== false));
|
|
|
|
tassert(is_tuple<empty_tuple>::val == true);
|
|
tassert(is_tuple<make_tuple<int>::type>::val == true);
|
|
tassert((is_tuple<make_tuple<int, slong>::type>::val == true));
|
|
tassert(is_tuple<int>::val == false);
|
|
}
|
|
|
|
struct filler
|
|
{
|
|
template<class T>
|
|
T create() const
|
|
{
|
|
if(mp::equal_types<T, slong>::val)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
};
|
|
void
|
|
test_htuples()
|
|
{
|
|
tassert((equal_types<make_tuple<int, int, int>::type,
|
|
make_homogeneous_tuple<int, 3>::type>::val));
|
|
|
|
typedef make_tuple<int, int, int> maker;
|
|
maker::type tpl = maker::make(1, 2, 3);
|
|
|
|
tassert(htuples::extract<1>(tpl) == make_tuple<int>::make(1));
|
|
tassert((htuples::extract<2>(tpl) == make_tuple<int, int>::make(1, 2)));
|
|
tassert((htuples::extract<3>(tpl) == make_tuple<int, int, int>::make(1, 2, 3)));
|
|
|
|
typedef make_tuple<int, int> make2;
|
|
tassert(htuples::removeres(tpl, 1) == make2::make(2, 3));
|
|
tassert(htuples::removeres(tpl, 2) == make2::make(1, 3));
|
|
tassert(htuples::removeres(tpl, 3) == make2::make(1, 2));
|
|
tassert(htuples::removeres(tpl, 4) == make2::make(1, 2));
|
|
|
|
typedef make_tuple<int, slong, int> maker3;
|
|
tassert((maker3::make(0, 1, 0) == htuples::fill<maker3::type>(filler())));
|
|
}
|
|
|
|
void
|
|
test_get()
|
|
{
|
|
typedef make_tuple<int, int&, const int&>::type tuple_t;
|
|
int a, b;
|
|
tuple_t t(17, make_tuple<int&, const int&>::type(a,
|
|
make_tuple<const int&>::type(b, empty_tuple())));
|
|
|
|
tassert((equal_types<int, tuple_get<tuple_t, 0>::type>::val));
|
|
tassert((equal_types<int&, tuple_get<tuple_t, 1>::type>::val));
|
|
tassert((equal_types<const int&, tuple_get<tuple_t, 2>::type>::val));
|
|
|
|
tassert((tuple_get<tuple_t, 0>::get(t) == 17));
|
|
tuple_get<tuple_t, 1>::get(t) = 42;
|
|
b = 3;
|
|
tassert((tuple_get<tuple_t, 2>::get(t) == 3));
|
|
tassert(a == 42);
|
|
|
|
const tuple_t ct(t);
|
|
tuple_get<tuple_t, 1>::get(ct) = 17;
|
|
tassert((tuple_get<tuple_t, 1>::get(ct) == 17));
|
|
}
|
|
|
|
void
|
|
test_set()
|
|
{
|
|
make_tuple<int, int, int>::type tup;
|
|
tup.set(make_tuple<int, char, short>::make(1, 2, 3));
|
|
tassert((tup == make_tuple<int, int, int>::make(1, 2, 3)));
|
|
}
|
|
|
|
void
|
|
test_equals_elementwise()
|
|
{
|
|
tassert((make_tuple<int, int, int>::make(1, 2, 3).equals_elementwise(
|
|
make_tuple<int, char, slong>::make(1, 2, 3))));
|
|
tassert((!make_tuple<int, int, int>::make(0, 2, 3).equals_elementwise(
|
|
make_tuple<int, char, slong>::make(1, 2, 3))));
|
|
}
|
|
|
|
int
|
|
main()
|
|
{
|
|
std::cout << "tuple....";
|
|
|
|
test_make();
|
|
test_back();
|
|
test_concat();
|
|
test_merge();
|
|
test_traits();
|
|
test_htuples();
|
|
test_get();
|
|
test_set();
|
|
test_equals_elementwise();
|
|
|
|
std::cout << "PASS" << std::endl;
|
|
return 0;
|
|
}
|
|
|