[libcxx-commits] [libcxx] r356162 - Add std::midpoint for integral and poiner types. Described in P0811, reviewed as D59099.

Marshall Clow via libcxx-commits libcxx-commits at lists.llvm.org
Thu Mar 14 09:25:56 PDT 2019


Author: marshall
Date: Thu Mar 14 09:25:55 2019
New Revision: 356162

URL: http://llvm.org/viewvc/llvm-project?rev=356162&view=rev
Log:
Add std::midpoint for integral and poiner types. Described in P0811, reviewed as D59099.

Added:
    libcxx/trunk/test/libcxx/numerics/numeric.ops/midpoint.integer.pass.cpp
    libcxx/trunk/test/std/numerics/numeric.ops/numeric.ops.midpoint/
    libcxx/trunk/test/std/numerics/numeric.ops/numeric.ops.midpoint/midpoint.fail.cpp
    libcxx/trunk/test/std/numerics/numeric.ops/numeric.ops.midpoint/midpoint.integer.pass.cpp
    libcxx/trunk/test/std/numerics/numeric.ops/numeric.ops.midpoint/midpoint.pointer.pass.cpp
Modified:
    libcxx/trunk/include/numeric

Modified: libcxx/trunk/include/numeric
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/numeric?rev=356162&r1=356161&r2=356162&view=diff
==============================================================================
--- libcxx/trunk/include/numeric (original)
+++ libcxx/trunk/include/numeric Thu Mar 14 09:25:55 2019
@@ -133,6 +133,10 @@ template <class M, class N>
 template <class M, class N>
     constexpr common_type_t<M,N> lcm(M m, N n);    // C++17
 
+integer         midpoint(integer a, integer b);                  // C++20
+pointer         midpoint(pointer a, pointer b);                  // C++20
+floating_point  midpoint(floating_point a, floating_point b);    // C++20
+
 }  // std
 
 */
@@ -519,6 +523,37 @@ lcm(_Tp __m, _Up __n)
 
 #endif /* _LIBCPP_STD_VER > 14 */
 
+#if _LIBCPP_STD_VER > 17
+template <class _Tp>
+_LIBCPP_INLINE_VISIBILITY constexpr
+enable_if_t<is_integral_v<_Tp> && !is_same_v<bool, _Tp>, _Tp>
+midpoint(_Tp __a, _Tp __b) noexcept
+_LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK
+{
+    using _Up = std::make_unsigned_t<_Tp>;
+
+    int __sign = 1;
+    _Up __m = __a;
+    _Up __M = __b;
+    if (__a > __b)
+    {
+        __sign = -1;
+        __m = __b;
+        __M = __a;
+    }
+     return __a + __sign * _Tp(_Up(__M-__m) >> 1);
+}
+
+
+template <class _TPtr>
+_LIBCPP_INLINE_VISIBILITY constexpr
+enable_if_t<is_pointer_v<_TPtr>, _TPtr>
+midpoint(_TPtr __a, _TPtr __b) noexcept
+{
+    return __a + _VSTD::midpoint(ptrdiff_t(0), __b - __a);
+}
+#endif
+
 _LIBCPP_END_NAMESPACE_STD
 
 _LIBCPP_POP_MACROS

Added: libcxx/trunk/test/libcxx/numerics/numeric.ops/midpoint.integer.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/numerics/numeric.ops/midpoint.integer.pass.cpp?rev=356162&view=auto
==============================================================================
--- libcxx/trunk/test/libcxx/numerics/numeric.ops/midpoint.integer.pass.cpp (added)
+++ libcxx/trunk/test/libcxx/numerics/numeric.ops/midpoint.integer.pass.cpp Thu Mar 14 09:25:55 2019
@@ -0,0 +1,63 @@
+//===----------------------------------------------------------------------===//
+//
+// 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++98, c++03, c++11, c++14, c++17
+// <numeric>
+
+// template <class _Tp>
+// _Tp midpoint(_Tp __a, _Tp __b) noexcept
+//
+
+#include <numeric>
+#include <cassert>
+#include "test_macros.h"
+
+//  Users are not supposed to provide template argument lists for 
+//  functions in the standard library (there's an exception for min and max)
+//  However, libc++ protects against this for pointers, so we check to make
+//  sure that our protection is working here.
+//  In some cases midpoint<int>(0,0) might get deduced as the pointer overload.
+
+template <typename T>
+void test()
+{
+    ASSERT_SAME_TYPE(T, decltype(std::midpoint<T>(0, 0)));
+}
+
+int main(int, char**)
+{
+    test<signed char>();
+    test<short>();
+    test<int>();
+    test<long>();
+    test<long long>();
+
+    test<int8_t>();
+    test<int16_t>();
+    test<int32_t>();
+    test<int64_t>();
+    test<__int128_t>();
+
+    test<unsigned char>();
+    test<unsigned short>();
+    test<unsigned int>();
+    test<unsigned long>();
+    test<unsigned long long>();
+
+    test<uint8_t>();
+    test<uint16_t>();
+    test<uint32_t>();
+    test<uint64_t>();
+    test<__uint128_t>();
+
+    test<char>();
+    test<ptrdiff_t>();
+    test<size_t>();
+
+    return 0;
+}

