15629d492Svarconst //===----------------------------------------------------------------------===//
25629d492Svarconst //
35629d492Svarconst // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45629d492Svarconst // See https://llvm.org/LICENSE.txt for license information.
55629d492Svarconst // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65629d492Svarconst //
75629d492Svarconst //===----------------------------------------------------------------------===//
85629d492Svarconst
95629d492Svarconst // UNSUPPORTED: c++03, c++11, c++14, c++17
105629d492Svarconst // In the modules build, adding another overload of `memmove` doesn't work.
11*3401b308SMark de Wever // UNSUPPORTED: clang-modules-build
125629d492Svarconst // GCC complains about "ambiguating" `__builtin_memmove`.
135629d492Svarconst // UNSUPPORTED: gcc
145629d492Svarconst
155629d492Svarconst // <algorithm>
165629d492Svarconst
175629d492Svarconst // These tests check that `std::copy` and `std::move` (including their variations like `copy_n`) forward to
185629d492Svarconst // `memmove` when possible.
195629d492Svarconst
205629d492Svarconst #include <cstddef>
215629d492Svarconst
225629d492Svarconst struct Foo {
235629d492Svarconst int i = 0;
245629d492Svarconst
255629d492Svarconst Foo() = default;
FooFoo265629d492Svarconst Foo(int set_i) : i(set_i) {}
275629d492Svarconst
285629d492Svarconst friend bool operator==(const Foo&, const Foo&) = default;
295629d492Svarconst };
305629d492Svarconst
315629d492Svarconst static bool memmove_called = false;
325629d492Svarconst
335629d492Svarconst // This template is a better match than the actual `builtin_memmove` (it can match the pointer type exactly, without an
345629d492Svarconst // implicit conversion to `void*`), so it should hijack the call inside `std::copy` and similar algorithms if it's made.
355629d492Svarconst template <class Dst, class Src>
__builtin_memmove(Dst * dst,Src * src,std::size_t count)36fb855eb9SMark de Wever constexpr void* __builtin_memmove(Dst* dst, Src* src, std::size_t count) {
375629d492Svarconst memmove_called = true;
385629d492Svarconst return __builtin_memmove(static_cast<void*>(dst), static_cast<const void*>(src), count);
395629d492Svarconst }
405629d492Svarconst
415629d492Svarconst #include <algorithm>
425629d492Svarconst #include <cassert>
435629d492Svarconst #include <cstdint>
445629d492Svarconst #include <iterator>
455629d492Svarconst #include <limits>
465629d492Svarconst #include <ranges>
475629d492Svarconst #include <type_traits>
485629d492Svarconst
495629d492Svarconst #include "test_iterators.h"
505629d492Svarconst
515629d492Svarconst static_assert(std::is_trivially_copyable_v<Foo>);
525629d492Svarconst
535629d492Svarconst // To test pointers to functions.
Func()545629d492Svarconst void Func() {}
555629d492Svarconst using FuncPtr = decltype(&Func);
565629d492Svarconst
575629d492Svarconst // To test pointers to members.
585629d492Svarconst struct S {
595629d492Svarconst int mem_obj = 0;
MemFuncS605629d492Svarconst void MemFunc() {}
615629d492Svarconst };
625629d492Svarconst using MemObjPtr = decltype(&S::mem_obj);
635629d492Svarconst using MemFuncPtr = decltype(&S::MemFunc);
645629d492Svarconst
655629d492Svarconst // To test bitfields.
665629d492Svarconst struct BitfieldS {
675629d492Svarconst unsigned char b1 : 3;
685629d492Svarconst unsigned char : 2;
695629d492Svarconst unsigned char b2 : 5;
705629d492Svarconst friend bool operator==(const BitfieldS&, const BitfieldS&) = default;
715629d492Svarconst };
725629d492Svarconst
735629d492Svarconst // To test non-default alignment.
745629d492Svarconst struct AlignedS {
755629d492Svarconst alignas(64) int x;
765629d492Svarconst alignas(8) int y;
775629d492Svarconst friend bool operator==(const AlignedS&, const AlignedS&) = default;
785629d492Svarconst };
795629d492Svarconst
805629d492Svarconst template <class T>
make(int from)815629d492Svarconst T make(int from) {
825629d492Svarconst return T(from);
835629d492Svarconst }
845629d492Svarconst
855629d492Svarconst template <class T>
865629d492Svarconst requires (std::is_pointer_v<T> && !std::is_function_v<std::remove_pointer_t<T>>)
make(int i)875629d492Svarconst T make(int i) {
885629d492Svarconst static std::remove_pointer_t<T> arr[8];
895629d492Svarconst return arr + i;
905629d492Svarconst }
915629d492Svarconst
925629d492Svarconst template <class T>
935629d492Svarconst requires std::same_as<T, FuncPtr>
make(int)945629d492Svarconst FuncPtr make(int) {
955629d492Svarconst return &Func;
965629d492Svarconst }
975629d492Svarconst
985629d492Svarconst template <class T>
995629d492Svarconst requires std::same_as<T, MemObjPtr>
make(int)1005629d492Svarconst MemObjPtr make(int) {
1015629d492Svarconst return &S::mem_obj;
1025629d492Svarconst }
1035629d492Svarconst
1045629d492Svarconst template <class T>
1055629d492Svarconst requires std::same_as<T, MemFuncPtr>
make(int)1065629d492Svarconst MemFuncPtr make(int) {
1075629d492Svarconst return &S::MemFunc;
1085629d492Svarconst }
1095629d492Svarconst
1105629d492Svarconst template <class T>
1115629d492Svarconst requires std::same_as<T, BitfieldS>
make(int x)1125629d492Svarconst BitfieldS make(int x) {
1135629d492Svarconst BitfieldS result = {};
1145629d492Svarconst result.b1 = x;
1155629d492Svarconst result.b2 = x;
1165629d492Svarconst return result;
1175629d492Svarconst }
1185629d492Svarconst
1195629d492Svarconst template <class T>
1205629d492Svarconst requires std::same_as<T, AlignedS>
make(int x)1215629d492Svarconst AlignedS make(int x) {
1225629d492Svarconst AlignedS result;
1235629d492Svarconst result.x = x;
1245629d492Svarconst result.y = x;
1255629d492Svarconst return result;
1265629d492Svarconst }
1275629d492Svarconst
1285629d492Svarconst template <class InIter, template <class> class SentWrapper, class OutIter, class Func>
test_one(Func func)1295629d492Svarconst void test_one(Func func) {
1305629d492Svarconst using From = std::iter_value_t<InIter>;
1315629d492Svarconst using To = std::iter_value_t<OutIter>;
1325629d492Svarconst
1335629d492Svarconst // Normal case.
1345629d492Svarconst {
135fb855eb9SMark de Wever const std::size_t N = 4;
1365629d492Svarconst
1375629d492Svarconst From input[N] = {make<From>(1), make<From>(2), make<From>(3), make<From>(4)};
1385629d492Svarconst To output[N];
1395629d492Svarconst
1405629d492Svarconst auto in = InIter(input);
1415629d492Svarconst auto in_end = InIter(input + N);
1425629d492Svarconst auto sent = SentWrapper<decltype(in_end)>(in_end);
1435629d492Svarconst auto out = OutIter(output);
1445629d492Svarconst
1455629d492Svarconst assert(!memmove_called);
1465629d492Svarconst func(in, sent, out, N);
1475629d492Svarconst assert(memmove_called);
1485629d492Svarconst memmove_called = false;
1495629d492Svarconst
1505629d492Svarconst assert(std::equal(input, input + N, output, [](const From& lhs, const To& rhs) {
1515629d492Svarconst // Prevents warnings/errors due to mismatched signed-ness.
1525629d492Svarconst if constexpr (std::convertible_to<From, To>) {
1535629d492Svarconst return static_cast<To>(lhs) == rhs;
1545629d492Svarconst } else if constexpr (std::convertible_to<To, From>) {
1555629d492Svarconst return lhs == static_cast<From>(rhs);
1565629d492Svarconst }
1575629d492Svarconst }));
1585629d492Svarconst }
1595629d492Svarconst }
1605629d492Svarconst
1615629d492Svarconst template <class InIter, template <class> class SentWrapper, class OutIter>
test_copy_and_move()1625629d492Svarconst void test_copy_and_move() {
1635629d492Svarconst // Classic.
1645629d492Svarconst if constexpr (std::same_as<InIter, SentWrapper<InIter>>) {
165fb855eb9SMark de Wever test_one<InIter, SentWrapper, OutIter>([](auto first, auto last, auto out, std::size_t) {
1665629d492Svarconst std::copy(first, last, out);
1675629d492Svarconst });
168fb855eb9SMark de Wever test_one<InIter, SentWrapper, OutIter>([](auto first, auto last, auto out, std::size_t n) {
1695629d492Svarconst std::copy_backward(first, last, out + n);
1705629d492Svarconst });
171fb855eb9SMark de Wever test_one<InIter, SentWrapper, OutIter>([](auto first, auto, auto out, std::size_t n) {
1725629d492Svarconst std::copy_n(first, n, out);
1735629d492Svarconst });
174fb855eb9SMark de Wever test_one<InIter, SentWrapper, OutIter>([](auto first, auto last, auto out, std::size_t) {
1755629d492Svarconst std::move(first, last, out);
1765629d492Svarconst });
177fb855eb9SMark de Wever test_one<InIter, SentWrapper, OutIter>([](auto first, auto last, auto out, std::size_t n) {
1785629d492Svarconst std::move_backward(first, last, out + n);
1795629d492Svarconst });
1805629d492Svarconst }
1815629d492Svarconst
1825629d492Svarconst // Ranges.
183fb855eb9SMark de Wever test_one<InIter, SentWrapper, OutIter>([](auto first, auto last, auto out, std::size_t) {
1845629d492Svarconst std::ranges::copy(first, last, out);
1855629d492Svarconst });
186fb855eb9SMark de Wever test_one<InIter, SentWrapper, OutIter>([](auto first, auto last, auto out, std::size_t n) {
1875629d492Svarconst std::ranges::copy_backward(first, last, out + n);
1885629d492Svarconst });
189fb855eb9SMark de Wever test_one<InIter, SentWrapper, OutIter>([](auto first, auto, auto out, std::size_t n) {
1905629d492Svarconst std::ranges::copy_n(first, n, out);
1915629d492Svarconst });
192fb855eb9SMark de Wever test_one<InIter, SentWrapper, OutIter>([](auto first, auto last, auto out, std::size_t) {
1935629d492Svarconst std::ranges::move(first, last, out);
1945629d492Svarconst });
195fb855eb9SMark de Wever test_one<InIter, SentWrapper, OutIter>([](auto first, auto last, auto out, std::size_t n) {
1965629d492Svarconst std::ranges::move_backward(first, last, out + n);
1975629d492Svarconst });
1985629d492Svarconst }
1995629d492Svarconst
2005629d492Svarconst template <class From, class To, template <class> class SentWrapper, bool BothDirections = !std::same_as<From, To>>
test_all_permutations_from_to_sent()2015629d492Svarconst void test_all_permutations_from_to_sent() {
2025629d492Svarconst test_copy_and_move<From*, SentWrapper, To*>();
2035629d492Svarconst test_copy_and_move<contiguous_iterator<From*>, SentWrapper, To*>();
2045629d492Svarconst test_copy_and_move<From*, SentWrapper, contiguous_iterator<To*>>();
2055629d492Svarconst test_copy_and_move<contiguous_iterator<From*>, SentWrapper, contiguous_iterator<To*>>();
2065629d492Svarconst
2075629d492Svarconst if (BothDirections) {
2085629d492Svarconst test_copy_and_move<To*, SentWrapper, From*>();
2095629d492Svarconst test_copy_and_move<contiguous_iterator<To*>, SentWrapper, From*>();
2105629d492Svarconst test_copy_and_move<To*, SentWrapper, contiguous_iterator<From*>>();
2115629d492Svarconst test_copy_and_move<contiguous_iterator<To*>, SentWrapper, contiguous_iterator<From*>>();
2125629d492Svarconst }
2135629d492Svarconst }
2145629d492Svarconst
test_different_signedness()2155629d492Svarconst void test_different_signedness() {
2165629d492Svarconst auto check = [](auto alg) {
2175629d492Svarconst // Signed -> unsigned.
2185629d492Svarconst {
2195629d492Svarconst constexpr int N = 3;
2205629d492Svarconst constexpr auto min_value = std::numeric_limits<int>::min();
2215629d492Svarconst
2225629d492Svarconst int in[N] = {-1, min_value / 2, min_value};
2235629d492Svarconst unsigned int out[N];
2245629d492Svarconst unsigned int expected[N] = {
2255629d492Svarconst static_cast<unsigned int>(in[0]),
2265629d492Svarconst static_cast<unsigned int>(in[1]),
2275629d492Svarconst static_cast<unsigned int>(in[2]),
2285629d492Svarconst };
2295629d492Svarconst
2305629d492Svarconst assert(!memmove_called);
2315629d492Svarconst alg(in, in + N, out, N);
2325629d492Svarconst assert(memmove_called);
2335629d492Svarconst memmove_called = false;
2345629d492Svarconst
2355629d492Svarconst assert(std::equal(out, out + N, expected));
2365629d492Svarconst }
2375629d492Svarconst
2385629d492Svarconst // Unsigned -> signed.
2395629d492Svarconst {
2405629d492Svarconst constexpr int N = 3;
2415629d492Svarconst constexpr auto max_signed = std::numeric_limits<int>::max();
2425629d492Svarconst constexpr auto max_unsigned = std::numeric_limits<unsigned int>::max();
2435629d492Svarconst
2445629d492Svarconst unsigned int in[N] = {static_cast<unsigned int>(max_signed) + 1, max_unsigned / 2, max_unsigned};
2455629d492Svarconst int out[N];
2465629d492Svarconst int expected[N] = {
2475629d492Svarconst static_cast<int>(in[0]),
2485629d492Svarconst static_cast<int>(in[1]),
2495629d492Svarconst static_cast<int>(in[2]),
2505629d492Svarconst };
2515629d492Svarconst
2525629d492Svarconst assert(!memmove_called);
2535629d492Svarconst alg(in, in + N, out, N);
2545629d492Svarconst assert(memmove_called);
2555629d492Svarconst memmove_called = false;
2565629d492Svarconst
2575629d492Svarconst assert(std::equal(out, out + N, expected));
2585629d492Svarconst }
2595629d492Svarconst };
2605629d492Svarconst
261fb855eb9SMark de Wever check([](auto first, auto last, auto out, std::size_t) {
2625629d492Svarconst std::copy(first, last, out);
2635629d492Svarconst });
264fb855eb9SMark de Wever check([](auto first, auto last, auto out, std::size_t n) {
2655629d492Svarconst std::copy_backward(first, last, out + n);
2665629d492Svarconst });
267fb855eb9SMark de Wever check([](auto first, auto, auto out, std::size_t n) {
2685629d492Svarconst std::copy_n(first, n, out);
2695629d492Svarconst });
270fb855eb9SMark de Wever check([](auto first, auto last, auto out, std::size_t) {
2715629d492Svarconst std::move(first, last, out);
2725629d492Svarconst });
273fb855eb9SMark de Wever check([](auto first, auto last, auto out, std::size_t n) {
2745629d492Svarconst std::move_backward(first, last, out + n);
2755629d492Svarconst });
2765629d492Svarconst
2775629d492Svarconst // Ranges.
278fb855eb9SMark de Wever check([](auto first, auto last, auto out, std::size_t) {
2795629d492Svarconst std::ranges::copy(first, last, out);
2805629d492Svarconst });
281fb855eb9SMark de Wever check([](auto first, auto last, auto out, std::size_t n) {
2825629d492Svarconst std::ranges::copy_backward(first, last, out + n);
2835629d492Svarconst });
284fb855eb9SMark de Wever check([](auto first, auto, auto out, std::size_t n) {
2855629d492Svarconst std::ranges::copy_n(first, n, out);
2865629d492Svarconst });
287fb855eb9SMark de Wever check([](auto first, auto last, auto out, std::size_t) {
2885629d492Svarconst std::ranges::move(first, last, out);
2895629d492Svarconst });
290fb855eb9SMark de Wever check([](auto first, auto last, auto out, std::size_t n) {
2915629d492Svarconst std::ranges::move_backward(first, last, out + n);
2925629d492Svarconst });
2935629d492Svarconst }
2945629d492Svarconst
test()2955629d492Svarconst void test() {
2965629d492Svarconst // Built-in.
2975629d492Svarconst test_all_permutations_from_to_sent<int, int, std::type_identity_t>();
2985629d492Svarconst // User-defined.
2995629d492Svarconst test_all_permutations_from_to_sent<Foo, Foo, std::type_identity_t>();
3005629d492Svarconst
3015629d492Svarconst // Conversions.
3025629d492Svarconst test_all_permutations_from_to_sent<char32_t, std::int32_t, sized_sentinel>();
3035629d492Svarconst test_all_permutations_from_to_sent<std::int32_t, std::uint32_t, sized_sentinel>();
3045629d492Svarconst // Conversion from `bool` to `char` invokes the optimization (the set of values for `char` is a superset of the set of
3055629d492Svarconst // values for `bool`), but the other way round cannot.
3065629d492Svarconst test_all_permutations_from_to_sent<bool, char, sized_sentinel, /*BothDirections=*/false>();
3075629d492Svarconst
3085629d492Svarconst // Copying between regular pointers.
3095629d492Svarconst test_copy_and_move<int**, std::type_identity_t, int**>();
3105629d492Svarconst
3115629d492Svarconst // Copying between pointers to functions.
3125629d492Svarconst test_copy_and_move<FuncPtr*, std::type_identity_t, FuncPtr*>();
3135629d492Svarconst
3145629d492Svarconst // Copying between pointers to members.
3155629d492Svarconst test_copy_and_move<MemObjPtr*, std::type_identity_t, MemObjPtr*>();
3165629d492Svarconst test_copy_and_move<MemFuncPtr*, std::type_identity_t, MemFuncPtr*>();
3175629d492Svarconst
3185629d492Svarconst // Copying structs with bitfields.
3195629d492Svarconst test_copy_and_move<BitfieldS*, std::type_identity_t, BitfieldS*>();
3205629d492Svarconst
3215629d492Svarconst // Copying objects with non-default alignment.
3225629d492Svarconst test_copy_and_move<AlignedS*, std::type_identity_t, AlignedS*>();
3235629d492Svarconst
3245629d492Svarconst // Copying integers with different signedness produces the same results as built-in assignment.
3255629d492Svarconst test_different_signedness();
3265629d492Svarconst }
3275629d492Svarconst
main(int,char **)3285629d492Svarconst int main(int, char**) {
3295629d492Svarconst test();
3305629d492Svarconst // The test relies on a global variable, so it cannot be made `constexpr`; the `memmove` optimization is not used in
3315629d492Svarconst // `constexpr` mode anyway.
3325629d492Svarconst
3335629d492Svarconst return 0;
3345629d492Svarconst }
335