Index: libcxx/include/numeric =================================================================== --- libcxx/include/numeric +++ libcxx/include/numeric @@ -133,6 +133,10 @@ template constexpr common_type_t 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 @@ #endif /* _LIBCPP_STD_VER > 14 */ +#if _LIBCPP_STD_VER > 17 +template +_LIBCPP_INLINE_VISIBILITY constexpr +enable_if_t && !is_same_v, _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 +_LIBCPP_INLINE_VISIBILITY constexpr +enable_if_t, _TPtr> +midpoint(_TPtr __a, _TPtr __b) noexcept +{ + return __a + midpoint(0, __b - __a); +} +#endif + _LIBCPP_END_NAMESPACE_STD _LIBCPP_POP_MACROS Index: libcxx/test/std/numerics/numeric.ops/numeric.ops.midpoint/midpoint.fail.cpp =================================================================== --- /dev/null +++ libcxx/test/std/numerics/numeric.ops/numeric.ops.midpoint/midpoint.fail.cpp @@ -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 +// + +// template +// _Tp midpoint(_Tp __a, _Tp __b) noexcept + +// An overload exists for each of char and all arithmetic types except bool. + +#include + +#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@numeric:* {{arithmetic on pointers to void}} + + return 0; +} Index: libcxx/test/std/numerics/numeric.ops/numeric.ops.midpoint/midpoint.integer.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/numerics/numeric.ops/numeric.ops.midpoint/midpoint.integer.pass.cpp @@ -0,0 +1,133 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// + +// template +// _Tp midpoint(_Tp __a, _Tp __b) noexcept +// + +#include +#include +#include "test_macros.h" + +template +void signed_test() +{ + constexpr T zero{0}; + constexpr T one{1}; + constexpr T two{2}; + constexpr T three{3}; + constexpr T four{4}; + + static_assert(std::is_same_v, ""); + static_assert( noexcept(std::midpoint(T(), T())), ""); + static_assert(std::midpoint(one, three) == two, ""); + using limits = std::numeric_limits; + + 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)); + + assert(std::midpoint(limits::min(), limits::max()) == T(-1)); + assert(std::midpoint(limits::max(), limits::min()) == T(0)); + + 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); + assert(std::midpoint(T(6), limits::max()) == limits::max()/2 + 3); + + 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 - 2); + assert(std::midpoint(T(-6), limits::max()) == limits::max()/2 - 3); +} + +template +void unsigned_test() +{ + constexpr T zero{0}; + constexpr T one{1}; + constexpr T two{2}; + constexpr T three{3}; + constexpr T four{4}; + + static_assert(std::is_same_v, ""); + static_assert( noexcept(std::midpoint(T(), T())), ""); + static_assert(std::midpoint(one, three) == two, ""); + using limits = std::numeric_limits; + const T half_way = (limits::max() - limits::min())/2; + + 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)); + + 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); + assert(std::midpoint(T(6), limits::max()) == half_way + 3); +} + + +int main(int, char**) +{ + signed_test(); + signed_test(); + signed_test(); + signed_test(); + signed_test(); + + signed_test(); + signed_test(); + signed_test(); + signed_test(); + signed_test<__int128_t>(); + + unsigned_test(); + unsigned_test(); + unsigned_test(); + unsigned_test(); + unsigned_test(); + + unsigned_test(); + unsigned_test(); + unsigned_test(); + unsigned_test(); + unsigned_test<__uint128_t>(); + +// int_test(); + signed_test(); + unsigned_test(); + + return 0; +} Index: libcxx/test/std/numerics/numeric.ops/numeric.ops.midpoint/midpoint.pointer.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/numerics/numeric.ops/numeric.ops.midpoint/midpoint.pointer.pass.cpp @@ -0,0 +1,55 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// + +// template +// _Tp* midpoint(_Tp* __a, _Tp* __b) noexcept +// + +#include +#include + +#include "test_macros.h" + + + +template +void pointer_test() +{ + T array[1000] = {}; // we need an array to make valid pointers + constexpr T cArray[2] = {}; + static_assert(std::is_same_v, ""); + static_assert( noexcept(std::midpoint(array, array)), ""); + static_assert(std::midpoint(cArray, cArray + 2) == 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(); + pointer_test< volatile char>(); + pointer_test(); + + pointer_test(); + pointer_test(); + + return 0; +}