Added: libcxx/trunk/test/std/numerics/numeric.ops/numeric.ops.midpoint/midpoint.fail.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/numerics/numeric.ops/numeric.ops.midpoint/midpoint.fail.cpp?rev=356162&view=auto
==============================================================================
--- libcxx/trunk/test/std/numerics/numeric.ops/numeric.ops.midpoint/midpoint.fail.cpp (added)
+++ libcxx/trunk/test/std/numerics/numeric.ops/numeric.ops.midpoint/midpoint.fail.cpp Thu Mar 14 09:25:55 2019
@@ -0,0 +1,30 @@
+//===----------------------------------------------------------------------===//
+//
+// 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++98, c++03, c++11, c++14, c++17
+// <numeric>
+
+// template <class _Tp>
+// _Tp midpoint(_Tp __a, _Tp __b) noexcept
+
+// An overload exists for each of char and all arithmetic types except bool.
+
+#include <numeric>
+
+#include "test_macros.h"
+
+int main(int, char**)
+{
+    (void) std::midpoint(false, true); // expected-error {{no matching function for call to 'midpoint'}}
+
+//  A couple of odd pointer types that should fail
+    (void) std::midpoint(nullptr, nullptr);     // expected-error {{no matching function for call to 'midpoint'}}
+    (void) std::midpoint((void *)0, (void *)0); // expected-error at numeric:* {{arithmetic on pointers to void}}
+    
+    return 0;
+}

Added: libcxx/trunk/test/std/numerics/numeric.ops/numeric.ops.midpoint/midpoint.integer.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/numerics/numeric.ops/numeric.ops.midpoint/midpoint.integer.pass.cpp?rev=356162&view=auto
==============================================================================
--- libcxx/trunk/test/std/numerics/numeric.ops/numeric.ops.midpoint/midpoint.integer.pass.cpp (added)
+++ libcxx/trunk/test/std/numerics/numeric.ops/numeric.ops.midpoint/midpoint.integer.pass.cpp Thu Mar 14 09:25:55 2019
@@ -0,0 +1,137 @@
+//===----------------------------------------------------------------------===//
+//
+// 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++98, c++03, c++11, c++14, c++17
+// <numeric>
+
+// template <class _Tp>
+// _Tp midpoint(_Tp __a, _Tp __b) noexcept
+//
+
+#include <numeric>
+#include <cassert>
+#include "test_macros.h"
+
+template <typename T>
+void signed_test()
+{
+    constexpr T zero{0};
+    constexpr T one{1};
+    constexpr T two{2};
+    constexpr T three{3};
+    constexpr T four{4};
+
+    ASSERT_SAME_TYPE(decltype(std::midpoint(T(), T())), T);
+    ASSERT_NOEXCEPT(          std::midpoint(T(), T()));
+    using limits = std::numeric_limits<T>;
+    
+    static_assert(std::midpoint(one, three) == two, "");
+    static_assert(std::midpoint(three, one) == two, "");
+
+    assert(std::midpoint(zero, zero) == zero);
+    assert(std::midpoint(zero, two)  == one);
+    assert(std::midpoint(two, zero)  == one);
+    assert(std::midpoint(two, two)   == two);
+
+    assert(std::midpoint(one, four)    == two);
+    assert(std::midpoint(four, one)    == three);
+    assert(std::midpoint(three, four)  == three);
+    assert(std::midpoint(four, three)  == four);
+
+    assert(std::midpoint(T( 3), T( 4)) == T(3));
+    assert(std::midpoint(T( 4), T( 3)) == T(4));
+    assert(std::midpoint(T(-3), T( 4)) == T(0));
+    assert(std::midpoint(T(-4), T( 3)) == T(-1));
+    assert(std::midpoint(T( 3), T(-4)) == T(0));
+    assert(std::midpoint(T( 4), T(-3)) == T(1));
+    assert(std::midpoint(T(-3), T(-4)) == T(-3));
+    assert(std::midpoint(T(-4), T(-3)) == T(-4));
+    
+    static_assert(std::midpoint(limits::min(), limits::max()) == T(-1), "");
+    static_assert(std::midpoint(limits::max(), limits::min()) == T( 0), "");
+
+    static_assert(std::midpoint(limits::min(), T(6)) == limits::min()/2 + 3, "");
+    assert(       std::midpoint(T(6), limits::min()) == limits::min()/2 + 3);
+    assert(       std::midpoint(limits::max(), T(6)) == limits::max()/2 + 4);
+    static_assert(std::midpoint(T(6), limits::max()) == limits::max()/2 + 3, "");
+
+    assert(       std::midpoint(limits::min(), T(-6)) == limits::min()/2 - 3);
+    static_assert(std::midpoint(T(-6), limits::min()) == limits::min()/2 - 3, "");
+    static_assert(std::midpoint(limits::max(), T(-6)) == limits::max()/2 - 2, "");
+    assert(       std::midpoint(T(-6), limits::max()) == limits::max()/2 - 3);
+}
+
+template <typename T>
+void unsigned_test()
+{
+    constexpr T zero{0};
+    constexpr T one{1};
+    constexpr T two{2};
+    constexpr T three{3};
+    constexpr T four{4};
+
+    ASSERT_SAME_TYPE(decltype(std::midpoint(T(), T())), T);
+    ASSERT_NOEXCEPT(          std::midpoint(T(), T()));
+    using limits = std::numeric_limits<T>;
+    const T half_way = (limits::max() - limits::min())/2;
+    
+    static_assert(std::midpoint(one, three) == two, "");
+    static_assert(std::midpoint(three, one) == two, "");
+
+    assert(std::midpoint(zero, zero) == zero);
+    assert(std::midpoint(zero, two)  == one);
+    assert(std::midpoint(two, zero)  == one);
+    assert(std::midpoint(two, two)   == two);
+
+    assert(std::midpoint(one, four)    == two);
+    assert(std::midpoint(four, one)    == three);
+    assert(std::midpoint(three, four)  == three);
+    assert(std::midpoint(four, three)  == four);
+    
+    assert(std::midpoint(limits::min(), limits::max()) == T(half_way));
+    assert(std::midpoint(limits::max(), limits::min()) == T(half_way + 1));
+
+    static_assert(std::midpoint(limits::min(), T(6)) == limits::min()/2 + 3, "");
+    assert(       std::midpoint(T(6), limits::min()) == limits::min()/2 + 3);
+    assert(       std::midpoint(limits::max(), T(6)) == half_way + 4);
+    static_assert(std::midpoint(T(6), limits::max()) == half_way + 3, "");
+}
+
+
+int main(int, char**)
+{
+    signed_test<signed char>();
+    signed_test<short>();
+    signed_test<int>();
+    signed_test<long>();
+    signed_test<long long>();
+
+    signed_test<int8_t>();
+    signed_test<int16_t>();
+    signed_test<int32_t>();
+    signed_test<int64_t>();
+    signed_test<__int128_t>();
+
+    unsigned_test<unsigned char>();
+    unsigned_test<unsigned short>();
+    unsigned_test<unsigned int>();
+    unsigned_test<unsigned long>();
+    unsigned_test<unsigned long long>();
+
+    unsigned_test<uint8_t>();
+    unsigned_test<uint16_t>();
+    unsigned_test<uint32_t>();
+    unsigned_test<uint64_t>();
+    unsigned_test<__uint128_t>();
+
+//     int_test<char>();
+    signed_test<ptrdiff_t>();
+    unsigned_test<size_t>();
+
+    return 0;
+}

