13b62047bSLouis Dionne // -*- C++ -*-
23b62047bSLouis Dionne //===-- reduce.pass.cpp ---------------------------------------------------===//
33b62047bSLouis Dionne //
43b62047bSLouis Dionne // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
53b62047bSLouis Dionne // See https://llvm.org/LICENSE.txt for license information.
63b62047bSLouis Dionne // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
73b62047bSLouis Dionne //
83b62047bSLouis Dionne //===----------------------------------------------------------------------===//
93b62047bSLouis Dionne 
103b62047bSLouis Dionne #include "support/pstl_test_config.h"
113b62047bSLouis Dionne 
123b62047bSLouis Dionne #ifdef PSTL_STANDALONE_TESTS
133b62047bSLouis Dionne #include "pstl/execution"
143b62047bSLouis Dionne #include "pstl/numeric"
153b62047bSLouis Dionne #else
163b62047bSLouis Dionne #include <execution>
173b62047bSLouis Dionne #include <numeric>
183b62047bSLouis Dionne #endif // PSTL_STANDALONE_TESTS
193b62047bSLouis Dionne 
203b62047bSLouis Dionne #include "support/utils.h"
213b62047bSLouis Dionne 
223b62047bSLouis Dionne using namespace TestUtils;
233b62047bSLouis Dionne 
243b62047bSLouis Dionne struct test_long_forms_for_one_policy
253b62047bSLouis Dionne {
263b62047bSLouis Dionne     template <typename Policy, typename Iterator, typename T, typename BinaryOp>
273b62047bSLouis Dionne     void
283b62047bSLouis Dionne     operator()(Policy&& exec, Iterator first, Iterator last, T init, BinaryOp binary, T expected)
293b62047bSLouis Dionne     {
303b62047bSLouis Dionne         T result_r = std::reduce(exec, first, last, init, binary);
313b62047bSLouis Dionne         EXPECT_EQ(expected, result_r, "bad result from reduce(exec, first, last, init, binary_op)");
323b62047bSLouis Dionne     }
333b62047bSLouis Dionne };
343b62047bSLouis Dionne 
353b62047bSLouis Dionne template <typename T, typename BinaryOp, typename F>
363b62047bSLouis Dionne void
373b62047bSLouis Dionne test_long_form(T init, BinaryOp binary_op, F f)
383b62047bSLouis Dionne {
393b62047bSLouis Dionne     // Try sequences of various lengths
403b62047bSLouis Dionne     for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
413b62047bSLouis Dionne     {
423b62047bSLouis Dionne         T expected(init);
433b62047bSLouis Dionne         Sequence<T> in(n, [n, f](size_t k) { return f((int32_t(k ^ n) % 1000 - 500)); });
443b62047bSLouis Dionne         for (size_t k = 0; k < n; ++k)
453b62047bSLouis Dionne             expected = binary_op(expected, in[k]);
463b62047bSLouis Dionne 
473b62047bSLouis Dionne         using namespace std;
483b62047bSLouis Dionne 
493b62047bSLouis Dionne         T result = transform_reduce_serial(in.cfbegin(), in.cfend(), init, binary_op, [](const T& t) { return t; });
503b62047bSLouis Dionne         EXPECT_EQ(expected, result, "bad result from reduce(first, last, init, binary_op_op)");
513b62047bSLouis Dionne 
523b62047bSLouis Dionne         invoke_on_all_policies(test_long_forms_for_one_policy(), in.begin(), in.end(), init, binary_op, expected);
533b62047bSLouis Dionne         invoke_on_all_policies(test_long_forms_for_one_policy(), in.cbegin(), in.cend(), init, binary_op, expected);
543b62047bSLouis Dionne     }
553b62047bSLouis Dionne }
563b62047bSLouis Dionne 
573b62047bSLouis Dionne struct test_two_short_forms
583b62047bSLouis Dionne {
593b62047bSLouis Dionne 
60*3dee12e4SLouis Dionne #if _PSTL_ICC_16_VC14_TEST_PAR_TBB_RT_RELEASE_64_BROKEN //dummy specialization by policy type, in case of broken configuration
613b62047bSLouis Dionne     template <typename Iterator>
623b62047bSLouis Dionne     void
633b62047bSLouis Dionne     operator()(pstl::execution::parallel_policy, Iterator first, Iterator last, Sum init, Sum expected)
643b62047bSLouis Dionne     {
653b62047bSLouis Dionne     }
663b62047bSLouis Dionne     template <typename Iterator>
673b62047bSLouis Dionne     void
683b62047bSLouis Dionne     operator()(pstl::execution::parallel_unsequenced_policy, Iterator first, Iterator last, Sum init, Sum expected)
693b62047bSLouis Dionne     {
703b62047bSLouis Dionne     }
713b62047bSLouis Dionne #endif
723b62047bSLouis Dionne 
733b62047bSLouis Dionne     template <typename Policy, typename Iterator>
743b62047bSLouis Dionne     void
753b62047bSLouis Dionne     operator()(Policy&& exec, Iterator first, Iterator last, Sum init, Sum expected)
763b62047bSLouis Dionne     {
773b62047bSLouis Dionne         using namespace std;
783b62047bSLouis Dionne 
793b62047bSLouis Dionne         Sum r0 = init + reduce(exec, first, last);
803b62047bSLouis Dionne         EXPECT_EQ(expected, r0, "bad result from reduce(exec, first, last)");
813b62047bSLouis Dionne 
823b62047bSLouis Dionne         Sum r1 = reduce(exec, first, last, init);
833b62047bSLouis Dionne         EXPECT_EQ(expected, r1, "bad result from reduce(exec, first, last, init)");
843b62047bSLouis Dionne     }
853b62047bSLouis Dionne };
863b62047bSLouis Dionne 
873b62047bSLouis Dionne // Test forms of reduce(...) that omit the binary_op or init operands.
883b62047bSLouis Dionne void
893b62047bSLouis Dionne test_short_forms()
903b62047bSLouis Dionne {
913b62047bSLouis Dionne     for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
923b62047bSLouis Dionne     {
933b62047bSLouis Dionne         Sum init(42, OddTag());
943b62047bSLouis Dionne         Sum expected(init);
953b62047bSLouis Dionne         Sequence<Sum> in(n, [n](size_t k) { return Sum((int32_t(k ^ n) % 1000 - 500), OddTag()); });
963b62047bSLouis Dionne         for (size_t k = 0; k < n; ++k)
973b62047bSLouis Dionne             expected = expected + in[k];
983b62047bSLouis Dionne         invoke_on_all_policies(test_two_short_forms(), in.begin(), in.end(), init, expected);
993b62047bSLouis Dionne         invoke_on_all_policies(test_two_short_forms(), in.cbegin(), in.cend(), init, expected);
1003b62047bSLouis Dionne     }
1013b62047bSLouis Dionne }
1023b62047bSLouis Dionne 
1033b62047bSLouis Dionne int32_t
1043b62047bSLouis Dionne main()
1053b62047bSLouis Dionne {
1063b62047bSLouis Dionne     // Test for popular types
1073b62047bSLouis Dionne     test_long_form(42, std::plus<int32_t>(), [](int32_t x) { return x; });
1083b62047bSLouis Dionne     test_long_form(42.0, std::plus<float64_t>(), [](float64_t x) { return x; });
1093b62047bSLouis Dionne 
1103b62047bSLouis Dionne     // Test for strict types
1113b62047bSLouis Dionne     test_long_form<Number>(Number(42, OddTag()), Add(OddTag()), [](int32_t x) { return Number(x, OddTag()); });
1123b62047bSLouis Dionne 
1133b62047bSLouis Dionne     // Short forms are just facade for long forms, so just test with a single type.
1143b62047bSLouis Dionne     test_short_forms();
1153b62047bSLouis Dionne     std::cout << done() << std::endl;
1163b62047bSLouis Dionne     return 0;
1173b62047bSLouis Dionne }
118