//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14
// <tuple>
// template <class F, class T> constexpr decltype(auto) apply(F &&, T &&)
// Testing extended function types. The extended function types are those
// named by INVOKE but that are not actual callable objects. These include
// bullets 1-4 of invoke.
#include <tuple>
#include <array>
#include <utility>
#include <cassert>
#include "test_macros.h"
int count = 0;
struct A_int_0
{
A_int_0() : obj1(0){}
A_int_0(int x) : obj1(x) {}
int mem1() { return ++count; }
int mem2() const { return ++count; }
int const obj1;
};
struct A_int_1
{
A_int_1() {}
A_int_1(int) {}
int mem1(int x) { return count += x; }
int mem2(int x) const { return count += x; }
};
struct A_int_2
{
A_int_2() {}
A_int_2(int) {}
int mem1(int x, int y) { return count += (x + y); }
int mem2(int x, int y) const { return count += (x + y); }
};
template <class A>
struct A_wrap
{
A_wrap() {}
A_wrap(int x) : m_a(x) {}
A & operator*() { return m_a; }
A const & operator*() const { return m_a; }
A m_a;
};
typedef A_wrap<A_int_0> A_wrap_0;
typedef A_wrap<A_int_1> A_wrap_1;
typedef A_wrap<A_int_2> A_wrap_2;
template <class A>
struct A_base : public A
{
A_base() : A() {}
A_base(int x) : A(x) {}
};
typedef A_base<A_int_0> A_base_0;
typedef A_base<A_int_1> A_base_1;
typedef A_base<A_int_2> A_base_2;
template <
class Tuple, class ConstTuple
, class TuplePtr, class ConstTuplePtr
, class TupleWrap, class ConstTupleWrap
, class TupleBase, class ConstTupleBase
>
void test_ext_int_0()
{
count = 0;
typedef A_int_0 T;
typedef A_wrap_0 Wrap;
typedef A_base_0 Base;
typedef int(T::*mem1_t)();
mem1_t mem1 = &T::mem1;
typedef int(T::*mem2_t)() const;
mem2_t mem2 = &T::mem2;
typedef int const T::*obj1_t;
obj1_t obj1 = &T::obj1;
// member function w/ref
{
T a;
Tuple t{a};
assert(1 == std::apply(mem1, t));
assert(count == 1);
}
count = 0;
// member function w/pointer
{
T a;
TuplePtr t{&a};
assert(1 == std::apply(mem1, t));
assert(count == 1);
}
count = 0;
// member function w/base
{
Base a;
TupleBase t{a};
assert(1 == std::apply(mem1, t));
assert(count == 1);
}
count = 0;
// member function w/wrap
{
Wrap a;
TupleWrap t{a};
assert(1 == std::apply(mem1, t));
assert(count == 1);
}
count = 0;
// const member function w/ref
{
T const a;
ConstTuple t{a};
assert(1 == std::apply(mem2, t));
assert(count == 1);
}
count = 0;
// const member function w/pointer
{
T const a;
ConstTuplePtr t{&a};
assert(1 == std::apply(mem2, t));
assert(count == 1);
}
count = 0;
// const member function w/base
{
Base const a;
ConstTupleBase t{a};
assert(1 == std::apply(mem2, t));
assert(count == 1);
}
count = 0;
// const member function w/wrapper
{
Wrap const a;
ConstTupleWrap t{a};
assert(1 == std::apply(mem2, t));
assert(1 == count);
}
// member object w/ref
{
T a{42};
Tuple t{a};
assert(42 == std::apply(obj1, t));
}
// member object w/pointer
{
T a{42};
TuplePtr t{&a};
assert(42 == std::apply(obj1, t));
}
// member object w/base
{
Base a{42};
TupleBase t{a};
assert(42 == std::apply(obj1, t));
}
// member object w/wrapper
{
Wrap a{42};
TupleWrap t{a};
assert(42 == std::apply(obj1, t));
}
}
template <
class Tuple, class ConstTuple
, class TuplePtr, class ConstTuplePtr
, class TupleWrap, class ConstTupleWrap
, class TupleBase, class ConstTupleBase
>
void test_ext_int_1()
{
count = 0;
typedef A_int_1 T;
typedef A_wrap_1 Wrap;
typedef A_base_1 Base;
typedef int(T::*mem1_t)(int);
mem1_t mem1 = &T::mem1;
typedef int(T::*mem2_t)(int) const;
mem2_t mem2 = &T::mem2;
// member function w/ref
{
T a;
Tuple t{a, 2};
assert(2 == std::apply(mem1, t));
assert(count == 2);
}
count = 0;
// member function w/pointer
{
T a;
TuplePtr t{&a, 3};
assert(3 == std::apply(mem1, t));
assert(count == 3);
}
count = 0;
// member function w/base
{
Base a;
TupleBase t{a, 4};
assert(4 == std::apply(mem1, t));
assert(count == 4);
}
count = 0;
// member function w/wrap
{
Wrap a;
TupleWrap t{a, 5};
assert(5 == std::apply(mem1, t));
assert(count == 5);
}
count = 0;
// const member function w/ref
{
T const a;
ConstTuple t{a, 6};
assert(6 == std::apply(mem2, t));
assert(count == 6);
}
count = 0;
// const member function w/pointer
{
T const a;
ConstTuplePtr t{&a, 7};
assert(7 == std::apply(mem2, t));
assert(count == 7);
}
count = 0;
// const member function w/base
{
Base const a;
ConstTupleBase t{a, 8};
assert(8 == std::apply(mem2, t));
assert(count == 8);
}
count = 0;
// const member function w/wrapper
{
Wrap const a;
ConstTupleWrap t{a, 9};
assert(9 == std::apply(mem2, t));
assert(9 == count);
}
}
template <
class Tuple, class ConstTuple
, class TuplePtr, class ConstTuplePtr
, class TupleWrap, class ConstTupleWrap
, class TupleBase, class ConstTupleBase
>
void test_ext_int_2()
{
count = 0;
typedef A_int_2 T;
typedef A_wrap_2 Wrap;
typedef A_base_2 Base;
typedef int(T::*mem1_t)(int, int);
mem1_t mem1 = &T::mem1;
typedef int(T::*mem2_t)(int, int) const;
mem2_t mem2 = &T::mem2;
// member function w/ref
{
T a;
Tuple t{a, 1, 1};
assert(2 == std::apply(mem1, t));
assert(count == 2);
}
count = 0;
// member function w/pointer
{
T a;
TuplePtr t{&a, 1, 2};
assert(3 == std::apply(mem1, t));
assert(count == 3);
}
count = 0;
// member function w/base
{
Base a;
TupleBase t{a, 2, 2};
assert(4 == std::apply(mem1, t));
assert(count == 4);
}
count = 0;
// member function w/wrap
{
Wrap a;
TupleWrap t{a, 2, 3};
assert(5 == std::apply(mem1, t));
assert(count == 5);
}
count = 0;
// const member function w/ref
{
T const a;
ConstTuple t{a, 3, 3};
assert(6 == std::apply(mem2, t));
assert(count == 6);
}
count = 0;
// const member function w/pointer
{
T const a;
ConstTuplePtr t{&a, 3, 4};
assert(7 == std::apply(mem2, t));
assert(count == 7);
}
count = 0;
// const member function w/base
{
Base const a;
ConstTupleBase t{a, 4, 4};
assert(8 == std::apply(mem2, t));
assert(count == 8);
}
count = 0;
// const member function w/wrapper
{
Wrap const a;
ConstTupleWrap t{a, 4, 5};
assert(9 == std::apply(mem2, t));
assert(9 == count);
}
}
int main(int, char**)
{
{
test_ext_int_0<
std::tuple<A_int_0 &>, std::tuple<A_int_0 const &>
, std::tuple<A_int_0 *>, std::tuple<A_int_0 const *>
, std::tuple<A_wrap_0 &>, std::tuple<A_wrap_0 const &>
, std::tuple<A_base_0 &>, std::tuple<A_base_0 const &>
>();
test_ext_int_0<
std::tuple<A_int_0>, std::tuple<A_int_0 const>
, std::tuple<A_int_0 *>, std::tuple<A_int_0 const *>
, std::tuple<A_wrap_0>, std::tuple<A_wrap_0 const>
, std::tuple<A_base_0>, std::tuple<A_base_0 const>
>();
test_ext_int_0<
std::array<A_int_0, 1>, std::array<A_int_0 const, 1>
, std::array<A_int_0*, 1>, std::array<A_int_0 const*, 1>
, std::array<A_wrap_0, 1>, std::array<A_wrap_0 const, 1>
, std::array<A_base_0, 1>, std::array<A_base_0 const, 1>
>();
}
{
test_ext_int_1<
std::tuple<A_int_1 &, int>, std::tuple<A_int_1 const &, int>
, std::tuple<A_int_1 *, int>, std::tuple<A_int_1 const *, int>
, std::tuple<A_wrap_1 &, int>, std::tuple<A_wrap_1 const &, int>
, std::tuple<A_base_1 &, int>, std::tuple<A_base_1 const &, int>
>();
test_ext_int_1<
std::tuple<A_int_1, int>, std::tuple<A_int_1 const, int>
, std::tuple<A_int_1 *, int>, std::tuple<A_int_1 const *, int>
, std::tuple<A_wrap_1, int>, std::tuple<A_wrap_1 const, int>
, std::tuple<A_base_1, int>, std::tuple<A_base_1 const, int>
>();
test_ext_int_1<
std::pair<A_int_1 &, int>, std::pair<A_int_1 const &, int>
, std::pair<A_int_1 *, int>, std::pair<A_int_1 const *, int>
, std::pair<A_wrap_1 &, int>, std::pair<A_wrap_1 const &, int>
, std::pair<A_base_1 &, int>, std::pair<A_base_1 const &, int>
>();
test_ext_int_1<
std::pair<A_int_1, int>, std::pair<A_int_1 const, int>
, std::pair<A_int_1 *, int>, std::pair<A_int_1 const *, int>
, std::pair<A_wrap_1, int>, std::pair<A_wrap_1 const, int>
, std::pair<A_base_1, int>, std::pair<A_base_1 const, int>
>();
}
{
test_ext_int_2<
std::tuple<A_int_2 &, int, int>, std::tuple<A_int_2 const &, int, int>
, std::tuple<A_int_2 *, int, int>, std::tuple<A_int_2 const *, int, int>
, std::tuple<A_wrap_2 &, int, int>, std::tuple<A_wrap_2 const &, int, int>
, std::tuple<A_base_2 &, int, int>, std::tuple<A_base_2 const &, int, int>
>();
test_ext_int_2<
std::tuple<A_int_2, int, int>, std::tuple<A_int_2 const, int, int>
, std::tuple<A_int_2 *, int, int>, std::tuple<A_int_2 const *, int, int>
, std::tuple<A_wrap_2, int, int>, std::tuple<A_wrap_2 const, int, int>
, std::tuple<A_base_2, int, int>, std::tuple<A_base_2 const, int, int>
>();
}
return 0;
}