Added: libcxx/trunk/test/std/numerics/numeric.ops/numeric.ops.midpoint/midpoint.pointer.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/numerics/numeric.ops/numeric.ops.midpoint/midpoint.pointer.pass.cpp?rev=356162&view=auto
==============================================================================
--- libcxx/trunk/test/std/numerics/numeric.ops/numeric.ops.midpoint/midpoint.pointer.pass.cpp (added)
+++ libcxx/trunk/test/std/numerics/numeric.ops/numeric.ops.midpoint/midpoint.pointer.pass.cpp Thu Mar 14 09:25:55 2019
@@ -0,0 +1,57 @@
+//===----------------------------------------------------------------------===//
+//
+// 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++98, c++03, c++11, c++14, c++17
+// <numeric>
+
+// template <class _Tp>
+// _Tp* midpoint(_Tp* __a, _Tp* __b) noexcept
+//
+
+#include <numeric>
+#include <cassert>
+
+#include "test_macros.h"
+
+
+
+template <typename T>
+void pointer_test()
+{
+    T array[1000] = {}; // we need an array to make valid pointers
+    constexpr T cArray[2] = {};
+    ASSERT_SAME_TYPE(decltype(std::midpoint(array, array)), T*);
+    ASSERT_NOEXCEPT(          std::midpoint(array, array));
+
+    static_assert(std::midpoint(cArray, cArray + 2) == cArray + 1, "");
+    static_assert(std::midpoint(cArray + 2, cArray) == cArray + 1, "");
+
+    assert(std::midpoint(array, array)        == array);
+    assert(std::midpoint(array, array + 1000) == array + 500);
+
+    assert(std::midpoint(array, array +    9) == array + 4);
+    assert(std::midpoint(array, array +   10) == array + 5);
+    assert(std::midpoint(array, array +   11) == array + 5);
+    assert(std::midpoint(array +    9, array) == array + 5);
+    assert(std::midpoint(array +   10, array) == array + 5);
+    assert(std::midpoint(array +   11, array) == array + 6);
+}
+
+
+int main(int, char**)
+{
+    pointer_test<               char>();
+    pointer_test<const          char>();
+    pointer_test<      volatile char>();
+    pointer_test<const volatile char>();
+    
+    pointer_test<int>();
+    pointer_test<double>();
+
+    return 0;
+}




More information about the libcxx-commits mailing list