mclow.lists updated this revision to Diff 60856.
mclow.lists added a comment.

Updated based on comments here and elsewhere.

- Do the abs once, rather than at every level of recursion
- Add tests for `bool`.
- Constexpr

Also, add an assertion to detect overflow in `lcm`.

I have not yet incorporated Eric's constexpr tests.


http://reviews.llvm.org/D21343

Files:
  include/experimental/numeric
  test/std/experimental/numeric/numeric.ops.overview/nothing_to_do.pass.cpp
  test/std/experimental/numeric/numeric.ops/nothing_to_do.pass.cpp
  
test/std/experimental/numeric/numeric.ops/numeric.ops.gcd/gcd.not_integral1.fail.cpp
  
test/std/experimental/numeric/numeric.ops/numeric.ops.gcd/gcd.not_integral2.fail.cpp
  test/std/experimental/numeric/numeric.ops/numeric.ops.gcd/gcd.pass.cpp
  
test/std/experimental/numeric/numeric.ops/numeric.ops.lcm/lcm.not_integral1.fail.cpp
  
test/std/experimental/numeric/numeric.ops/numeric.ops.lcm/lcm.not_integral2.fail.cpp
  test/std/experimental/numeric/numeric.ops/numeric.ops.lcm/lcm.pass.cpp

