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
11// <numeric>
12
13// template<class _M, class _N>
14// constexpr common_type_t<_M,_N> gcd(_M __m, _N __n)
15
16#include <experimental/numeric>
17#include <cassert>
18#include <cstdlib>
19#include <iostream>
20
21constexpr struct {
22  int x;
23  int y;
24  int expect;
25} Cases[] = {
26    {0, 0, 0},
27    {1, 0, 0},
28    {0, 1, 0},
29    {1, 1, 1},
30    {2, 3, 6},
31    {2, 4, 4},
32    {3, 17, 51},
33    {36, 18, 36}
34};
35
36template <typename Input1, typename Input2, typename Output>
37constexpr bool test0(Input1 in1, Input2 in2, Output out)
38{
39    static_assert((std::is_same<Output, decltype(std::experimental::lcm(Input1(0), Input2(0)))>::value), "" );
40    static_assert((std::is_same<Output, decltype(std::experimental::lcm(Input2(0), Input1(0)))>::value), "" );
41    return out == std::experimental::lcm(in1, in2) ? true : (std::abort(), false);
42}
43
44
45template <typename Input1, typename Input2 = Input1>
46constexpr bool do_test(int = 0)
47{
48    using S1 = typename std::make_signed<Input1>::type;
49    using S2 = typename std::make_signed<Input2>::type;
50    using U1 = typename std::make_unsigned<Input1>::type;
51    using U2 = typename std::make_unsigned<Input2>::type;
52    bool accumulate = true;
53    for (auto TC : Cases) {
54        { // Test with two signed types
55            using Output = std::common_type_t<S1, S2>;
56            accumulate &= test0<S1, S2, Output>(TC.x, TC.y, TC.expect);
57            accumulate &= test0<S1, S2, Output>(-TC.x, TC.y, TC.expect);
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<S2, S1, Output>(TC.x, TC.y, TC.expect);
61            accumulate &= test0<S2, S1, 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        }
65        { // test with two unsigned types
66            using Output = std::common_type_t<U1, U2>;
67            accumulate &= test0<U1, U2, Output>(TC.x, TC.y, TC.expect);
68            accumulate &= test0<U2, U1, Output>(TC.x, TC.y, TC.expect);
69        }
70        { // Test with mixed signs
71            using Output = std::common_type_t<S1, U2>;
72            accumulate &= test0<S1, U2, Output>(TC.x, TC.y, TC.expect);
73            accumulate &= test0<U2, S1, Output>(TC.x, TC.y, TC.expect);
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        }
77        { // Test with mixed signs
78            using Output = std::common_type_t<S2, U1>;
79            accumulate &= test0<S2, U1, Output>(TC.x, TC.y, TC.expect);
80            accumulate &= test0<U1, S2, Output>(TC.x, TC.y, TC.expect);
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        }
84    }
85    return accumulate;
86}
87
88int main()
89{
90    auto non_cce = std::rand(); // a value that can't possibly be constexpr
91
92    static_assert(do_test<signed char>(), "");
93    static_assert(do_test<short>(), "");
94    static_assert(do_test<int>(), "");
95    static_assert(do_test<long>(), "");
96    static_assert(do_test<long long>(), "");
97
98    assert(do_test<signed char>(non_cce));
99    assert(do_test<short>(non_cce));
100    assert(do_test<int>(non_cce));
101    assert(do_test<long>(non_cce));
102    assert(do_test<long long>(non_cce));
103
104    static_assert(do_test< int8_t>(), "");
105    static_assert(do_test<int16_t>(), "");
106    static_assert(do_test<int32_t>(), "");
107    static_assert(do_test<int64_t>(), "");
108
109    assert(do_test< int8_t>(non_cce));
110    assert(do_test<int16_t>(non_cce));
111    assert(do_test<int32_t>(non_cce));
112    assert(do_test<int64_t>(non_cce));
113
114    static_assert(do_test<signed char, int>(), "");
115    static_assert(do_test<int, signed char>(), "");
116    static_assert(do_test<short, int>(), "");
117    static_assert(do_test<int, short>(), "");
118    static_assert(do_test<int, long>(), "");
119    static_assert(do_test<long, int>(), "");
120    static_assert(do_test<int, long long>(), "");
121    static_assert(do_test<long long, int>(), "");
122
123    assert((do_test<signed char, int>(non_cce)));
124    assert((do_test<int, signed char>(non_cce)));
125    assert((do_test<short, int>(non_cce)));
126    assert((do_test<int, short>(non_cce)));
127    assert((do_test<int, long>(non_cce)));
128    assert((do_test<long, int>(non_cce)));
129    assert((do_test<int, long long>(non_cce)));
130    assert((do_test<long long, int>(non_cce)));
131
132//  LWG#2792
133    {
134    auto res1 = std::experimental::lcm((int64_t)1234, (int32_t)-2147483648);
135    (void) std::experimental::lcm<int, unsigned long>(INT_MIN, 2);	// this used to trigger UBSAN
136    static_assert( std::is_same<decltype(res1), std::common_type<int64_t, int32_t>::type>::value, "");
137	assert(res1 == 1324997410816LL);
138    }
139}
140