1//===----------------------------------------------------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is dual licensed under the MIT and the University of Illinois Open
6// Source Licenses. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// UNSUPPORTED: c++98, c++03, c++11, c++14
11
12// <numeric>
13
14// template<class _M, class _N>
15// constexpr common_type_t<_M,_N> gcd(_M __m, _N __n)
16
17#include <numeric>
18#include <cassert>
19#include <cstdlib>    // for rand()
20#include <iostream>
21
22constexpr struct {
23  int x;
24  int y;
25  int expect;
26} Cases[] = {
27    {0, 0, 0},
28    {1, 0, 1},
29    {0, 1, 1},
30    {1, 1, 1},
31    {2, 3, 1},
32    {2, 4, 2},
33    {36, 17, 1},
34    {36, 18, 18}
35};
36
37
38template <typename Input1, typename Input2, typename Output>
39constexpr bool test0(Input1 in1, Input2 in2, Output out)
40{
41    static_assert((std::is_same<Output, decltype(std::gcd(in1, in2))>::value), "" );
42    static_assert((std::is_same<Output, decltype(std::gcd(in2, in1))>::value), "" );
43    return out == std::gcd(in1, in2) ? true : (std::abort(), false);
44}
45
46
47template <typename Input1, typename Input2 = Input1>
48constexpr bool do_test(int = 0)
49{
50    using S1 = typename std::make_signed<Input1>::type;
51    using S2 = typename std::make_signed<Input2>::type;
52    using U1 = typename std::make_unsigned<Input1>::type;
53    using U2 = typename std::make_unsigned<Input2>::type;
54    bool accumulate = true;
55    for (auto TC : Cases) {
56        { // Test with two signed types
57            using Output = std::common_type_t<S1, S2>;
58            accumulate &= test0<S1, S2, Output>(TC.x, TC.y, TC.expect);
59            accumulate &= test0<S1, S2, Output>(-TC.x, TC.y, TC.expect);
60            accumulate &= test0<S1, S2, Output>(TC.x, -TC.y, TC.expect);
61            accumulate &= test0<S1, S2, Output>(-TC.x, -TC.y, TC.expect);
62            accumulate &= test0<S2, S1, Output>(TC.x, TC.y, TC.expect);
63            accumulate &= test0<S2, S1, Output>(-TC.x, TC.y, TC.expect);
64            accumulate &= test0<S2, S1, Output>(TC.x, -TC.y, TC.expect);
65            accumulate &= test0<S2, S1, Output>(-TC.x, -TC.y, TC.expect);
66        }
67        { // test with two unsigned types
68            using Output = std::common_type_t<U1, U2>;
69            accumulate &= test0<U1, U2, Output>(TC.x, TC.y, TC.expect);
70            accumulate &= test0<U2, U1, Output>(TC.x, TC.y, TC.expect);
71        }
72        { // Test with mixed signs
73            using Output = std::common_type_t<S1, U2>;
74            accumulate &= test0<S1, U2, Output>(TC.x, TC.y, TC.expect);
75            accumulate &= test0<U2, S1, Output>(TC.x, TC.y, TC.expect);
76            accumulate &= test0<S1, U2, Output>(-TC.x, TC.y, TC.expect);
77            accumulate &= test0<U2, S1, Output>(TC.x, -TC.y, TC.expect);
78        }
79        { // Test with mixed signs
80            using Output = std::common_type_t<S2, U1>;
81            accumulate &= test0<S2, U1, Output>(TC.x, TC.y, TC.expect);
82            accumulate &= test0<U1, S2, Output>(TC.x, TC.y, TC.expect);
83            accumulate &= test0<S2, U1, Output>(-TC.x, TC.y, TC.expect);
84            accumulate &= test0<U1, S2, Output>(TC.x, -TC.y, TC.expect);
85        }
86    }
87    return accumulate;
88}
89
90int main()
91{
92    auto non_cce = std::rand(); // a value that can't possibly be constexpr
93
94    static_assert(do_test<signed char>(), "");
95    static_assert(do_test<short>(), "");
96    static_assert(do_test<int>(), "");
97    static_assert(do_test<long>(), "");
98    static_assert(do_test<long long>(), "");
99
100    assert(do_test<signed char>(non_cce));
101    assert(do_test<short>(non_cce));
102    assert(do_test<int>(non_cce));
103    assert(do_test<long>(non_cce));
104    assert(do_test<long long>(non_cce));
105
106    static_assert(do_test< int8_t>(), "");
107    static_assert(do_test<int16_t>(), "");
108    static_assert(do_test<int32_t>(), "");
109    static_assert(do_test<int64_t>(), "");
110
111    assert(do_test< int8_t>(non_cce));
112    assert(do_test<int16_t>(non_cce));
113    assert(do_test<int32_t>(non_cce));
114    assert(do_test<int64_t>(non_cce));
115
116    static_assert(do_test<signed char, int>(), "");
117    static_assert(do_test<int, signed char>(), "");
118    static_assert(do_test<short, int>(), "");
119    static_assert(do_test<int, short>(), "");
120    static_assert(do_test<int, long>(), "");
121    static_assert(do_test<long, int>(), "");
122    static_assert(do_test<int, long long>(), "");
123    static_assert(do_test<long long, int>(), "");
124
125    assert((do_test<signed char, int>(non_cce)));
126    assert((do_test<int, signed char>(non_cce)));
127    assert((do_test<short, int>(non_cce)));
128    assert((do_test<int, short>(non_cce)));
129    assert((do_test<int, long>(non_cce)));
130    assert((do_test<long, int>(non_cce)));
131    assert((do_test<int, long long>(non_cce)));
132    assert((do_test<long long, int>(non_cce)));
133
134//  LWG#2837
135    {
136        auto res = std::gcd((int64_t)1234, (int32_t)-2147483648);
137        static_assert( std::is_same<decltype(res), std::common_type<int64_t, int32_t>::type>::value, "");
138        assert(res == 2);
139    }
140}
141