Index: test/std/experimental/numeric/numeric.ops.overview/nothing_to_do.pass.cpp
===================================================================
--- test/std/experimental/numeric/numeric.ops.overview/nothing_to_do.pass.cpp
+++ test/std/experimental/numeric/numeric.ops.overview/nothing_to_do.pass.cpp
@@ -0,0 +1,15 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// UNSUPPORTED: c++98, c++03, c++11
+// <numeric>
+
+#include <experimental/numeric>
+
+int main () {}
Index: test/std/experimental/numeric/numeric.ops/numeric.ops.lcm/lcm.pass.cpp
===================================================================
--- test/std/experimental/numeric/numeric.ops/numeric.ops.lcm/lcm.pass.cpp
+++ test/std/experimental/numeric/numeric.ops/numeric.ops.lcm/lcm.pass.cpp
@@ -0,0 +1,260 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// 
+// UNSUPPORTED: c++98, c++03, c++11
+// <numeric>
+
+// template<class _M, class _N>
+// constexpr common_type_t<_M,_N> gcd(_M __m, _N __n)
+
+#include <experimental/numeric>
+#include <cassert>
+#include <iostream>
+
+template <typename Input1, typename Input2, typename Output>
+void test0(Input1 in1, Input2 in2, Output out)
+{
+    static_assert((std::is_same<Output, decltype(std::experimental::lcm(Input1(0), Input2(0)))>::value), "" );
+    static_assert((std::is_same<Output, decltype(std::experimental::lcm(Input2(0), Input1(0)))>::value), "" );
+    assert(out == std::experimental::lcm(in1, in2));
+    assert(out == std::experimental::lcm(in2, in1));
+}
+
+
+template <typename Input>
+void test_same_signed()
+{
+    static_assert(( std::is_signed<Input>::value), "" );
+
+//  Returns: zero when either m or n is zero.
+    test0<Input, Input, Input>( 0,  0,  0);
+    test0<Input, Input, Input>( 1,  0,  0);
+    test0<Input, Input, Input>( 0,  1,  0);
+    test0<Input, Input, Input>(-1,  0,  0);
+    test0<Input, Input, Input>( 0, -1,  0);
+
+//  Otherwise, returns the least common multiple of |m| and |n|.
+    test0<Input, Input, Input>(  1,   1,  1);
+    test0<Input, Input, Input>(  2,   3,  6);
+    test0<Input, Input, Input>(  2,   4,  4);
+    test0<Input, Input, Input>(  3,  17, 51);
+    test0<Input, Input, Input>( 36,  18, 36);
+    
+    test0<Input, Input, Input>( -1,   1,  1);
+    test0<Input, Input, Input>( -2,   3,  6);
+    test0<Input, Input, Input>( -2,   4,  4);
+    test0<Input, Input, Input>( -3,  17, 51);
+    test0<Input, Input, Input>(-36,  18, 36);
+
+    test0<Input, Input, Input>(  1,  -1,  1);
+    test0<Input, Input, Input>(  2,  -3,  6);
+    test0<Input, Input, Input>(  2,  -4,  4);
+    test0<Input, Input, Input>(  3, -17, 51);
+    test0<Input, Input, Input>( 36, -18, 36);
+    
+    test0<Input, Input, Input>( -1,  -1,  1);
+    test0<Input, Input, Input>( -2,  -3,  6);
+    test0<Input, Input, Input>( -2,  -4,  4);
+    test0<Input, Input, Input>( -3, -17, 51);
+    test0<Input, Input, Input>(-36, -18, 36);
+}
+
+template <typename Input>
+void test_same_unsigned()
+{
+    static_assert((!std::is_signed<Input>::value), "" );
+
+//  Returns: zero when either m or n is zero.
+    test0<Input, Input, Input>( 0,  0,  0);
+    test0<Input, Input, Input>( 1,  0,  0);
+    test0<Input, Input, Input>( 0,  1,  0);
+
+//  Otherwise, returns the least common multiple of |m| and |n|.
+    test0<Input, Input, Input>(  1,   1,  1);
+    test0<Input, Input, Input>(  2,   3,  6);
+    test0<Input, Input, Input>(  2,   4,  4);
+    test0<Input, Input, Input>(  3,  17, 51);
+    test0<Input, Input, Input>( 36,  18, 36);
+}
+
+
+template <typename Input1, typename Input2, typename Output>
+void test_different_signed()
+{
+    static_assert(( std::is_signed<Input1>::value), "" );
+    static_assert(( std::is_signed<Input2>::value), "" );
+
+//  Returns: zero when either m or n is zero.
+    test0<Input1, Input2, Output>( 0,  0,  0);
+    test0<Input1, Input2, Output>( 1,  0,  0);
+    test0<Input1, Input2, Output>( 0,  1,  0);
+    test0<Input1, Input2, Output>(-1,  0,  0);
+    test0<Input1, Input2, Output>( 0, -1,  0);
+
+//  Otherwise, returns the least common multiple of |m| and |n|.
+    test0<Input1, Input2, Output>(  1,   1,  1);
+    test0<Input1, Input2, Output>(  2,   3,  6);
+    test0<Input1, Input2, Output>(  2,   4,  4);
+    test0<Input1, Input2, Output>(  3,  17, 51);
+    test0<Input1, Input2, Output>( 36,  18, 36);
+
+    test0<Input1, Input2, Output>( -1,   1,  1);
+    test0<Input1, Input2, Output>( -2,   3,  6);
+    test0<Input1, Input2, Output>( -2,   4,  4);
+    test0<Input1, Input2, Output>( -3,  17, 51);
+    test0<Input1, Input2, Output>(-36,  18, 36);
+    
+    test0<Input1, Input2, Output>(  1,  -1,  1);
+    test0<Input1, Input2, Output>(  2,  -3,  6);
+    test0<Input1, Input2, Output>(  2,  -4,  4);
+    test0<Input1, Input2, Output>(  3, -17, 51);
+    test0<Input1, Input2, Output>( 36, -18, 36);
+
+    test0<Input1, Input2, Output>( -1,  -1,  1);
+    test0<Input1, Input2, Output>( -2,  -3,  6);
+    test0<Input1, Input2, Output>( -2,  -4,  4);
+    test0<Input1, Input2, Output>( -3, -17, 51);
+    test0<Input1, Input2, Output>(-36, -18, 36);
+}
+
+template <typename Input1, typename Input2, typename Output>
+void test_different_unsigned()
+{
+    static_assert((!std::is_signed<Input1>::value), "" );
+    static_assert((!std::is_signed<Input2>::value), "" );
+
+//  Returns: zero when either m or n is zero.
+    test0<Input1, Input2, Output>( 0,  0,  0);
+    test0<Input1, Input2, Output>( 1,  0,  0);
+    test0<Input1, Input2, Output>( 0,  1,  0);
+
+//  Otherwise, returns the least common multiple of |m| and |n|.
+    test0<Input1, Input2, Output>(  1,   1,  1);
+    test0<Input1, Input2, Output>(  2,   3,  6);
+    test0<Input1, Input2, Output>(  2,   4,  4);
+    test0<Input1, Input2, Output>(  3,  17, 51);
+    test0<Input1, Input2, Output>( 36,  18, 36);
+}
+
+template <typename Input1, typename Input2, typename Output>
+void test_mixed_first_signed()
+{
+    static_assert(( std::is_signed<Input1>::value), "" );
+    static_assert((!std::is_signed<Input2>::value), "" );
+
+//  Returns: zero when either m or n is zero.
+    test0<Input1, Input2, Output>( 0,  0,  0);
+    test0<Input1, Input2, Output>( 1,  0,  0);
+    test0<Input1, Input2, Output>(-1,  0,  0);
+    test0<Input1, Input2, Output>( 0,  1,  0);
+
+//  Otherwise, returns the least common multiple of |m| and |n|.
+    test0<Input1, Input2, Output>(  1,   1,  1);
+    test0<Input1, Input2, Output>(  2,   3,  6);
+    test0<Input1, Input2, Output>(  2,   4,  4);
+    test0<Input1, Input2, Output>(  3,  17, 51);
+    test0<Input1, Input2, Output>( 36,  18, 36);
+
+    test0<Input1, Input2, Output>( -1,   1,  1);
+    test0<Input1, Input2, Output>( -2,   3,  6);
+    test0<Input1, Input2, Output>( -2,   4,  4);
+    test0<Input1, Input2, Output>( -3,  17, 51);
+    test0<Input1, Input2, Output>(-36,  18, 36);
+}
+
+template <typename Input1, typename Input2, typename Output>
+void test_mixed_second_signed()
+{
+    static_assert((!std::is_signed<Input1>::value), "" );
+    static_assert(( std::is_signed<Input2>::value), "" );
+
+//  Returns: zero when either m or n is zero.
+    test0<Input1, Input2, Output>( 0,  0,  0);
+    test0<Input1, Input2, Output>( 1,  0,  0);
+    test0<Input1, Input2, Output>( 0,  1,  0);
+    test0<Input1, Input2, Output>( 0, -1,  0);
+
+//  Otherwise, returns the least common multiple of |m| and |n|.
+    test0<Input1, Input2, Output>(  1,   1,  1);
+    test0<Input1, Input2, Output>(  2,   3,  6);
+    test0<Input1, Input2, Output>(  2,   4,  4);
+    test0<Input1, Input2, Output>(  3,  17, 51);
+    test0<Input1, Input2, Output>( 36,  18, 36);
+
+//  Otherwise, returns the least common multiple of |m| and |n|.
+    test0<Input1, Input2, Output>(  1,  -1,  1);
+    test0<Input1, Input2, Output>(  2,  -3,  6);
+    test0<Input1, Input2, Output>(  2,  -4,  4);
+    test0<Input1, Input2, Output>(  3, -17, 51);
+    test0<Input1, Input2, Output>( 36, -18, 36);
+}
+
+int main()
+{
+    test_same_signed<signed char>();
+    test_same_signed<short>();
+    test_same_signed<int>();
+    test_same_signed<long>();
+    test_same_signed<long long>();
+
+    test_same_signed< int8_t>();
+    test_same_signed<int16_t>();
+    test_same_signed<int32_t>();
+    test_same_signed<int64_t>();
+
+    test_same_unsigned<unsigned char>();
+    test_same_unsigned<unsigned short>();
+    test_same_unsigned<unsigned int>();
+    test_same_unsigned<unsigned long>();
+    test_same_unsigned<unsigned long long>();
+    test_same_unsigned<std::size_t>();
+
+    test_same_unsigned< uint8_t>();
+    test_same_unsigned<uint16_t>();
+    test_same_unsigned<uint32_t>();
+    test_same_unsigned<uint64_t>();
+    
+    test_different_signed<signed char, int, int>();
+    test_different_signed<int, signed char, int>();
+    test_different_signed<short, int, int>();
+    test_different_signed<int, short, int>();
+    test_different_signed<int, long, long>();
+    test_different_signed<long, int, long>();
+    test_different_signed<int, long long, long long>();
+    test_different_signed<long long, int, long long>();
+    
+    test_different_unsigned<unsigned char, unsigned int, unsigned int>();
+    test_different_unsigned<unsigned int, unsigned char, unsigned int>();
+    test_different_unsigned<unsigned short, unsigned int, unsigned int>();
+    test_different_unsigned<unsigned int, unsigned short, unsigned int>();
+    test_different_unsigned<unsigned int, unsigned long, unsigned long>();
+    test_different_unsigned<unsigned long, unsigned int, unsigned long>();
+    test_different_unsigned<unsigned int, unsigned long long, unsigned long long>();
+    test_different_unsigned<unsigned long long, unsigned int, unsigned long long>();
+
+    test_mixed_first_signed<signed char, unsigned char, int>();
+    test_mixed_first_signed<int, unsigned char, int>();
+    test_mixed_first_signed<int, unsigned int, unsigned int>();
+    test_mixed_first_signed<long, unsigned int, long>();
+    test_mixed_first_signed<long long, unsigned int, long long>();
+    test_mixed_first_signed<long long, unsigned long, unsigned long long>();
+
+    test_mixed_second_signed<unsigned char, signed char, int>();
+    test_mixed_second_signed<unsigned char, int, int>();
+    test_mixed_second_signed<unsigned int, int, unsigned int>();
+    test_mixed_second_signed<unsigned int, long, long>();
+    test_mixed_second_signed<unsigned int, long long, long long>();
+    test_mixed_second_signed<unsigned long, long long, unsigned long long>();
+
+//	Weirdness with bool
+	test0<bool, signed char, int>(false, 'A', 0);
+	test0<bool, signed char, int>(true, 'B', 'B');
+	test0<bool, int, int>(false, 3, 0);
+	test0<bool, int, int>(true, 3, 3);
+}
Index: test/std/experimental/numeric/numeric.ops/numeric.ops.lcm/lcm.not_integral2.fail.cpp
===================================================================
--- test/std/experimental/numeric/numeric.ops/numeric.ops.lcm/lcm.not_integral2.fail.cpp
+++ test/std/experimental/numeric/numeric.ops/numeric.ops.lcm/lcm.not_integral2.fail.cpp
@@ -0,0 +1,24 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// 
+// UNSUPPORTED: c++98, c++03, c++11
+// <numeric>
+
+// template<class _M, class _N>
+// constexpr common_type_t<_M,_N> lcm(_M __m, _N __n)
+
+// Remarks: If either M or N is not an integer type, the program is ill-formed.
+
+#include <experimental/numeric>
+
+
+int main()
+{
+    std::experimental::lcm(4, 6.0);
+}
Index: test/std/experimental/numeric/numeric.ops/numeric.ops.lcm/lcm.not_integral1.fail.cpp
===================================================================
--- test/std/experimental/numeric/numeric.ops/numeric.ops.lcm/lcm.not_integral1.fail.cpp
+++ test/std/experimental/numeric/numeric.ops/numeric.ops.lcm/lcm.not_integral1.fail.cpp
@@ -0,0 +1,24 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// UNSUPPORTED: c++98, c++03, c++11
+// <numeric>
+
+// template<class _M, class _N>
+// constexpr common_type_t<_M,_N> lcm(_M __m, _N __n)
+
+// Remarks: If either M or N is not an integer type, the program is ill-formed.
+
+#include <experimental/numeric>
+
+
+int main()
+{
+    std::experimental::lcm(2.0, 4);
+}
Index: test/std/experimental/numeric/numeric.ops/numeric.ops.gcd/gcd.pass.cpp
===================================================================
--- test/std/experimental/numeric/numeric.ops/numeric.ops.gcd/gcd.pass.cpp
+++ test/std/experimental/numeric/numeric.ops/numeric.ops.gcd/gcd.pass.cpp
@@ -0,0 +1,261 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// 
+// UNSUPPORTED: c++98, c++03, c++11
+// <numeric>
+
+// template<class _M, class _N>
+// constexpr common_type_t<_M,_N> gcd(_M __m, _N __n)
+
+#include <experimental/numeric>
+#include <cassert>
+#include <iostream>
+
+template <typename Input1, typename Input2, typename Output>
+constexpr void test0(const Input1 &in1, const Input2 &in2, const Output &out)
+{
+    static_assert((std::is_same<Output, decltype(std::experimental::gcd(in1, in2))>::value), "" );
+    static_assert((std::is_same<Output, decltype(std::experimental::gcd(in2, in1))>::value), "" );
+    assert(out == std::experimental::gcd(in1, in2));
+    assert(out == std::experimental::gcd(in2, in1));
+//     static_assert((0 <= std::experimental::gcd(in1, in2)), "");
+//     static_assert((0 <= std::experimental::gcd(in2, in1)), "");
+}
+
+
+template <typename Input>
+constexpr void test_same_signed()
+{
+    static_assert(( std::is_signed<Input>::value), "" );
+
+//  Returns: zero when m and n are both zero.
+    test0<Input, Input, Input>( 0,  0,  0);
+    test0<Input, Input, Input>( 1,  0,  1);
+    test0<Input, Input, Input>( 0,  1,  1);
+    test0<Input, Input, Input>(-1,  0,  1);
+    test0<Input, Input, Input>( 0, -1,  1);
+
+//  Otherwise, returns the greatest common divisor of |m| and |n|.
+    test0<Input, Input, Input>(  1,   1,  1);
+    test0<Input, Input, Input>(  2,   3,  1);  // relatively prime
+    test0<Input, Input, Input>(  2,   4,  2);
+    test0<Input, Input, Input>( 36,  17,  1);  // relatively prime
+    test0<Input, Input, Input>( 36,  18, 18);
+    
+    test0<Input, Input, Input>( -1,   1,  1);
+    test0<Input, Input, Input>( -2,   3,  1);
+    test0<Input, Input, Input>( -2,   4,  2);
+    test0<Input, Input, Input>(-36,  17,  1);
+    test0<Input, Input, Input>(-36,  18, 18);
+
+    test0<Input, Input, Input>(  1,  -1,  1);
+    test0<Input, Input, Input>(  2,  -3,  1);
+    test0<Input, Input, Input>(  2,  -4,  2);
+    test0<Input, Input, Input>( 36, -17,  1);
+    test0<Input, Input, Input>( 36, -18, 18);
+
+    test0<Input, Input, Input>( -1,  -1,  1);
+    test0<Input, Input, Input>( -2,  -3,  1);
+    test0<Input, Input, Input>( -2,  -4,  2);
+    test0<Input, Input, Input>(-36, -17,  1);
+    test0<Input, Input, Input>(-36, -18, 18);
+}
+
+template <typename Input>
+constexpr void test_same_unsigned()
+{
+    static_assert((!std::is_signed<Input>::value), "" );
+
+//  Returns: zero when m and n are both zero.
+    test0<Input, Input, Input>( 0,  0,  0);
+    test0<Input, Input, Input>( 1,  0,  1);
+    test0<Input, Input, Input>( 0,  1,  1);
+
+//  Otherwise, returns the greatest common divisor of |m| and |n|.
+    test0<Input, Input, Input>(  1,   1,  1);
+    test0<Input, Input, Input>(  2,   3,  1);  // relatively prime
+    test0<Input, Input, Input>(  2,   4,  2);
+    test0<Input, Input, Input>( 36,  17,  1);  // relatively prime
+    test0<Input, Input, Input>( 36,  18, 18);
+}
+
+
+template <typename Input1, typename Input2, typename Output>
+constexpr void test_different_signed()
+{
+    static_assert(( std::is_signed<Input1>::value), "" );
+    static_assert(( std::is_signed<Input2>::value), "" );
+
+//  Returns: zero when m and n are both zero.
+    test0<Input1, Input2, Output>( 0,  0,  0);
+    test0<Input1, Input2, Output>( 1,  0,  1);
+    test0<Input1, Input2, Output>( 0,  1,  1);
+    test0<Input1, Input2, Output>(-1,  0,  1);
+    test0<Input1, Input2, Output>( 0, -1,  1);
+
+//  Otherwise, returns the greatest common divisor of |m| and |n|.
+    test0<Input1, Input2, Output>(  1,   1,  1);
+    test0<Input1, Input2, Output>(  2,   3,  1);  // relatively prime
+    test0<Input1, Input2, Output>(  2,   4,  2);
+    test0<Input1, Input2, Output>( 36,  17,  1);  // relatively prime
+    test0<Input1, Input2, Output>( 36,  18, 18);
+    
+    test0<Input1, Input2, Output>( -1,   1,  1);
+    test0<Input1, Input2, Output>( -2,   3,  1);
+    test0<Input1, Input2, Output>( -2,   4,  2);
+    test0<Input1, Input2, Output>(-36,  17,  1);
+    test0<Input1, Input2, Output>(-36,  18, 18);
+
+    test0<Input1, Input2, Output>(  1,  -1,  1);
+    test0<Input1, Input2, Output>(  2,  -3,  1);
+    test0<Input1, Input2, Output>(  2,  -4,  2);
+    test0<Input1, Input2, Output>( 36, -17,  1);
+    test0<Input1, Input2, Output>( 36, -18, 18);
+
+    test0<Input1, Input2, Output>( -1,  -1,  1);
+    test0<Input1, Input2, Output>( -2,  -3,  1);
+    test0<Input1, Input2, Output>( -2,  -4,  2);
+    test0<Input1, Input2, Output>(-36, -17,  1);
+    test0<Input1, Input2, Output>(-36, -18, 18);
+}
+
+template <typename Input1, typename Input2, typename Output>
+constexpr void test_different_unsigned()
+{
+    static_assert((!std::is_signed<Input1>::value), "" );
+    static_assert((!std::is_signed<Input2>::value), "" );
+
+//  Returns: zero when m and n are both zero.
+    test0<Input1, Input2, Output>( 0,  0,  0);
+    test0<Input1, Input2, Output>( 1,  0,  1);
+    test0<Input1, Input2, Output>( 0,  1,  1);
+
+//  Otherwise, returns the greatest common divisor of |m| and |n|.
+    test0<Input1, Input2, Output>(  1,   1,  1);
+    test0<Input1, Input2, Output>(  2,   3,  1);  // relatively prime
+    test0<Input1, Input2, Output>(  2,   4,  2);
+    test0<Input1, Input2, Output>( 36,  17,  1);  // relatively prime
+    test0<Input1, Input2, Output>( 36,  18, 18);
+}
+
+template <typename Input1, typename Input2, typename Output>
+constexpr void test_mixed_first_signed()
+{
+    static_assert(( std::is_signed<Input1>::value), "" );
+    static_assert((!std::is_signed<Input2>::value), "" );
+
+//  Returns: zero when m and n are both zero.
+    test0<Input1, Input2, Output>( 0,  0,  0);
+    test0<Input1, Input2, Output>( 1,  0,  1);
+    test0<Input1, Input2, Output>( 0,  1,  1);
+
+//  Otherwise, returns the greatest common divisor of |m| and |n|.
+    test0<Input1, Input2, Output>(  1,   1,  1);
+    test0<Input1, Input2, Output>(  2,   3,  1);  // relatively prime
+    test0<Input1, Input2, Output>(  2,   4,  2);
+    test0<Input1, Input2, Output>( 36,  17,  1);  // relatively prime
+    test0<Input1, Input2, Output>( 36,  18, 18);
+
+//  Otherwise, returns the greatest common divisor of |m| and |n|.
+    test0<Input1, Input2, Output>( -1,   1,  1);
+    test0<Input1, Input2, Output>( -2,   3,  1);  // relatively prime
+    test0<Input1, Input2, Output>( -2,   4,  2);
+    test0<Input1, Input2, Output>(-36,  17,  1);  // relatively prime
+    test0<Input1, Input2, Output>(-36,  18, 18);
+}
+
+template <typename Input1, typename Input2, typename Output>
+constexpr void test_mixed_second_signed()
+{
+    static_assert((!std::is_signed<Input1>::value), "" );
+    static_assert(( std::is_signed<Input2>::value), "" );
+
+//  Returns: zero when m and n are both zero.
+    test0<Input1, Input2, Output>( 0,  0,  0);
+    test0<Input1, Input2, Output>( 1,  0,  1);
+    test0<Input1, Input2, Output>( 0,  1,  1);
+
+//  Otherwise, returns the greatest common divisor of |m| and |n|.
+    test0<Input1, Input2, Output>(  1,   1,  1);
+    test0<Input1, Input2, Output>(  2,   3,  1);  // relatively prime
+    test0<Input1, Input2, Output>(  2,   4,  2);
+    test0<Input1, Input2, Output>( 36,  17,  1);  // relatively prime
+    test0<Input1, Input2, Output>( 36,  18, 18);
+
+//  Otherwise, returns the greatest common divisor of |m| and |n|.
+    test0<Input1, Input2, Output>(  1,  -1,  1);
+    test0<Input1, Input2, Output>(  2,  -3,  1);  // relatively prime
+    test0<Input1, Input2, Output>(  2,  -4,  2);
+    test0<Input1, Input2, Output>( 36, -17,  1);  // relatively prime
+    test0<Input1, Input2, Output>( 36, -18, 18);
+}
+
+int main()
+{
+    test_same_signed<signed char>();
+    test_same_signed<short>();
+    test_same_signed<int>();
+    test_same_signed<long>();
+    test_same_signed<long long>();
+
+    test_same_signed< int8_t>();
+    test_same_signed<int16_t>();
+    test_same_signed<int32_t>();
+    test_same_signed<int64_t>();
+
+    test_same_unsigned<unsigned char>();
+    test_same_unsigned<unsigned short>();
+    test_same_unsigned<unsigned int>();
+    test_same_unsigned<unsigned long>();
+    test_same_unsigned<unsigned long long>();
+    test_same_unsigned<std::size_t>();
+
+    test_same_unsigned< uint8_t>();
+    test_same_unsigned<uint16_t>();
+    test_same_unsigned<uint32_t>();
+    test_same_unsigned<uint64_t>();
+    
+    test_different_signed<signed char, int, int>();
+    test_different_signed<int, signed char, int>();
+    test_different_signed<short, int, int>();
+    test_different_signed<int, short, int>();
+    test_different_signed<int, long, long>();
+    test_different_signed<long, int, long>();
+    test_different_signed<int, long long, long long>();
+    test_different_signed<long long, int, long long>();
+    
+    test_different_unsigned<unsigned char, unsigned int, unsigned int>();
+    test_different_unsigned<unsigned int, unsigned char, unsigned int>();
+    test_different_unsigned<unsigned short, unsigned int, unsigned int>();
+    test_different_unsigned<unsigned int, unsigned short, unsigned int>();
+    test_different_unsigned<unsigned int, unsigned long, unsigned long>();
+    test_different_unsigned<unsigned long, unsigned int, unsigned long>();
+    test_different_unsigned<unsigned int, unsigned long long, unsigned long long>();
+    test_different_unsigned<unsigned long long, unsigned int, unsigned long long>();
+
+    test_mixed_first_signed<signed char, unsigned char, int>();
+    test_mixed_first_signed<int, unsigned char, int>();
+    test_mixed_first_signed<int, unsigned int, unsigned int>();
+    test_mixed_first_signed<long, unsigned int, long>();
+    test_mixed_first_signed<long long, unsigned int, long long>();
+    test_mixed_first_signed<long long, unsigned long, unsigned long long>();
+
+    test_mixed_second_signed<unsigned char, signed char, int>();
+    test_mixed_second_signed<unsigned char, int, int>();
+    test_mixed_second_signed<unsigned int, int, unsigned int>();
+    test_mixed_second_signed<unsigned int, long, long>();
+    test_mixed_second_signed<unsigned int, long long, long long>();
+    test_mixed_second_signed<unsigned long, long long, unsigned long long>();
+
+//	Weirdness with bool
+	test0<bool, signed char, int>(false, 'A', 'A');
+	test0<bool, signed char, int>(true, 'B', 1);
+	test0<bool, int, int>(false, 3, 3);
+	test0<bool, int, int>(true, 3, 1);
+}
Index: test/std/experimental/numeric/numeric.ops/numeric.ops.gcd/gcd.not_integral2.fail.cpp
===================================================================
--- test/std/experimental/numeric/numeric.ops/numeric.ops.gcd/gcd.not_integral2.fail.cpp
+++ test/std/experimental/numeric/numeric.ops/numeric.ops.gcd/gcd.not_integral2.fail.cpp
@@ -0,0 +1,24 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// 
+// UNSUPPORTED: c++98, c++03, c++11
+// <numeric>
+
+// template<class _M, class _N>
+// constexpr common_type_t<_M,_N> gcd(_M __m, _N __n)
+
+// Remarks: If either M or N is not an integer type, the program is ill-formed.
+
+#include <experimental/numeric>
+
+
+int main()
+{
+    std::experimental::gcd(4, 6.0);
+}
Index: test/std/experimental/numeric/numeric.ops/numeric.ops.gcd/gcd.not_integral1.fail.cpp
===================================================================
--- test/std/experimental/numeric/numeric.ops/numeric.ops.gcd/gcd.not_integral1.fail.cpp
+++ test/std/experimental/numeric/numeric.ops/numeric.ops.gcd/gcd.not_integral1.fail.cpp
@@ -0,0 +1,24 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// 
+// UNSUPPORTED: c++98, c++03, c++11
+// <numeric>
+
+// template<class _M, class _N>
+// constexpr common_type_t<_M,_N> gcd(_M __m, _N __n)
+
+// Remarks: If either M or N is not an integer type, the program is ill-formed.
+
+#include <experimental/numeric>
+
+
+int main()
+{
+    std::experimental::gcd(2.0, 4);
+}
Index: test/std/experimental/numeric/numeric.ops/nothing_to_do.pass.cpp
===================================================================
--- test/std/experimental/numeric/numeric.ops/nothing_to_do.pass.cpp
+++ test/std/experimental/numeric/numeric.ops/nothing_to_do.pass.cpp
@@ -0,0 +1,15 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// UNSUPPORTED: c++98, c++03, c++11
+// <numeric>
+
+#include <experimental/numeric>
+
+int main () {}
Index: include/experimental/numeric
===================================================================
--- include/experimental/numeric
+++ include/experimental/numeric
@@ -0,0 +1,100 @@
+// -*- C++ -*-
+//===--------------------------- numeric ----------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP_EXPERIMENTAL_NUMERIC
+#define _LIBCPP_EXPERIMENTAL_NUMERIC
+/*
+    experimental/numeric synopsis
+
+// C++1z
+namespace std {
+namespace experimental {
+inline namespace fundamentals_v2 {
+
+  // 13.1.2, Greatest common divisor
+  template<class M, class N>
+  constexpr common_type_t<M,N> gcd(M m, N n);
+
+  // 13.1.3, Least common multiple
+  template<class M, class N>
+  constexpr common_type_t<M,N> lcm(M m, N n);
+
+} // namespace fundamentals_v2
+} // namespace experimental
+} // namespace std
+
+ */
+
+#include <experimental/__config>
+#include <numeric>
+#include <type_traits>              // is_integral
+#include <limits>                   // numeric_limits
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_LFTS
+
+template <typename _Tp, bool _IsSigned = is_signed<_Tp>::value> struct __abs;
+
+template <typename _Tp>
+struct __abs<_Tp, true> {
+    _LIBCPP_CONSTEXPR _LIBCPP_INLINE_VISIBILITY
+    _Tp operator()(_Tp __t) const noexcept { return __t >= 0 ? __t : -__t; }
+};
+
+template <typename _Tp>
+struct __abs<_Tp, false> {
+    _LIBCPP_CONSTEXPR _LIBCPP_INLINE_VISIBILITY
+    _Tp operator()(_Tp __t) const noexcept { return __t; }
+};
+
+
+template<class _Tp>
+_LIBCPP_CONSTEXPR _LIBCPP_INLINE_VISIBILITY
+_Tp __gcd(_Tp __m, _Tp __n)
+{
+    static_assert((!is_signed<_Tp>::value), "" );
+    return __n == 0 ? __m : __gcd<_Tp>(__n, __m % __n);
+}
+
+
+template<class _Tp, class _Up>
+_LIBCPP_CONSTEXPR _LIBCPP_INLINE_VISIBILITY
+common_type_t<_Tp,_Up>
+gcd(_Tp __m, _Up __n)
+{
+    static_assert((is_integral<_Tp>::value && is_integral<_Up>::value), "Arguments to gcd must be integer types");
+    using _Rp = common_type_t<_Tp,_Up>;
+    using _Wp = make_unsigned_t<_Rp>;
+    return static_cast<_Rp>(__gcd(static_cast<_Wp>(__abs<_Tp>()(__m)),
+                                  static_cast<_Wp>(__abs<_Up>()(__n))));
+}
+
+template<class _Tp, class _Up>
+_LIBCPP_CONSTEXPR _LIBCPP_INLINE_VISIBILITY
+common_type_t<_Tp,_Up>
+lcm(_Tp __m, _Up __n)
+{
+    static_assert((is_integral<_Tp>::value && is_integral<_Up>::value), "Arguments to lcm must be integer types");
+    if (__m == 0 || __n == 0)
+        return 0;
+
+    using _Rp = common_type_t<_Tp,_Up>;
+    _Rp __val1 = __abs<_Tp>()(__m) / gcd(__m,__n);
+    _Up __val2 = __abs<_Up>()(__n);
+    _LIBCPP_ASSERT((numeric_limits<_Rp>::max() / __val1 > __val2), "Overflow in lcm");
+    return __val1 * __val2;
+}
+
+_LIBCPP_END_NAMESPACE_LFTS
+
+#endif /* _LIBCPP_EXPERIMENTAL_MAP */
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to