13b62047bSLouis Dionne // -*- C++ -*-
23b62047bSLouis Dionne //===-- utils.h -----------------------------------------------------------===//
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 // File contains common utilities that tests rely on
113b62047bSLouis Dionne
123b62047bSLouis Dionne // Do not #include <algorithm>, because if we do we will not detect accidental dependencies.
133b62047bSLouis Dionne #include <atomic>
143b62047bSLouis Dionne #include <cstdint>
153b62047bSLouis Dionne #include <cstdlib>
163b62047bSLouis Dionne #include <cstring>
173b62047bSLouis Dionne #include <iostream>
183b62047bSLouis Dionne #include <iterator>
193b62047bSLouis Dionne #include <memory>
203b62047bSLouis Dionne #include <sstream>
213b62047bSLouis Dionne #include <vector>
223b62047bSLouis Dionne
233b62047bSLouis Dionne #include "pstl_test_config.h"
243b62047bSLouis Dionne
253b62047bSLouis Dionne namespace TestUtils
263b62047bSLouis Dionne {
273b62047bSLouis Dionne
283b62047bSLouis Dionne typedef double float64_t;
293b62047bSLouis Dionne typedef float float32_t;
303b62047bSLouis Dionne
313b62047bSLouis Dionne template <class T, std::size_t N>
323b62047bSLouis Dionne constexpr size_t
const_size(const T (&)[N])335c4c4431SLouis Dionne const_size(const T (&)[N]) noexcept
343b62047bSLouis Dionne {
353b62047bSLouis Dionne return N;
363b62047bSLouis Dionne }
373b62047bSLouis Dionne
383b62047bSLouis Dionne template <typename T>
393b62047bSLouis Dionne class Sequence;
403b62047bSLouis Dionne
413b62047bSLouis Dionne // Handy macros for error reporting
423b62047bSLouis Dionne #define EXPECT_TRUE(condition, message) ::TestUtils::expect(true, condition, __FILE__, __LINE__, message)
433b62047bSLouis Dionne #define EXPECT_FALSE(condition, message) ::TestUtils::expect(false, condition, __FILE__, __LINE__, message)
443b62047bSLouis Dionne
453b62047bSLouis Dionne // Check that expected and actual are equal and have the same type.
463b62047bSLouis Dionne #define EXPECT_EQ(expected, actual, message) ::TestUtils::expect_equal(expected, actual, __FILE__, __LINE__, message)
473b62047bSLouis Dionne
483b62047bSLouis Dionne // Check that sequences started with expected and actual and have had size n are equal and have the same type.
493b62047bSLouis Dionne #define EXPECT_EQ_N(expected, actual, n, message) \
503b62047bSLouis Dionne ::TestUtils::expect_equal(expected, actual, n, __FILE__, __LINE__, message)
513b62047bSLouis Dionne
523b62047bSLouis Dionne // Issue error message from outstr, adding a newline.
533b62047bSLouis Dionne // Real purpose of this routine is to have a place to hang a breakpoint.
543b62047bSLouis Dionne inline void
issue_error_message(std::stringstream & outstr)553b62047bSLouis Dionne issue_error_message(std::stringstream& outstr)
563b62047bSLouis Dionne {
573b62047bSLouis Dionne outstr << std::endl;
583b62047bSLouis Dionne std::cerr << outstr.str();
593b62047bSLouis Dionne std::exit(EXIT_FAILURE);
603b62047bSLouis Dionne }
613b62047bSLouis Dionne
623b62047bSLouis Dionne inline void
expect(bool expected,bool condition,const char * file,int32_t line,const char * message)633b62047bSLouis Dionne expect(bool expected, bool condition, const char* file, int32_t line, const char* message)
643b62047bSLouis Dionne {
653b62047bSLouis Dionne if (condition != expected)
663b62047bSLouis Dionne {
673b62047bSLouis Dionne std::stringstream outstr;
683b62047bSLouis Dionne outstr << "error at " << file << ":" << line << " - " << message;
693b62047bSLouis Dionne issue_error_message(outstr);
703b62047bSLouis Dionne }
713b62047bSLouis Dionne }
723b62047bSLouis Dionne
733b62047bSLouis Dionne // Do not change signature to const T&.
743b62047bSLouis Dionne // Function must be able to detect const differences between expected and actual.
753b62047bSLouis Dionne template <typename T>
763b62047bSLouis Dionne void
expect_equal(T & expected,T & actual,const char * file,int32_t line,const char * message)773b62047bSLouis Dionne expect_equal(T& expected, T& actual, const char* file, int32_t line, const char* message)
783b62047bSLouis Dionne {
793b62047bSLouis Dionne if (!(expected == actual))
803b62047bSLouis Dionne {
813b62047bSLouis Dionne std::stringstream outstr;
823b62047bSLouis Dionne outstr << "error at " << file << ":" << line << " - " << message << ", expected " << expected << " got "
833b62047bSLouis Dionne << actual;
843b62047bSLouis Dionne issue_error_message(outstr);
853b62047bSLouis Dionne }
863b62047bSLouis Dionne }
873b62047bSLouis Dionne
883b62047bSLouis Dionne template <typename T>
893b62047bSLouis Dionne void
expect_equal(Sequence<T> & expected,Sequence<T> & actual,const char * file,int32_t line,const char * message)903b62047bSLouis Dionne expect_equal(Sequence<T>& expected, Sequence<T>& actual, const char* file, int32_t line, const char* message)
913b62047bSLouis Dionne {
923b62047bSLouis Dionne size_t n = expected.size();
933b62047bSLouis Dionne size_t m = actual.size();
943b62047bSLouis Dionne if (n != m)
953b62047bSLouis Dionne {
963b62047bSLouis Dionne std::stringstream outstr;
973b62047bSLouis Dionne outstr << "error at " << file << ":" << line << " - " << message << ", expected sequence of size " << n
983b62047bSLouis Dionne << " got sequence of size " << m;
993b62047bSLouis Dionne issue_error_message(outstr);
1003b62047bSLouis Dionne return;
1013b62047bSLouis Dionne }
1023b62047bSLouis Dionne size_t error_count = 0;
1033b62047bSLouis Dionne for (size_t k = 0; k < n && error_count < 10; ++k)
1043b62047bSLouis Dionne {
1053b62047bSLouis Dionne if (!(expected[k] == actual[k]))
1063b62047bSLouis Dionne {
1073b62047bSLouis Dionne std::stringstream outstr;
1083b62047bSLouis Dionne outstr << "error at " << file << ":" << line << " - " << message << ", at index " << k << " expected "
1093b62047bSLouis Dionne << expected[k] << " got " << actual[k];
1103b62047bSLouis Dionne issue_error_message(outstr);
1113b62047bSLouis Dionne ++error_count;
1123b62047bSLouis Dionne }
1133b62047bSLouis Dionne }
1143b62047bSLouis Dionne }
1153b62047bSLouis Dionne
1163b62047bSLouis Dionne template <typename Iterator1, typename Iterator2, typename Size>
1173b62047bSLouis Dionne void
expect_equal(Iterator1 expected_first,Iterator2 actual_first,Size n,const char * file,int32_t line,const char * message)1183b62047bSLouis Dionne expect_equal(Iterator1 expected_first, Iterator2 actual_first, Size n, const char* file, int32_t line,
1193b62047bSLouis Dionne const char* message)
1203b62047bSLouis Dionne {
1213b62047bSLouis Dionne size_t error_count = 0;
1225c4c4431SLouis Dionne for (Size k = 0; k < n && error_count < 10; ++k, ++expected_first, ++actual_first)
1233b62047bSLouis Dionne {
1243b62047bSLouis Dionne if (!(*expected_first == *actual_first))
1253b62047bSLouis Dionne {
1263b62047bSLouis Dionne std::stringstream outstr;
1273b62047bSLouis Dionne outstr << "error at " << file << ":" << line << " - " << message << ", at index " << k;
1283b62047bSLouis Dionne issue_error_message(outstr);
1293b62047bSLouis Dionne ++error_count;
1303b62047bSLouis Dionne }
1313b62047bSLouis Dionne }
1323b62047bSLouis Dionne }
1333b62047bSLouis Dionne
1343b62047bSLouis Dionne // ForwardIterator is like type Iterator, but restricted to be a forward iterator.
1353b62047bSLouis Dionne // Only the forward iterator signatures that are necessary for tests are present.
1363b62047bSLouis Dionne // Post-increment in particular is deliberatly omitted since our templates should avoid using it
1373b62047bSLouis Dionne // because of efficiency considerations.
1383b62047bSLouis Dionne template <typename Iterator, typename IteratorTag>
1393b62047bSLouis Dionne class ForwardIterator
1403b62047bSLouis Dionne {
1413b62047bSLouis Dionne public:
1423b62047bSLouis Dionne typedef IteratorTag iterator_category;
1433b62047bSLouis Dionne typedef typename std::iterator_traits<Iterator>::value_type value_type;
1443b62047bSLouis Dionne typedef typename std::iterator_traits<Iterator>::difference_type difference_type;
1453b62047bSLouis Dionne typedef typename std::iterator_traits<Iterator>::pointer pointer;
1463b62047bSLouis Dionne typedef typename std::iterator_traits<Iterator>::reference reference;
1473b62047bSLouis Dionne
1483b62047bSLouis Dionne protected:
1493b62047bSLouis Dionne Iterator my_iterator;
1503b62047bSLouis Dionne typedef value_type element_type;
1513b62047bSLouis Dionne
1523b62047bSLouis Dionne public:
1533b62047bSLouis Dionne ForwardIterator() = default;
ForwardIterator(Iterator i)1543b62047bSLouis Dionne explicit ForwardIterator(Iterator i) : my_iterator(i) {}
1553b62047bSLouis Dionne reference operator*() const { return *my_iterator; }
1563b62047bSLouis Dionne Iterator operator->() const { return my_iterator; }
1573b62047bSLouis Dionne ForwardIterator
1583b62047bSLouis Dionne operator++()
1593b62047bSLouis Dionne {
1603b62047bSLouis Dionne ++my_iterator;
1613b62047bSLouis Dionne return *this;
1623b62047bSLouis Dionne }
1633b62047bSLouis Dionne ForwardIterator operator++(int32_t)
1643b62047bSLouis Dionne {
1653b62047bSLouis Dionne auto retval = *this;
1663b62047bSLouis Dionne my_iterator++;
1673b62047bSLouis Dionne return retval;
1683b62047bSLouis Dionne }
1693b62047bSLouis Dionne friend bool
1703b62047bSLouis Dionne operator==(const ForwardIterator& i, const ForwardIterator& j)
1713b62047bSLouis Dionne {
1723b62047bSLouis Dionne return i.my_iterator == j.my_iterator;
1733b62047bSLouis Dionne }
1743b62047bSLouis Dionne friend bool
1753b62047bSLouis Dionne operator!=(const ForwardIterator& i, const ForwardIterator& j)
1763b62047bSLouis Dionne {
1773b62047bSLouis Dionne return i.my_iterator != j.my_iterator;
1783b62047bSLouis Dionne }
1793b62047bSLouis Dionne
1803b62047bSLouis Dionne Iterator
iterator()1813b62047bSLouis Dionne iterator() const
1823b62047bSLouis Dionne {
1833b62047bSLouis Dionne return my_iterator;
1843b62047bSLouis Dionne }
1853b62047bSLouis Dionne };
1863b62047bSLouis Dionne
1873b62047bSLouis Dionne template <typename Iterator, typename IteratorTag>
1883b62047bSLouis Dionne class BidirectionalIterator : public ForwardIterator<Iterator, IteratorTag>
1893b62047bSLouis Dionne {
1903b62047bSLouis Dionne typedef ForwardIterator<Iterator, IteratorTag> base_type;
1913b62047bSLouis Dionne
1923b62047bSLouis Dionne public:
1933b62047bSLouis Dionne BidirectionalIterator() = default;
BidirectionalIterator(Iterator i)1943b62047bSLouis Dionne explicit BidirectionalIterator(Iterator i) : base_type(i) {}
BidirectionalIterator(const base_type & i)1953b62047bSLouis Dionne BidirectionalIterator(const base_type& i) : base_type(i.iterator()) {}
1963b62047bSLouis Dionne
1973b62047bSLouis Dionne BidirectionalIterator
1983b62047bSLouis Dionne operator++()
1993b62047bSLouis Dionne {
2003b62047bSLouis Dionne ++base_type::my_iterator;
2013b62047bSLouis Dionne return *this;
2023b62047bSLouis Dionne }
2033b62047bSLouis Dionne BidirectionalIterator
2043b62047bSLouis Dionne operator--()
2053b62047bSLouis Dionne {
2063b62047bSLouis Dionne --base_type::my_iterator;
2073b62047bSLouis Dionne return *this;
2083b62047bSLouis Dionne }
2093b62047bSLouis Dionne BidirectionalIterator operator++(int32_t)
2103b62047bSLouis Dionne {
2113b62047bSLouis Dionne auto retval = *this;
2123b62047bSLouis Dionne base_type::my_iterator++;
2133b62047bSLouis Dionne return retval;
2143b62047bSLouis Dionne }
2153b62047bSLouis Dionne BidirectionalIterator operator--(int32_t)
2163b62047bSLouis Dionne {
2173b62047bSLouis Dionne auto retval = *this;
2183b62047bSLouis Dionne base_type::my_iterator--;
2193b62047bSLouis Dionne return retval;
2203b62047bSLouis Dionne }
2213b62047bSLouis Dionne };
2223b62047bSLouis Dionne
2233b62047bSLouis Dionne template <typename Iterator, typename F>
2243b62047bSLouis Dionne void
fill_data(Iterator first,Iterator last,F f)2253b62047bSLouis Dionne fill_data(Iterator first, Iterator last, F f)
2263b62047bSLouis Dionne {
2273b62047bSLouis Dionne typedef typename std::iterator_traits<Iterator>::value_type T;
2283b62047bSLouis Dionne for (std::size_t i = 0; first != last; ++first, ++i)
2293b62047bSLouis Dionne {
2303b62047bSLouis Dionne *first = T(f(i));
2313b62047bSLouis Dionne }
2323b62047bSLouis Dionne }
2333b62047bSLouis Dionne
2345b0502dfSDvorskiy, Mikhail struct MemoryChecker {
2355b0502dfSDvorskiy, Mikhail // static counters and state tags
2365b0502dfSDvorskiy, Mikhail static std::atomic<std::int64_t> alive_object_counter; // initialized outside
2375b0502dfSDvorskiy, Mikhail static constexpr std::int64_t alive_state = 0xAAAAAAAAAAAAAAAA;
2385b0502dfSDvorskiy, Mikhail static constexpr std::int32_t dead_state = 0; // only used as a set value to cancel alive_state
2395b0502dfSDvorskiy, Mikhail
2405b0502dfSDvorskiy, Mikhail std::int32_t _value; // object value used for algorithms
2415b0502dfSDvorskiy, Mikhail std::int64_t _state; // state tag used for checks
2425b0502dfSDvorskiy, Mikhail
2435b0502dfSDvorskiy, Mikhail // ctors, dtors, assign ops
_valueMemoryChecker2445b0502dfSDvorskiy, Mikhail explicit MemoryChecker(std::int32_t value = 0) : _value(value) {
2455b0502dfSDvorskiy, Mikhail // check for EXPECT_TRUE(state() != alive_state, ...) has not been done since we cannot guarantee that
2465b0502dfSDvorskiy, Mikhail // raw memory for object being constructed does not have a bit sequence being equal to alive_state
2475b0502dfSDvorskiy, Mikhail
2485b0502dfSDvorskiy, Mikhail // set constructed state and increment counter for living object
2495b0502dfSDvorskiy, Mikhail inc_alive_objects();
2505b0502dfSDvorskiy, Mikhail _state = alive_state;
2515b0502dfSDvorskiy, Mikhail }
MemoryCheckerMemoryChecker2525b0502dfSDvorskiy, Mikhail MemoryChecker(MemoryChecker&& other) : _value(other.value()) {
2535b0502dfSDvorskiy, Mikhail // check for EXPECT_TRUE(state() != alive_state, ...) has not been done since
2545b0502dfSDvorskiy, Mikhail // compiler can optimize out the move ctor call that results in false positive failure
2555b0502dfSDvorskiy, Mikhail EXPECT_TRUE(other.state() == alive_state, "wrong effect from MemoryChecker(MemoryChecker&&): attemp to construct an object from non-existing object");
2565b0502dfSDvorskiy, Mikhail // set constructed state and increment counter for living object
2575b0502dfSDvorskiy, Mikhail inc_alive_objects();
2585b0502dfSDvorskiy, Mikhail _state = alive_state;
2595b0502dfSDvorskiy, Mikhail }
MemoryCheckerMemoryChecker2605b0502dfSDvorskiy, Mikhail MemoryChecker(const MemoryChecker& other) : _value(other.value()) {
2615b0502dfSDvorskiy, Mikhail // check for EXPECT_TRUE(state() != alive_state, ...) has not been done since
2625b0502dfSDvorskiy, Mikhail // compiler can optimize out the copy ctor call that results in false positive failure
2635b0502dfSDvorskiy, Mikhail EXPECT_TRUE(other.state() == alive_state, "wrong effect from MemoryChecker(const MemoryChecker&): attemp to construct an object from non-existing object");
2645b0502dfSDvorskiy, Mikhail // set constructed state and increment counter for living object
2655b0502dfSDvorskiy, Mikhail inc_alive_objects();
2665b0502dfSDvorskiy, Mikhail _state = alive_state;
2675b0502dfSDvorskiy, Mikhail }
2685b0502dfSDvorskiy, Mikhail MemoryChecker& operator=(MemoryChecker&& other) {
2695b0502dfSDvorskiy, Mikhail // check if we do not assign over uninitialized memory
2705b0502dfSDvorskiy, Mikhail EXPECT_TRUE(state() == alive_state, "wrong effect from MemoryChecker::operator=(MemoryChecker&& other): attemp to assign to non-existing object");
2715b0502dfSDvorskiy, Mikhail EXPECT_TRUE(other.state() == alive_state, "wrong effect from MemoryChecker::operator=(MemoryChecker&& other): attemp to assign from non-existing object");
2725b0502dfSDvorskiy, Mikhail // just assign new value, counter is the same, state is the same
2735b0502dfSDvorskiy, Mikhail _value = other.value();
2745b0502dfSDvorskiy, Mikhail
2755b0502dfSDvorskiy, Mikhail return *this;
2765b0502dfSDvorskiy, Mikhail }
2775b0502dfSDvorskiy, Mikhail MemoryChecker& operator=(const MemoryChecker& other) {
2785b0502dfSDvorskiy, Mikhail // check if we do not assign over uninitialized memory
2795b0502dfSDvorskiy, Mikhail EXPECT_TRUE(state() == alive_state, "wrong effect from MemoryChecker::operator=(const MemoryChecker& other): attemp to assign to non-existing object");
2805b0502dfSDvorskiy, Mikhail EXPECT_TRUE(other.state() == alive_state, "wrong effect from MemoryChecker::operator=(const MemoryChecker& other): attemp to assign from non-existing object");
2815b0502dfSDvorskiy, Mikhail // just assign new value, counter is the same, state is the same
2825b0502dfSDvorskiy, Mikhail _value = other.value();
2835b0502dfSDvorskiy, Mikhail
2845b0502dfSDvorskiy, Mikhail return *this;
2855b0502dfSDvorskiy, Mikhail }
~MemoryCheckerMemoryChecker2865b0502dfSDvorskiy, Mikhail ~MemoryChecker() {
2875b0502dfSDvorskiy, Mikhail // check if we do not double destruct the object
2885b0502dfSDvorskiy, Mikhail EXPECT_TRUE(state() == alive_state, "wrong effect from ~MemoryChecker(): attemp to destroy non-existing object");
2895b0502dfSDvorskiy, Mikhail // set destructed state and decrement counter for living object
2905b0502dfSDvorskiy, Mikhail static_cast<volatile std::int64_t&>(_state) = dead_state;
2915b0502dfSDvorskiy, Mikhail dec_alive_objects();
2925b0502dfSDvorskiy, Mikhail }
2935b0502dfSDvorskiy, Mikhail
2945b0502dfSDvorskiy, Mikhail // getters
valueMemoryChecker2955b0502dfSDvorskiy, Mikhail std::int32_t value() const { return _value; }
stateMemoryChecker2965b0502dfSDvorskiy, Mikhail std::int64_t state() const { return _state; }
alive_objectsMemoryChecker2975b0502dfSDvorskiy, Mikhail static std::int32_t alive_objects() { return alive_object_counter.load(); }
2985b0502dfSDvorskiy, Mikhail private:
2995b0502dfSDvorskiy, Mikhail // setters
inc_alive_objectsMemoryChecker3005b0502dfSDvorskiy, Mikhail void inc_alive_objects() { alive_object_counter.fetch_add(1); }
dec_alive_objectsMemoryChecker3015b0502dfSDvorskiy, Mikhail void dec_alive_objects() { alive_object_counter.fetch_sub(1); }
3025b0502dfSDvorskiy, Mikhail };
3035b0502dfSDvorskiy, Mikhail
3045b0502dfSDvorskiy, Mikhail std::atomic<std::int64_t> MemoryChecker::alive_object_counter{0};
3055b0502dfSDvorskiy, Mikhail
3065b0502dfSDvorskiy, Mikhail std::ostream& operator<<(std::ostream& os, const MemoryChecker& val) { return (os << val.value()); }
3075b0502dfSDvorskiy, Mikhail bool operator==(const MemoryChecker& v1, const MemoryChecker& v2) { return v1.value() == v2.value(); }
3085b0502dfSDvorskiy, Mikhail bool operator<(const MemoryChecker& v1, const MemoryChecker& v2) { return v1.value() < v2.value(); }
3095b0502dfSDvorskiy, Mikhail
3103b62047bSLouis Dionne // Sequence<T> is a container of a sequence of T with lots of kinds of iterators.
3113b62047bSLouis Dionne // Prefixes on begin/end mean:
3123b62047bSLouis Dionne // c = "const"
3133b62047bSLouis Dionne // f = "forward"
3143b62047bSLouis Dionne // No prefix indicates non-const random-access iterator.
3153b62047bSLouis Dionne template <typename T>
3163b62047bSLouis Dionne class Sequence
3173b62047bSLouis Dionne {
3183b62047bSLouis Dionne std::vector<T> m_storage;
3193b62047bSLouis Dionne
3203b62047bSLouis Dionne public:
3213b62047bSLouis Dionne typedef typename std::vector<T>::iterator iterator;
3223b62047bSLouis Dionne typedef typename std::vector<T>::const_iterator const_iterator;
3233b62047bSLouis Dionne typedef ForwardIterator<iterator, std::forward_iterator_tag> forward_iterator;
3243b62047bSLouis Dionne typedef ForwardIterator<const_iterator, std::forward_iterator_tag> const_forward_iterator;
3253b62047bSLouis Dionne
3263b62047bSLouis Dionne typedef BidirectionalIterator<iterator, std::bidirectional_iterator_tag> bidirectional_iterator;
3273b62047bSLouis Dionne typedef BidirectionalIterator<const_iterator, std::bidirectional_iterator_tag> const_bidirectional_iterator;
3283b62047bSLouis Dionne
3293b62047bSLouis Dionne typedef T value_type;
Sequence(size_t size)3303b62047bSLouis Dionne explicit Sequence(size_t size) : m_storage(size) {}
3313b62047bSLouis Dionne
3323b62047bSLouis Dionne // Construct sequence [f(0), f(1), ... f(size-1)]
3333b62047bSLouis Dionne // f can rely on its invocations being sequential from 0 to size-1.
3343b62047bSLouis Dionne template <typename Func>
Sequence(size_t size,Func f)3353b62047bSLouis Dionne Sequence(size_t size, Func f)
3363b62047bSLouis Dionne {
3373b62047bSLouis Dionne m_storage.reserve(size);
3383b62047bSLouis Dionne // Use push_back because T might not have a default constructor
3393b62047bSLouis Dionne for (size_t k = 0; k < size; ++k)
3403b62047bSLouis Dionne m_storage.push_back(T(f(k)));
3413b62047bSLouis Dionne }
Sequence(const std::initializer_list<T> & data)3423b62047bSLouis Dionne Sequence(const std::initializer_list<T>& data) : m_storage(data) {}
3433b62047bSLouis Dionne
3443b62047bSLouis Dionne const_iterator
begin()3453b62047bSLouis Dionne begin() const
3463b62047bSLouis Dionne {
3473b62047bSLouis Dionne return m_storage.begin();
3483b62047bSLouis Dionne }
3493b62047bSLouis Dionne const_iterator
end()3503b62047bSLouis Dionne end() const
3513b62047bSLouis Dionne {
3523b62047bSLouis Dionne return m_storage.end();
3533b62047bSLouis Dionne }
3543b62047bSLouis Dionne iterator
begin()3553b62047bSLouis Dionne begin()
3563b62047bSLouis Dionne {
3573b62047bSLouis Dionne return m_storage.begin();
3583b62047bSLouis Dionne }
3593b62047bSLouis Dionne iterator
end()3603b62047bSLouis Dionne end()
3613b62047bSLouis Dionne {
3623b62047bSLouis Dionne return m_storage.end();
3633b62047bSLouis Dionne }
3643b62047bSLouis Dionne const_iterator
cbegin()3653b62047bSLouis Dionne cbegin() const
3663b62047bSLouis Dionne {
3673b62047bSLouis Dionne return m_storage.cbegin();
3683b62047bSLouis Dionne }
3693b62047bSLouis Dionne const_iterator
cend()3703b62047bSLouis Dionne cend() const
3713b62047bSLouis Dionne {
3723b62047bSLouis Dionne return m_storage.cend();
3733b62047bSLouis Dionne }
3743b62047bSLouis Dionne forward_iterator
fbegin()3753b62047bSLouis Dionne fbegin()
3763b62047bSLouis Dionne {
3773b62047bSLouis Dionne return forward_iterator(m_storage.begin());
3783b62047bSLouis Dionne }
3793b62047bSLouis Dionne forward_iterator
fend()3803b62047bSLouis Dionne fend()
3813b62047bSLouis Dionne {
3823b62047bSLouis Dionne return forward_iterator(m_storage.end());
3833b62047bSLouis Dionne }
3843b62047bSLouis Dionne const_forward_iterator
cfbegin()3853b62047bSLouis Dionne cfbegin() const
3863b62047bSLouis Dionne {
3873b62047bSLouis Dionne return const_forward_iterator(m_storage.cbegin());
3883b62047bSLouis Dionne }
3893b62047bSLouis Dionne const_forward_iterator
cfend()3903b62047bSLouis Dionne cfend() const
3913b62047bSLouis Dionne {
3923b62047bSLouis Dionne return const_forward_iterator(m_storage.cend());
3933b62047bSLouis Dionne }
3943b62047bSLouis Dionne const_forward_iterator
fbegin()3953b62047bSLouis Dionne fbegin() const
3963b62047bSLouis Dionne {
3973b62047bSLouis Dionne return const_forward_iterator(m_storage.cbegin());
3983b62047bSLouis Dionne }
3993b62047bSLouis Dionne const_forward_iterator
fend()4003b62047bSLouis Dionne fend() const
4013b62047bSLouis Dionne {
4023b62047bSLouis Dionne return const_forward_iterator(m_storage.cend());
4033b62047bSLouis Dionne }
4043b62047bSLouis Dionne
4053b62047bSLouis Dionne const_bidirectional_iterator
cbibegin()4063b62047bSLouis Dionne cbibegin() const
4073b62047bSLouis Dionne {
4083b62047bSLouis Dionne return const_bidirectional_iterator(m_storage.cbegin());
4093b62047bSLouis Dionne }
4103b62047bSLouis Dionne const_bidirectional_iterator
cbiend()4113b62047bSLouis Dionne cbiend() const
4123b62047bSLouis Dionne {
4133b62047bSLouis Dionne return const_bidirectional_iterator(m_storage.cend());
4143b62047bSLouis Dionne }
4153b62047bSLouis Dionne
4163b62047bSLouis Dionne bidirectional_iterator
bibegin()4173b62047bSLouis Dionne bibegin()
4183b62047bSLouis Dionne {
4193b62047bSLouis Dionne return bidirectional_iterator(m_storage.begin());
4203b62047bSLouis Dionne }
4213b62047bSLouis Dionne bidirectional_iterator
biend()4223b62047bSLouis Dionne biend()
4233b62047bSLouis Dionne {
4243b62047bSLouis Dionne return bidirectional_iterator(m_storage.end());
4253b62047bSLouis Dionne }
4263b62047bSLouis Dionne
4273b62047bSLouis Dionne std::size_t
size()4283b62047bSLouis Dionne size() const
4293b62047bSLouis Dionne {
4303b62047bSLouis Dionne return m_storage.size();
4313b62047bSLouis Dionne }
4323b62047bSLouis Dionne const T*
data()4333b62047bSLouis Dionne data() const
4343b62047bSLouis Dionne {
4353b62047bSLouis Dionne return m_storage.data();
4363b62047bSLouis Dionne }
4373b62047bSLouis Dionne typename std::vector<T>::reference operator[](size_t j) { return m_storage[j]; }
4383b62047bSLouis Dionne const T& operator[](size_t j) const { return m_storage[j]; }
4393b62047bSLouis Dionne
4403b62047bSLouis Dionne // Fill with given value
4413b62047bSLouis Dionne void
fill(const T & value)4423b62047bSLouis Dionne fill(const T& value)
4433b62047bSLouis Dionne {
4443b62047bSLouis Dionne for (size_t i = 0; i < m_storage.size(); i++)
4453b62047bSLouis Dionne m_storage[i] = value;
4463b62047bSLouis Dionne }
4473b62047bSLouis Dionne
4483b62047bSLouis Dionne void
4493b62047bSLouis Dionne print() const;
4503b62047bSLouis Dionne
4513b62047bSLouis Dionne template <typename Func>
4523b62047bSLouis Dionne void
fill(Func f)4533b62047bSLouis Dionne fill(Func f)
4543b62047bSLouis Dionne {
4553b62047bSLouis Dionne fill_data(m_storage.begin(), m_storage.end(), f);
4563b62047bSLouis Dionne }
4573b62047bSLouis Dionne };
4583b62047bSLouis Dionne
4593b62047bSLouis Dionne template <typename T>
4603b62047bSLouis Dionne void
print()4613b62047bSLouis Dionne Sequence<T>::print() const
4623b62047bSLouis Dionne {
4633b62047bSLouis Dionne std::cout << "size = " << size() << ": { ";
4643b62047bSLouis Dionne std::copy(begin(), end(), std::ostream_iterator<T>(std::cout, " "));
4653b62047bSLouis Dionne std::cout << " } " << std::endl;
4663b62047bSLouis Dionne }
4673b62047bSLouis Dionne
4683b62047bSLouis Dionne // Predicates for algorithms
4693b62047bSLouis Dionne template <typename DataType>
4703b62047bSLouis Dionne struct is_equal_to
4713b62047bSLouis Dionne {
is_equal_tois_equal_to4723b62047bSLouis Dionne is_equal_to(const DataType& expected) : m_expected(expected) {}
4733b62047bSLouis Dionne bool
operatoris_equal_to4743b62047bSLouis Dionne operator()(const DataType& actual) const
4753b62047bSLouis Dionne {
4763b62047bSLouis Dionne return actual == m_expected;
4773b62047bSLouis Dionne }
4783b62047bSLouis Dionne
4793b62047bSLouis Dionne private:
4803b62047bSLouis Dionne DataType m_expected;
4813b62047bSLouis Dionne };
4823b62047bSLouis Dionne
4833b62047bSLouis Dionne // Low-quality hash function, returns value between 0 and (1<<bits)-1
4843b62047bSLouis Dionne // Warning: low-order bits are quite predictable.
4853b62047bSLouis Dionne inline size_t
HashBits(size_t i,size_t bits)4863b62047bSLouis Dionne HashBits(size_t i, size_t bits)
4873b62047bSLouis Dionne {
4883b62047bSLouis Dionne size_t mask = bits >= 8 * sizeof(size_t) ? ~size_t(0) : (size_t(1) << bits) - 1;
4893b62047bSLouis Dionne return (424157 * i ^ 0x24aFa) & mask;
4903b62047bSLouis Dionne }
4913b62047bSLouis Dionne
4923b62047bSLouis Dionne // Stateful unary op
4933b62047bSLouis Dionne template <typename T, typename U>
4943b62047bSLouis Dionne class Complement
4953b62047bSLouis Dionne {
4963b62047bSLouis Dionne int32_t val;
4973b62047bSLouis Dionne
4983b62047bSLouis Dionne public:
Complement(T v)4993b62047bSLouis Dionne Complement(T v) : val(v) {}
5003b62047bSLouis Dionne U
operator()5013b62047bSLouis Dionne operator()(const T& x) const
5023b62047bSLouis Dionne {
5033b62047bSLouis Dionne return U(val - x);
5043b62047bSLouis Dionne }
5053b62047bSLouis Dionne };
5063b62047bSLouis Dionne
5073b62047bSLouis Dionne // Tag used to prevent accidental use of converting constructor, even if use is explicit.
5083b62047bSLouis Dionne struct OddTag
5093b62047bSLouis Dionne {
5103b62047bSLouis Dionne };
5113b62047bSLouis Dionne
5123b62047bSLouis Dionne class Sum;
5133b62047bSLouis Dionne
5143b62047bSLouis Dionne // Type with limited set of operations. Not default-constructible.
5153b62047bSLouis Dionne // Only available operator is "==".
5163b62047bSLouis Dionne // Typically used as value type in tests.
5173b62047bSLouis Dionne class Number
5183b62047bSLouis Dionne {
5193b62047bSLouis Dionne int32_t value;
5203b62047bSLouis Dionne friend class Add;
5213b62047bSLouis Dionne friend class Sum;
5223b62047bSLouis Dionne friend class IsMultiple;
5233b62047bSLouis Dionne friend class Congruent;
5243b62047bSLouis Dionne friend Sum
5253b62047bSLouis Dionne operator+(const Sum& x, const Sum& y);
5263b62047bSLouis Dionne
5273b62047bSLouis Dionne public:
Number(int32_t val,OddTag)5283b62047bSLouis Dionne Number(int32_t val, OddTag) : value(val) {}
5293b62047bSLouis Dionne friend bool
5303b62047bSLouis Dionne operator==(const Number& x, const Number& y)
5313b62047bSLouis Dionne {
5323b62047bSLouis Dionne return x.value == y.value;
5333b62047bSLouis Dionne }
5343b62047bSLouis Dionne friend std::ostream&
5353b62047bSLouis Dionne operator<<(std::ostream& o, const Number& d)
5363b62047bSLouis Dionne {
5373b62047bSLouis Dionne return o << d.value;
5383b62047bSLouis Dionne }
5393b62047bSLouis Dionne };
5403b62047bSLouis Dionne
5413b62047bSLouis Dionne // Stateful predicate for Number. Not default-constructible.
5423b62047bSLouis Dionne class IsMultiple
5433b62047bSLouis Dionne {
5443b62047bSLouis Dionne long modulus;
5453b62047bSLouis Dionne
5463b62047bSLouis Dionne public:
5473b62047bSLouis Dionne // True if x is multiple of modulus
5483b62047bSLouis Dionne bool
operator()5493b62047bSLouis Dionne operator()(Number x) const
5503b62047bSLouis Dionne {
5513b62047bSLouis Dionne return x.value % modulus == 0;
5523b62047bSLouis Dionne }
IsMultiple(long modulus_,OddTag)5533b62047bSLouis Dionne IsMultiple(long modulus_, OddTag) : modulus(modulus_) {}
5543b62047bSLouis Dionne };
5553b62047bSLouis Dionne
5563b62047bSLouis Dionne // Stateful equivalence-class predicate for Number. Not default-constructible.
5573b62047bSLouis Dionne class Congruent
5583b62047bSLouis Dionne {
5593b62047bSLouis Dionne long modulus;
5603b62047bSLouis Dionne
5613b62047bSLouis Dionne public:
5623b62047bSLouis Dionne // True if x and y have same remainder for the given modulus.
5633b62047bSLouis Dionne // Note: this is not quite the same as "equivalent modulo modulus" when x and y have different
5643b62047bSLouis Dionne // sign, but nonetheless AreCongruent is still an equivalence relationship, which is all
5653b62047bSLouis Dionne // we need for testing.
5663b62047bSLouis Dionne bool
operator()5673b62047bSLouis Dionne operator()(Number x, Number y) const
5683b62047bSLouis Dionne {
5693b62047bSLouis Dionne return x.value % modulus == y.value % modulus;
5703b62047bSLouis Dionne }
Congruent(long modulus_,OddTag)5713b62047bSLouis Dionne Congruent(long modulus_, OddTag) : modulus(modulus_) {}
5723b62047bSLouis Dionne };
5733b62047bSLouis Dionne
5743b62047bSLouis Dionne // Stateful reduction operation for Number
5753b62047bSLouis Dionne class Add
5763b62047bSLouis Dionne {
5773b62047bSLouis Dionne long bias;
5783b62047bSLouis Dionne
5793b62047bSLouis Dionne public:
Add(OddTag)5803b62047bSLouis Dionne explicit Add(OddTag) : bias(1) {}
5813b62047bSLouis Dionne Number
operator()5823b62047bSLouis Dionne operator()(Number x, const Number& y)
5833b62047bSLouis Dionne {
5843b62047bSLouis Dionne return Number(x.value + y.value + (bias - 1), OddTag());
5853b62047bSLouis Dionne }
5863b62047bSLouis Dionne };
5873b62047bSLouis Dionne
5883b62047bSLouis Dionne // Class similar to Number, but has default constructor and +.
5893b62047bSLouis Dionne class Sum : public Number
5903b62047bSLouis Dionne {
5913b62047bSLouis Dionne public:
Sum()5923b62047bSLouis Dionne Sum() : Number(0, OddTag()) {}
Sum(long x,OddTag)5933b62047bSLouis Dionne Sum(long x, OddTag) : Number(x, OddTag()) {}
5943b62047bSLouis Dionne friend Sum
5953b62047bSLouis Dionne operator+(const Sum& x, const Sum& y)
5963b62047bSLouis Dionne {
5973b62047bSLouis Dionne return Sum(x.value + y.value, OddTag());
5983b62047bSLouis Dionne }
5993b62047bSLouis Dionne };
6003b62047bSLouis Dionne
6013b62047bSLouis Dionne // Type with limited set of operations, which includes an associative but not commutative operation.
6023b62047bSLouis Dionne // Not default-constructible.
6033b62047bSLouis Dionne // Typically used as value type in tests involving "GENERALIZED_NONCOMMUTATIVE_SUM".
6043b62047bSLouis Dionne class MonoidElement
6053b62047bSLouis Dionne {
6063b62047bSLouis Dionne size_t a, b;
6073b62047bSLouis Dionne
6083b62047bSLouis Dionne public:
MonoidElement(size_t a_,size_t b_,OddTag)6093b62047bSLouis Dionne MonoidElement(size_t a_, size_t b_, OddTag) : a(a_), b(b_) {}
6103b62047bSLouis Dionne friend bool
6113b62047bSLouis Dionne operator==(const MonoidElement& x, const MonoidElement& y)
6123b62047bSLouis Dionne {
6133b62047bSLouis Dionne return x.a == y.a && x.b == y.b;
6143b62047bSLouis Dionne }
6153b62047bSLouis Dionne friend std::ostream&
6163b62047bSLouis Dionne operator<<(std::ostream& o, const MonoidElement& x)
6173b62047bSLouis Dionne {
6183b62047bSLouis Dionne return o << "[" << x.a << ".." << x.b << ")";
6193b62047bSLouis Dionne }
6203b62047bSLouis Dionne friend class AssocOp;
6213b62047bSLouis Dionne };
6223b62047bSLouis Dionne
6233b62047bSLouis Dionne // Stateful associative op for MonoidElement
6243b62047bSLouis Dionne // It's not really a monoid since the operation is not allowed for any two elements.
6253b62047bSLouis Dionne // But it's good enough for testing.
6263b62047bSLouis Dionne class AssocOp
6273b62047bSLouis Dionne {
6283b62047bSLouis Dionne unsigned c;
6293b62047bSLouis Dionne
6303b62047bSLouis Dionne public:
AssocOp(OddTag)6313b62047bSLouis Dionne explicit AssocOp(OddTag) : c(5) {}
6323b62047bSLouis Dionne MonoidElement
operator()6333b62047bSLouis Dionne operator()(const MonoidElement& x, const MonoidElement& y)
6343b62047bSLouis Dionne {
6353b62047bSLouis Dionne unsigned d = 5;
6363b62047bSLouis Dionne EXPECT_EQ(d, c, "state lost");
6373b62047bSLouis Dionne EXPECT_EQ(x.b, y.a, "commuted?");
6383b62047bSLouis Dionne
6393b62047bSLouis Dionne return MonoidElement(x.a, y.b, OddTag());
6403b62047bSLouis Dionne }
6413b62047bSLouis Dionne };
6423b62047bSLouis Dionne
6433b62047bSLouis Dionne // Multiplication of matrix is an associative but not commutative operation
6443b62047bSLouis Dionne // Typically used as value type in tests involving "GENERALIZED_NONCOMMUTATIVE_SUM".
6453b62047bSLouis Dionne template <typename T>
6463b62047bSLouis Dionne struct Matrix2x2
6473b62047bSLouis Dionne {
6483b62047bSLouis Dionne T a[2][2];
Matrix2x2Matrix2x26493b62047bSLouis Dionne Matrix2x2() : a{{1, 0}, {0, 1}} {}
Matrix2x2Matrix2x26503b62047bSLouis Dionne Matrix2x2(T x, T y) : a{{0, x}, {x, y}} {}
6513b9a1bb1SLouis Dionne #if !defined(_PSTL_ICL_19_VC14_VC141_TEST_SCAN_RELEASE_BROKEN)
Matrix2x2Matrix2x26523b62047bSLouis Dionne Matrix2x2(const Matrix2x2& m) : a{{m.a[0][0], m.a[0][1]}, {m.a[1][0], m.a[1][1]}} {}
6533b62047bSLouis Dionne Matrix2x2&
6543b62047bSLouis Dionne operator=(const Matrix2x2& m)
6553b62047bSLouis Dionne {
6563b62047bSLouis Dionne a[0][0] = m.a[0][0], a[0][1] = m.a[0][1], a[1][0] = m.a[1][0], a[1][1] = m.a[1][1];
6573b62047bSLouis Dionne return *this;
6583b62047bSLouis Dionne }
6593b62047bSLouis Dionne #endif
6603b62047bSLouis Dionne };
6613b62047bSLouis Dionne
6623b62047bSLouis Dionne template <typename T>
6633b62047bSLouis Dionne bool
6643b62047bSLouis Dionne operator==(const Matrix2x2<T>& left, const Matrix2x2<T>& right)
6653b62047bSLouis Dionne {
6663b62047bSLouis Dionne return left.a[0][0] == right.a[0][0] && left.a[0][1] == right.a[0][1] && left.a[1][0] == right.a[1][0] &&
6673b62047bSLouis Dionne left.a[1][1] == right.a[1][1];
6683b62047bSLouis Dionne }
6693b62047bSLouis Dionne
6703b62047bSLouis Dionne template <typename T>
6713b62047bSLouis Dionne Matrix2x2<T>
multiply_matrix(const Matrix2x2<T> & left,const Matrix2x2<T> & right)6723b62047bSLouis Dionne multiply_matrix(const Matrix2x2<T>& left, const Matrix2x2<T>& right)
6733b62047bSLouis Dionne {
6743b62047bSLouis Dionne Matrix2x2<T> result;
6753b62047bSLouis Dionne for (int32_t i = 0; i < 2; ++i)
6763b62047bSLouis Dionne {
6773b62047bSLouis Dionne for (int32_t j = 0; j < 2; ++j)
6783b62047bSLouis Dionne {
6793b62047bSLouis Dionne result.a[i][j] = left.a[i][0] * right.a[0][j] + left.a[i][1] * right.a[1][j];
6803b62047bSLouis Dionne }
6813b62047bSLouis Dionne }
6823b62047bSLouis Dionne return result;
6833b62047bSLouis Dionne }
6843b62047bSLouis Dionne
6853b62047bSLouis Dionne //============================================================================
6863b62047bSLouis Dionne // Adapters for creating different types of iterators.
6873b62047bSLouis Dionne //
6883b62047bSLouis Dionne // In this block we implemented some adapters for creating differnet types of iterators.
6893b62047bSLouis Dionne // It's needed for extending the unit testing of Parallel STL algorithms.
6903b62047bSLouis Dionne // We have adapters for iterators with different tags (forward_iterator_tag, bidirectional_iterator_tag), reverse iterators.
6913b62047bSLouis Dionne // The input iterator should be const or non-const, non-reverse random access iterator.
6923b62047bSLouis Dionne // Iterator creates in "MakeIterator":
6933b62047bSLouis Dionne // firstly, iterator is "packed" by "IteratorTypeAdapter" (creating forward or bidirectional iterator)
6943b62047bSLouis Dionne // then iterator is "packed" by "ReverseAdapter" (if it's possible)
6953b62047bSLouis Dionne // So, from input iterator we may create, for example, reverse bidirectional iterator.
6963b62047bSLouis Dionne // "Main" functor for testing iterators is named "invoke_on_all_iterator_types".
6973b62047bSLouis Dionne
6983b62047bSLouis Dionne // Base adapter
6993b62047bSLouis Dionne template <typename Iterator>
7003b62047bSLouis Dionne struct BaseAdapter
7013b62047bSLouis Dionne {
7023b62047bSLouis Dionne typedef Iterator iterator_type;
7033b62047bSLouis Dionne iterator_type
operatorBaseAdapter7043b62047bSLouis Dionne operator()(Iterator it)
7053b62047bSLouis Dionne {
7063b62047bSLouis Dionne return it;
7073b62047bSLouis Dionne }
7083b62047bSLouis Dionne };
7093b62047bSLouis Dionne
7103b62047bSLouis Dionne // Check if the iterator is reverse iterator
7113b62047bSLouis Dionne // Note: it works only for iterators that created by std::reverse_iterator
7123b62047bSLouis Dionne template <typename NotReverseIterator>
7133b62047bSLouis Dionne struct isReverse : std::false_type
7143b62047bSLouis Dionne {
7153b62047bSLouis Dionne };
7163b62047bSLouis Dionne
7173b62047bSLouis Dionne template <typename Iterator>
7183b62047bSLouis Dionne struct isReverse<std::reverse_iterator<Iterator>> : std::true_type
7193b62047bSLouis Dionne {
7203b62047bSLouis Dionne };
7213b62047bSLouis Dionne
7223b62047bSLouis Dionne // Reverse adapter
7233b62047bSLouis Dionne template <typename Iterator, typename IsReverse>
7243b62047bSLouis Dionne struct ReverseAdapter
7253b62047bSLouis Dionne {
7263b62047bSLouis Dionne typedef std::reverse_iterator<Iterator> iterator_type;
7273b62047bSLouis Dionne iterator_type
7283b62047bSLouis Dionne operator()(Iterator it)
7293b62047bSLouis Dionne {
7303b9a1bb1SLouis Dionne #if defined(_PSTL_CPP14_MAKE_REVERSE_ITERATOR_PRESENT)
7313b62047bSLouis Dionne return std::make_reverse_iterator(it);
7323b62047bSLouis Dionne #else
7333b62047bSLouis Dionne return iterator_type(it);
7343b62047bSLouis Dionne #endif
7353b62047bSLouis Dionne }
7363b62047bSLouis Dionne };
7373b62047bSLouis Dionne
7383b62047bSLouis Dionne // Non-reverse adapter
7393b62047bSLouis Dionne template <typename Iterator>
7403b62047bSLouis Dionne struct ReverseAdapter<Iterator, std::false_type> : BaseAdapter<Iterator>
7413b62047bSLouis Dionne {
7423b62047bSLouis Dionne };
7433b62047bSLouis Dionne
7443b62047bSLouis Dionne // Iterator adapter by type (by default std::random_access_iterator_tag)
7453b62047bSLouis Dionne template <typename Iterator, typename IteratorTag>
7463b62047bSLouis Dionne struct IteratorTypeAdapter : BaseAdapter<Iterator>
7473b62047bSLouis Dionne {
7483b62047bSLouis Dionne };
7493b62047bSLouis Dionne
7503b62047bSLouis Dionne // Iterator adapter for forward iterator
7513b62047bSLouis Dionne template <typename Iterator>
7523b62047bSLouis Dionne struct IteratorTypeAdapter<Iterator, std::forward_iterator_tag>
7533b62047bSLouis Dionne {
7543b62047bSLouis Dionne typedef ForwardIterator<Iterator, std::forward_iterator_tag> iterator_type;
7553b62047bSLouis Dionne iterator_type
7563b62047bSLouis Dionne operator()(Iterator it)
7573b62047bSLouis Dionne {
7583b62047bSLouis Dionne return iterator_type(it);
7593b62047bSLouis Dionne }
7603b62047bSLouis Dionne };
7613b62047bSLouis Dionne
7623b62047bSLouis Dionne // Iterator adapter for bidirectional iterator
7633b62047bSLouis Dionne template <typename Iterator>
7643b62047bSLouis Dionne struct IteratorTypeAdapter<Iterator, std::bidirectional_iterator_tag>
7653b62047bSLouis Dionne {
7663b62047bSLouis Dionne typedef BidirectionalIterator<Iterator, std::bidirectional_iterator_tag> iterator_type;
7673b62047bSLouis Dionne iterator_type
7683b62047bSLouis Dionne operator()(Iterator it)
7693b62047bSLouis Dionne {
7703b62047bSLouis Dionne return iterator_type(it);
7713b62047bSLouis Dionne }
7723b62047bSLouis Dionne };
7733b62047bSLouis Dionne
7743b62047bSLouis Dionne //For creating iterator with new type
7753b62047bSLouis Dionne template <typename InputIterator, typename IteratorTag, typename IsReverse>
7763b62047bSLouis Dionne struct MakeIterator
7773b62047bSLouis Dionne {
7783b62047bSLouis Dionne typedef IteratorTypeAdapter<InputIterator, IteratorTag> IterByType;
7793b62047bSLouis Dionne typedef ReverseAdapter<typename IterByType::iterator_type, IsReverse> ReverseIter;
7803b62047bSLouis Dionne
7813b62047bSLouis Dionne typename ReverseIter::iterator_type
7823b62047bSLouis Dionne operator()(InputIterator it)
7833b62047bSLouis Dionne {
7843b62047bSLouis Dionne return ReverseIter()(IterByType()(it));
7853b62047bSLouis Dionne }
7863b62047bSLouis Dionne };
7873b62047bSLouis Dionne
7883b62047bSLouis Dionne // Useful constant variables
7893b62047bSLouis Dionne constexpr std::size_t GuardSize = 5;
7903b62047bSLouis Dionne constexpr std::ptrdiff_t sizeLimit = 1000;
7913b62047bSLouis Dionne
7923b62047bSLouis Dionne template <typename Iter, typename Void = void> // local iterator_traits for non-iterators
7933b62047bSLouis Dionne struct iterator_traits_
7943b62047bSLouis Dionne {
7953b62047bSLouis Dionne };
7963b62047bSLouis Dionne
7973b62047bSLouis Dionne template <typename Iter> // For iterators
7983b62047bSLouis Dionne struct iterator_traits_<Iter,
7993b62047bSLouis Dionne typename std::enable_if<!std::is_void<typename Iter::iterator_category>::value, void>::type>
8003b62047bSLouis Dionne {
8013b62047bSLouis Dionne typedef typename Iter::iterator_category iterator_category;
8023b62047bSLouis Dionne };
8033b62047bSLouis Dionne
8043b62047bSLouis Dionne template <typename T> // For pointers
8053b62047bSLouis Dionne struct iterator_traits_<T*>
8063b62047bSLouis Dionne {
8073b62047bSLouis Dionne typedef std::random_access_iterator_tag iterator_category;
8083b62047bSLouis Dionne };
8093b62047bSLouis Dionne
8103b62047bSLouis Dionne // is iterator Iter has tag Tag
8113b62047bSLouis Dionne template <typename Iter, typename Tag>
8123b62047bSLouis Dionne using is_same_iterator_category = std::is_same<typename iterator_traits_<Iter>::iterator_category, Tag>;
8133b62047bSLouis Dionne
8143b62047bSLouis Dionne // if we run with reverse or const iterators we shouldn't test the large range
8153b62047bSLouis Dionne template <typename IsReverse, typename IsConst>
8163b62047bSLouis Dionne struct invoke_if_
8173b62047bSLouis Dionne {
8183b62047bSLouis Dionne template <typename Op, typename... Rest>
8193b62047bSLouis Dionne void
8203b62047bSLouis Dionne operator()(bool is_allow, Op op, Rest&&... rest)
8213b62047bSLouis Dionne {
8223b62047bSLouis Dionne if (is_allow)
8233b62047bSLouis Dionne op(std::forward<Rest>(rest)...);
8243b62047bSLouis Dionne }
8253b62047bSLouis Dionne };
8263b62047bSLouis Dionne template <>
8273b62047bSLouis Dionne struct invoke_if_<std::false_type, std::false_type>
8283b62047bSLouis Dionne {
8293b62047bSLouis Dionne template <typename Op, typename... Rest>
8303b62047bSLouis Dionne void
8315c4c4431SLouis Dionne operator()(bool, Op op, Rest&&... rest)
8323b62047bSLouis Dionne {
8333b62047bSLouis Dionne op(std::forward<Rest>(rest)...);
8343b62047bSLouis Dionne }
8353b62047bSLouis Dionne };
8363b62047bSLouis Dionne
8373b62047bSLouis Dionne // Base non_const_wrapper struct. It is used to distinguish non_const testcases
8383b62047bSLouis Dionne // from a regular one. For non_const testcases only compilation is checked.
8393b62047bSLouis Dionne struct non_const_wrapper
8403b62047bSLouis Dionne {
8413b62047bSLouis Dionne };
8423b62047bSLouis Dionne
8433b62047bSLouis Dionne // Generic wrapper to specify iterator type to execute callable Op on.
8443b62047bSLouis Dionne // The condition can be either positive(Op is executed only with IteratorTag)
8453b62047bSLouis Dionne // or negative(Op is executed with every type of iterators except IteratorTag)
8463b62047bSLouis Dionne template <typename Op, typename IteratorTag, bool IsPositiveCondition = true>
8473b62047bSLouis Dionne struct non_const_wrapper_tagged : non_const_wrapper
8483b62047bSLouis Dionne {
8493b62047bSLouis Dionne template <typename Policy, typename Iterator>
8503b62047bSLouis Dionne typename std::enable_if<IsPositiveCondition == is_same_iterator_category<Iterator, IteratorTag>::value, void>::type
8513b62047bSLouis Dionne operator()(Policy&& exec, Iterator iter)
8523b62047bSLouis Dionne {
8533b62047bSLouis Dionne Op()(exec, iter);
8543b62047bSLouis Dionne }
8553b62047bSLouis Dionne
8563b62047bSLouis Dionne template <typename Policy, typename InputIterator, typename OutputIterator>
8573b62047bSLouis Dionne typename std::enable_if<IsPositiveCondition == is_same_iterator_category<OutputIterator, IteratorTag>::value,
8583b62047bSLouis Dionne void>::type
8593b62047bSLouis Dionne operator()(Policy&& exec, InputIterator input_iter, OutputIterator out_iter)
8603b62047bSLouis Dionne {
8613b62047bSLouis Dionne Op()(exec, input_iter, out_iter);
8623b62047bSLouis Dionne }
8633b62047bSLouis Dionne
8643b62047bSLouis Dionne template <typename Policy, typename Iterator>
8653b62047bSLouis Dionne typename std::enable_if<IsPositiveCondition != is_same_iterator_category<Iterator, IteratorTag>::value, void>::type
8665c4c4431SLouis Dionne operator()(Policy&&, Iterator)
8673b62047bSLouis Dionne {
8683b62047bSLouis Dionne }
8693b62047bSLouis Dionne
8703b62047bSLouis Dionne template <typename Policy, typename InputIterator, typename OutputIterator>
8713b62047bSLouis Dionne typename std::enable_if<IsPositiveCondition != is_same_iterator_category<OutputIterator, IteratorTag>::value,
8723b62047bSLouis Dionne void>::type
8735c4c4431SLouis Dionne operator()(Policy&&, InputIterator, OutputIterator)
8743b62047bSLouis Dionne {
8753b62047bSLouis Dionne }
8763b62047bSLouis Dionne };
8773b62047bSLouis Dionne
8783b62047bSLouis Dionne // These run_for_* structures specify with which types of iterators callable object Op
8793b62047bSLouis Dionne // should be executed.
8803b62047bSLouis Dionne template <typename Op>
8813b62047bSLouis Dionne struct run_for_rnd : non_const_wrapper_tagged<Op, std::random_access_iterator_tag>
8823b62047bSLouis Dionne {
8833b62047bSLouis Dionne };
8843b62047bSLouis Dionne
8853b62047bSLouis Dionne template <typename Op>
8863b62047bSLouis Dionne struct run_for_rnd_bi : non_const_wrapper_tagged<Op, std::forward_iterator_tag, false>
8873b62047bSLouis Dionne {
8883b62047bSLouis Dionne };
8893b62047bSLouis Dionne
8903b62047bSLouis Dionne template <typename Op>
8913b62047bSLouis Dionne struct run_for_rnd_fw : non_const_wrapper_tagged<Op, std::bidirectional_iterator_tag, false>
8923b62047bSLouis Dionne {
8933b62047bSLouis Dionne };
8943b62047bSLouis Dionne
8953b62047bSLouis Dionne // Invoker for different types of iterators.
8963b62047bSLouis Dionne template <typename IteratorTag, typename IsReverse>
8973b62047bSLouis Dionne struct iterator_invoker
8983b62047bSLouis Dionne {
8993b62047bSLouis Dionne template <typename Iterator>
9003b62047bSLouis Dionne using make_iterator = MakeIterator<Iterator, IteratorTag, IsReverse>;
9013b62047bSLouis Dionne template <typename Iterator>
9023b62047bSLouis Dionne using IsConst = typename std::is_const<
9033b62047bSLouis Dionne typename std::remove_pointer<typename std::iterator_traits<Iterator>::pointer>::type>::type;
9043b62047bSLouis Dionne template <typename Iterator>
9053b62047bSLouis Dionne using invoke_if = invoke_if_<IsReverse, IsConst<Iterator>>;
9063b62047bSLouis Dionne
9073b62047bSLouis Dionne // A single iterator version which is used for non_const testcases
9083b62047bSLouis Dionne template <typename Policy, typename Op, typename Iterator>
9093b62047bSLouis Dionne typename std::enable_if<is_same_iterator_category<Iterator, std::random_access_iterator_tag>::value &&
9103b62047bSLouis Dionne std::is_base_of<non_const_wrapper, Op>::value,
9113b62047bSLouis Dionne void>::type
9123b62047bSLouis Dionne operator()(Policy&& exec, Op op, Iterator iter)
9133b62047bSLouis Dionne {
9143b62047bSLouis Dionne op(std::forward<Policy>(exec), make_iterator<Iterator>()(iter));
9153b62047bSLouis Dionne }
9163b62047bSLouis Dionne
9173b62047bSLouis Dionne // A version with 2 iterators which is used for non_const testcases
9183b62047bSLouis Dionne template <typename Policy, typename Op, typename InputIterator, typename OutputIterator>
9193b62047bSLouis Dionne typename std::enable_if<is_same_iterator_category<OutputIterator, std::random_access_iterator_tag>::value &&
9203b62047bSLouis Dionne std::is_base_of<non_const_wrapper, Op>::value,
9213b62047bSLouis Dionne void>::type
9223b62047bSLouis Dionne operator()(Policy&& exec, Op op, InputIterator input_iter, OutputIterator out_iter)
9233b62047bSLouis Dionne {
9243b62047bSLouis Dionne op(std::forward<Policy>(exec), make_iterator<InputIterator>()(input_iter),
9253b62047bSLouis Dionne make_iterator<OutputIterator>()(out_iter));
9263b62047bSLouis Dionne }
9273b62047bSLouis Dionne
9283b62047bSLouis Dionne template <typename Policy, typename Op, typename Iterator, typename Size, typename... Rest>
9293b62047bSLouis Dionne typename std::enable_if<is_same_iterator_category<Iterator, std::random_access_iterator_tag>::value, void>::type
9303b62047bSLouis Dionne operator()(Policy&& exec, Op op, Iterator begin, Size n, Rest&&... rest)
9313b62047bSLouis Dionne {
9323b62047bSLouis Dionne invoke_if<Iterator>()(n <= sizeLimit, op, exec, make_iterator<Iterator>()(begin), n,
9333b62047bSLouis Dionne std::forward<Rest>(rest)...);
9343b62047bSLouis Dionne }
9353b62047bSLouis Dionne
9363b62047bSLouis Dionne template <typename Policy, typename Op, typename Iterator, typename... Rest>
9373b62047bSLouis Dionne typename std::enable_if<is_same_iterator_category<Iterator, std::random_access_iterator_tag>::value &&
9383b62047bSLouis Dionne !std::is_base_of<non_const_wrapper, Op>::value,
9393b62047bSLouis Dionne void>::type
9403b62047bSLouis Dionne operator()(Policy&& exec, Op op, Iterator inputBegin, Iterator inputEnd, Rest&&... rest)
9413b62047bSLouis Dionne {
9423b62047bSLouis Dionne invoke_if<Iterator>()(std::distance(inputBegin, inputEnd) <= sizeLimit, op, exec,
9433b62047bSLouis Dionne make_iterator<Iterator>()(inputBegin), make_iterator<Iterator>()(inputEnd),
9443b62047bSLouis Dionne std::forward<Rest>(rest)...);
9453b62047bSLouis Dionne }
9463b62047bSLouis Dionne
9473b62047bSLouis Dionne template <typename Policy, typename Op, typename InputIterator, typename OutputIterator, typename... Rest>
9483b62047bSLouis Dionne typename std::enable_if<is_same_iterator_category<OutputIterator, std::random_access_iterator_tag>::value,
9493b62047bSLouis Dionne void>::type
9503b62047bSLouis Dionne operator()(Policy&& exec, Op op, InputIterator inputBegin, InputIterator inputEnd, OutputIterator outputBegin,
9513b62047bSLouis Dionne Rest&&... rest)
9523b62047bSLouis Dionne {
9533b62047bSLouis Dionne invoke_if<InputIterator>()(std::distance(inputBegin, inputEnd) <= sizeLimit, op, exec,
9543b62047bSLouis Dionne make_iterator<InputIterator>()(inputBegin), make_iterator<InputIterator>()(inputEnd),
9553b62047bSLouis Dionne make_iterator<OutputIterator>()(outputBegin), std::forward<Rest>(rest)...);
9563b62047bSLouis Dionne }
9573b62047bSLouis Dionne
9583b62047bSLouis Dionne template <typename Policy, typename Op, typename InputIterator, typename OutputIterator, typename... Rest>
9593b62047bSLouis Dionne typename std::enable_if<is_same_iterator_category<OutputIterator, std::random_access_iterator_tag>::value,
9603b62047bSLouis Dionne void>::type
9613b62047bSLouis Dionne operator()(Policy&& exec, Op op, InputIterator inputBegin, InputIterator inputEnd, OutputIterator outputBegin,
9623b62047bSLouis Dionne OutputIterator outputEnd, Rest&&... rest)
9633b62047bSLouis Dionne {
9643b62047bSLouis Dionne invoke_if<InputIterator>()(std::distance(inputBegin, inputEnd) <= sizeLimit, op, exec,
9653b62047bSLouis Dionne make_iterator<InputIterator>()(inputBegin), make_iterator<InputIterator>()(inputEnd),
9663b62047bSLouis Dionne make_iterator<OutputIterator>()(outputBegin),
9673b62047bSLouis Dionne make_iterator<OutputIterator>()(outputEnd), std::forward<Rest>(rest)...);
9683b62047bSLouis Dionne }
9693b62047bSLouis Dionne
9703b62047bSLouis Dionne template <typename Policy, typename Op, typename InputIterator1, typename InputIterator2, typename OutputIterator,
9713b62047bSLouis Dionne typename... Rest>
9723b62047bSLouis Dionne typename std::enable_if<is_same_iterator_category<OutputIterator, std::random_access_iterator_tag>::value,
9733b62047bSLouis Dionne void>::type
9743b62047bSLouis Dionne operator()(Policy&& exec, Op op, InputIterator1 inputBegin1, InputIterator1 inputEnd1, InputIterator2 inputBegin2,
9753b62047bSLouis Dionne InputIterator2 inputEnd2, OutputIterator outputBegin, OutputIterator outputEnd, Rest&&... rest)
9763b62047bSLouis Dionne {
9773b62047bSLouis Dionne invoke_if<InputIterator1>()(
9783b62047bSLouis Dionne std::distance(inputBegin1, inputEnd1) <= sizeLimit, op, exec, make_iterator<InputIterator1>()(inputBegin1),
9793b62047bSLouis Dionne make_iterator<InputIterator1>()(inputEnd1), make_iterator<InputIterator2>()(inputBegin2),
9803b62047bSLouis Dionne make_iterator<InputIterator2>()(inputEnd2), make_iterator<OutputIterator>()(outputBegin),
9813b62047bSLouis Dionne make_iterator<OutputIterator>()(outputEnd), std::forward<Rest>(rest)...);
9823b62047bSLouis Dionne }
9833b62047bSLouis Dionne };
9843b62047bSLouis Dionne
9853b62047bSLouis Dionne // Invoker for reverse iterators only
9863b62047bSLouis Dionne // Note: if we run with reverse iterators we shouldn't test the large range
9873b62047bSLouis Dionne template <typename IteratorTag>
9883b62047bSLouis Dionne struct iterator_invoker<IteratorTag, /* IsReverse = */ std::true_type>
9893b62047bSLouis Dionne {
9903b62047bSLouis Dionne
9913b62047bSLouis Dionne template <typename Iterator>
9923b62047bSLouis Dionne using make_iterator = MakeIterator<Iterator, IteratorTag, std::true_type>;
9933b62047bSLouis Dionne
9943b62047bSLouis Dionne // A single iterator version which is used for non_const testcases
9953b62047bSLouis Dionne template <typename Policy, typename Op, typename Iterator>
9963b62047bSLouis Dionne typename std::enable_if<is_same_iterator_category<Iterator, std::random_access_iterator_tag>::value &&
9973b62047bSLouis Dionne std::is_base_of<non_const_wrapper, Op>::value,
9983b62047bSLouis Dionne void>::type
9993b62047bSLouis Dionne operator()(Policy&& exec, Op op, Iterator iter)
10003b62047bSLouis Dionne {
10013b62047bSLouis Dionne op(std::forward<Policy>(exec), make_iterator<Iterator>()(iter));
10023b62047bSLouis Dionne }
10033b62047bSLouis Dionne
10043b62047bSLouis Dionne // A version with 2 iterators which is used for non_const testcases
10053b62047bSLouis Dionne template <typename Policy, typename Op, typename InputIterator, typename OutputIterator>
10063b62047bSLouis Dionne typename std::enable_if<is_same_iterator_category<OutputIterator, std::random_access_iterator_tag>::value &&
10073b62047bSLouis Dionne std::is_base_of<non_const_wrapper, Op>::value,
10083b62047bSLouis Dionne void>::type
10093b62047bSLouis Dionne operator()(Policy&& exec, Op op, InputIterator input_iter, OutputIterator out_iter)
10103b62047bSLouis Dionne {
10113b62047bSLouis Dionne op(std::forward<Policy>(exec), make_iterator<InputIterator>()(input_iter),
10123b62047bSLouis Dionne make_iterator<OutputIterator>()(out_iter));
10133b62047bSLouis Dionne }
10143b62047bSLouis Dionne
10153b62047bSLouis Dionne template <typename Policy, typename Op, typename Iterator, typename Size, typename... Rest>
10163b62047bSLouis Dionne typename std::enable_if<is_same_iterator_category<Iterator, std::random_access_iterator_tag>::value, void>::type
10173b62047bSLouis Dionne operator()(Policy&& exec, Op op, Iterator begin, Size n, Rest&&... rest)
10183b62047bSLouis Dionne {
10193b62047bSLouis Dionne if (n <= sizeLimit)
10203b62047bSLouis Dionne op(exec, make_iterator<Iterator>()(begin + n), n, std::forward<Rest>(rest)...);
10213b62047bSLouis Dionne }
10223b62047bSLouis Dionne
10233b62047bSLouis Dionne template <typename Policy, typename Op, typename Iterator, typename... Rest>
10243b62047bSLouis Dionne typename std::enable_if<is_same_iterator_category<Iterator, std::random_access_iterator_tag>::value &&
10253b62047bSLouis Dionne !std::is_base_of<non_const_wrapper, Op>::value,
10263b62047bSLouis Dionne void>::type
10273b62047bSLouis Dionne operator()(Policy&& exec, Op op, Iterator inputBegin, Iterator inputEnd, Rest&&... rest)
10283b62047bSLouis Dionne {
10293b62047bSLouis Dionne if (std::distance(inputBegin, inputEnd) <= sizeLimit)
10303b62047bSLouis Dionne op(exec, make_iterator<Iterator>()(inputEnd), make_iterator<Iterator>()(inputBegin),
10313b62047bSLouis Dionne std::forward<Rest>(rest)...);
10323b62047bSLouis Dionne }
10333b62047bSLouis Dionne
10343b62047bSLouis Dionne template <typename Policy, typename Op, typename InputIterator, typename OutputIterator, typename... Rest>
10353b62047bSLouis Dionne typename std::enable_if<is_same_iterator_category<OutputIterator, std::random_access_iterator_tag>::value,
10363b62047bSLouis Dionne void>::type
10373b62047bSLouis Dionne operator()(Policy&& exec, Op op, InputIterator inputBegin, InputIterator inputEnd, OutputIterator outputBegin,
10383b62047bSLouis Dionne Rest&&... rest)
10393b62047bSLouis Dionne {
10403b62047bSLouis Dionne if (std::distance(inputBegin, inputEnd) <= sizeLimit)
10413b62047bSLouis Dionne op(exec, make_iterator<InputIterator>()(inputEnd), make_iterator<InputIterator>()(inputBegin),
10423b62047bSLouis Dionne make_iterator<OutputIterator>()(outputBegin + (inputEnd - inputBegin)), std::forward<Rest>(rest)...);
10433b62047bSLouis Dionne }
10443b62047bSLouis Dionne
10453b62047bSLouis Dionne template <typename Policy, typename Op, typename InputIterator, typename OutputIterator, typename... Rest>
10463b62047bSLouis Dionne typename std::enable_if<is_same_iterator_category<OutputIterator, std::random_access_iterator_tag>::value,
10473b62047bSLouis Dionne void>::type
10483b62047bSLouis Dionne operator()(Policy&& exec, Op op, InputIterator inputBegin, InputIterator inputEnd, OutputIterator outputBegin,
10493b62047bSLouis Dionne OutputIterator outputEnd, Rest&&... rest)
10503b62047bSLouis Dionne {
10513b62047bSLouis Dionne if (std::distance(inputBegin, inputEnd) <= sizeLimit)
10523b62047bSLouis Dionne op(exec, make_iterator<InputIterator>()(inputEnd), make_iterator<InputIterator>()(inputBegin),
10533b62047bSLouis Dionne make_iterator<OutputIterator>()(outputEnd), make_iterator<OutputIterator>()(outputBegin),
10543b62047bSLouis Dionne std::forward<Rest>(rest)...);
10553b62047bSLouis Dionne }
10563b62047bSLouis Dionne
10573b62047bSLouis Dionne template <typename Policy, typename Op, typename InputIterator1, typename InputIterator2, typename OutputIterator,
10583b62047bSLouis Dionne typename... Rest>
10593b62047bSLouis Dionne typename std::enable_if<is_same_iterator_category<OutputIterator, std::random_access_iterator_tag>::value,
10603b62047bSLouis Dionne void>::type
10613b62047bSLouis Dionne operator()(Policy&& exec, Op op, InputIterator1 inputBegin1, InputIterator1 inputEnd1, InputIterator2 inputBegin2,
10623b62047bSLouis Dionne InputIterator2 inputEnd2, OutputIterator outputBegin, OutputIterator outputEnd, Rest&&... rest)
10633b62047bSLouis Dionne {
10643b62047bSLouis Dionne if (std::distance(inputBegin1, inputEnd1) <= sizeLimit)
10653b62047bSLouis Dionne op(exec, make_iterator<InputIterator1>()(inputEnd1), make_iterator<InputIterator1>()(inputBegin1),
10663b62047bSLouis Dionne make_iterator<InputIterator2>()(inputEnd2), make_iterator<InputIterator2>()(inputBegin2),
10673b62047bSLouis Dionne make_iterator<OutputIterator>()(outputEnd), make_iterator<OutputIterator>()(outputBegin),
10683b62047bSLouis Dionne std::forward<Rest>(rest)...);
10693b62047bSLouis Dionne }
10703b62047bSLouis Dionne };
10713b62047bSLouis Dionne
10723b62047bSLouis Dionne // We can't create reverse iterator from forward iterator
10733b62047bSLouis Dionne template <>
10743b62047bSLouis Dionne struct iterator_invoker<std::forward_iterator_tag, /*isReverse=*/std::true_type>
10753b62047bSLouis Dionne {
10763b62047bSLouis Dionne template <typename... Rest>
10773b62047bSLouis Dionne void
10785c4c4431SLouis Dionne operator()(Rest&&...)
10793b62047bSLouis Dionne {
10803b62047bSLouis Dionne }
10813b62047bSLouis Dionne };
10823b62047bSLouis Dionne
10833b62047bSLouis Dionne template <typename IsReverse>
10843b62047bSLouis Dionne struct reverse_invoker
10853b62047bSLouis Dionne {
10863b62047bSLouis Dionne template <typename... Rest>
10873b62047bSLouis Dionne void
10883b62047bSLouis Dionne operator()(Rest&&... rest)
10893b62047bSLouis Dionne {
10903b62047bSLouis Dionne // Random-access iterator
10913b62047bSLouis Dionne iterator_invoker<std::random_access_iterator_tag, IsReverse>()(std::forward<Rest>(rest)...);
10923b62047bSLouis Dionne
10933b62047bSLouis Dionne // Forward iterator
10943b62047bSLouis Dionne iterator_invoker<std::forward_iterator_tag, IsReverse>()(std::forward<Rest>(rest)...);
10953b62047bSLouis Dionne
10963b62047bSLouis Dionne // Bidirectional iterator
10973b62047bSLouis Dionne iterator_invoker<std::bidirectional_iterator_tag, IsReverse>()(std::forward<Rest>(rest)...);
10983b62047bSLouis Dionne }
10993b62047bSLouis Dionne };
11003b62047bSLouis Dionne
11013b62047bSLouis Dionne struct invoke_on_all_iterator_types
11023b62047bSLouis Dionne {
11033b62047bSLouis Dionne template <typename... Rest>
11043b62047bSLouis Dionne void
11053b62047bSLouis Dionne operator()(Rest&&... rest)
11063b62047bSLouis Dionne {
11073b62047bSLouis Dionne reverse_invoker</* IsReverse = */ std::false_type>()(std::forward<Rest>(rest)...);
11083b62047bSLouis Dionne reverse_invoker</* IsReverse = */ std::true_type>()(std::forward<Rest>(rest)...);
11093b62047bSLouis Dionne }
11103b62047bSLouis Dionne };
11113b62047bSLouis Dionne //============================================================================
11123b62047bSLouis Dionne
11133b62047bSLouis Dionne // Invoke op(policy,rest...) for each possible policy.
11143b62047bSLouis Dionne template <typename Op, typename... T>
11153b62047bSLouis Dionne void
11163b62047bSLouis Dionne invoke_on_all_policies(Op op, T&&... rest)
11173b62047bSLouis Dionne {
11183b62047bSLouis Dionne using namespace __pstl::execution;
11193b62047bSLouis Dionne
11203b62047bSLouis Dionne // Try static execution policies
11213b62047bSLouis Dionne invoke_on_all_iterator_types()(seq, op, std::forward<T>(rest)...);
11223b62047bSLouis Dionne invoke_on_all_iterator_types()(unseq, op, std::forward<T>(rest)...);
11233b62047bSLouis Dionne invoke_on_all_iterator_types()(par, op, std::forward<T>(rest)...);
11243b62047bSLouis Dionne invoke_on_all_iterator_types()(par_unseq, op, std::forward<T>(rest)...);
11253b62047bSLouis Dionne }
11263b62047bSLouis Dionne
11273b62047bSLouis Dionne template <typename F>
11283b62047bSLouis Dionne struct NonConstAdapter
11293b62047bSLouis Dionne {
11303b62047bSLouis Dionne F my_f;
11313b62047bSLouis Dionne NonConstAdapter(const F& f) : my_f(f) {}
11323b62047bSLouis Dionne
11333b62047bSLouis Dionne template <typename... Types>
11343b62047bSLouis Dionne auto
11353b62047bSLouis Dionne operator()(Types&&... args) -> decltype(std::declval<F>().
11363b62047bSLouis Dionne operator()(std::forward<Types>(args)...))
11373b62047bSLouis Dionne {
11383b62047bSLouis Dionne return my_f(std::forward<Types>(args)...);
11393b62047bSLouis Dionne }
11403b62047bSLouis Dionne };
11413b62047bSLouis Dionne
11423b62047bSLouis Dionne template <typename F>
11433b62047bSLouis Dionne NonConstAdapter<F>
11443b62047bSLouis Dionne non_const(const F& f)
11453b62047bSLouis Dionne {
11463b62047bSLouis Dionne return NonConstAdapter<F>(f);
11473b62047bSLouis Dionne }
11483b62047bSLouis Dionne
11493b62047bSLouis Dionne // Wrapper for types. It's need for counting of constructing and destructing objects
11503b62047bSLouis Dionne template <typename T>
11513b62047bSLouis Dionne class Wrapper
11523b62047bSLouis Dionne {
11533b62047bSLouis Dionne public:
11543b62047bSLouis Dionne Wrapper()
11553b62047bSLouis Dionne {
11563b62047bSLouis Dionne my_field = std::shared_ptr<T>(new T());
11573b62047bSLouis Dionne ++my_count;
11583b62047bSLouis Dionne }
11593b62047bSLouis Dionne Wrapper(const T& input)
11603b62047bSLouis Dionne {
11613b62047bSLouis Dionne my_field = std::shared_ptr<T>(new T(input));
11623b62047bSLouis Dionne ++my_count;
11633b62047bSLouis Dionne }
11643b62047bSLouis Dionne Wrapper(const Wrapper& input)
11653b62047bSLouis Dionne {
11663b62047bSLouis Dionne my_field = input.my_field;
11673b62047bSLouis Dionne ++my_count;
11683b62047bSLouis Dionne }
11693b62047bSLouis Dionne Wrapper(Wrapper&& input)
11703b62047bSLouis Dionne {
11713b62047bSLouis Dionne my_field = input.my_field;
11723b62047bSLouis Dionne input.my_field = nullptr;
11733b62047bSLouis Dionne ++move_count;
11743b62047bSLouis Dionne }
11753b62047bSLouis Dionne Wrapper&
11763b62047bSLouis Dionne operator=(const Wrapper& input)
11773b62047bSLouis Dionne {
11783b62047bSLouis Dionne my_field = input.my_field;
11793b62047bSLouis Dionne return *this;
11803b62047bSLouis Dionne }
11813b62047bSLouis Dionne Wrapper&
11823b62047bSLouis Dionne operator=(Wrapper&& input)
11833b62047bSLouis Dionne {
11843b62047bSLouis Dionne my_field = input.my_field;
11853b62047bSLouis Dionne input.my_field = nullptr;
11863b62047bSLouis Dionne ++move_count;
11873b62047bSLouis Dionne return *this;
11883b62047bSLouis Dionne }
11893b62047bSLouis Dionne bool
11903b62047bSLouis Dionne operator==(const Wrapper& input) const
11913b62047bSLouis Dionne {
11923b62047bSLouis Dionne return my_field == input.my_field;
11933b62047bSLouis Dionne }
11943b62047bSLouis Dionne bool
11953b62047bSLouis Dionne operator<(const Wrapper& input) const
11963b62047bSLouis Dionne {
11973b62047bSLouis Dionne return *my_field < *input.my_field;
11983b62047bSLouis Dionne }
11993b62047bSLouis Dionne bool
12003b62047bSLouis Dionne operator>(const Wrapper& input) const
12013b62047bSLouis Dionne {
12023b62047bSLouis Dionne return *my_field > *input.my_field;
12033b62047bSLouis Dionne }
12043b62047bSLouis Dionne friend std::ostream&
12053b62047bSLouis Dionne operator<<(std::ostream& stream, const Wrapper& input)
12063b62047bSLouis Dionne {
12073b62047bSLouis Dionne return stream << *(input.my_field);
12083b62047bSLouis Dionne }
12093b62047bSLouis Dionne ~Wrapper()
12103b62047bSLouis Dionne {
12113b62047bSLouis Dionne --my_count;
12123b62047bSLouis Dionne if (move_count > 0)
12133b62047bSLouis Dionne {
12143b62047bSLouis Dionne --move_count;
12153b62047bSLouis Dionne }
12163b62047bSLouis Dionne }
12173b62047bSLouis Dionne T*
12183b62047bSLouis Dionne get_my_field() const
12193b62047bSLouis Dionne {
12203b62047bSLouis Dionne return my_field.get();
12213b62047bSLouis Dionne };
12223b62047bSLouis Dionne static size_t
12233b62047bSLouis Dionne Count()
12243b62047bSLouis Dionne {
12253b62047bSLouis Dionne return my_count;
12263b62047bSLouis Dionne }
12273b62047bSLouis Dionne static size_t
12283b62047bSLouis Dionne MoveCount()
12293b62047bSLouis Dionne {
12303b62047bSLouis Dionne return move_count;
12313b62047bSLouis Dionne }
12323b62047bSLouis Dionne static void
12333b62047bSLouis Dionne SetCount(const size_t& n)
12343b62047bSLouis Dionne {
12353b62047bSLouis Dionne my_count = n;
12363b62047bSLouis Dionne }
12373b62047bSLouis Dionne static void
12383b62047bSLouis Dionne SetMoveCount(const size_t& n)
12393b62047bSLouis Dionne {
12403b62047bSLouis Dionne move_count = n;
12413b62047bSLouis Dionne }
12423b62047bSLouis Dionne
12433b62047bSLouis Dionne private:
12443b62047bSLouis Dionne static std::atomic<size_t> my_count;
12453b62047bSLouis Dionne static std::atomic<size_t> move_count;
12463b62047bSLouis Dionne std::shared_ptr<T> my_field;
12473b62047bSLouis Dionne };
12483b62047bSLouis Dionne
12493b62047bSLouis Dionne template <typename T>
12503b62047bSLouis Dionne std::atomic<size_t> Wrapper<T>::my_count = {0};
12513b62047bSLouis Dionne
12523b62047bSLouis Dionne template <typename T>
12533b62047bSLouis Dionne std::atomic<size_t> Wrapper<T>::move_count = {0};
12543b62047bSLouis Dionne
12553b62047bSLouis Dionne template <typename InputIterator, typename T, typename BinaryOperation, typename UnaryOperation>
12563b62047bSLouis Dionne T
12573b62047bSLouis Dionne transform_reduce_serial(InputIterator first, InputIterator last, T init, BinaryOperation binary_op,
12583b62047bSLouis Dionne UnaryOperation unary_op) noexcept
12593b62047bSLouis Dionne {
12603b62047bSLouis Dionne for (; first != last; ++first)
12613b62047bSLouis Dionne {
12623b62047bSLouis Dionne init = binary_op(init, unary_op(*first));
12633b62047bSLouis Dionne }
12643b62047bSLouis Dionne return init;
12653b62047bSLouis Dionne }
12663b62047bSLouis Dionne
12673b62047bSLouis Dionne static const char*
12683b62047bSLouis Dionne done()
12693b62047bSLouis Dionne {
12703b9a1bb1SLouis Dionne #if defined(_PSTL_TEST_SUCCESSFUL_KEYWORD)
12713b62047bSLouis Dionne return "done";
12723b62047bSLouis Dionne #else
12733b62047bSLouis Dionne return "passed";
12743b62047bSLouis Dionne #endif
12753b62047bSLouis Dionne }
12763b62047bSLouis Dionne
12773b62047bSLouis Dionne // test_algo_basic_* functions are used to execute
12783b62047bSLouis Dionne // f on a very basic sequence of elements of type T.
12793b62047bSLouis Dionne
12803b62047bSLouis Dionne // Should be used with unary predicate
12813b62047bSLouis Dionne template <typename T, typename F>
12823b62047bSLouis Dionne static void
12833b62047bSLouis Dionne test_algo_basic_single(F&& f)
12843b62047bSLouis Dionne {
12853b62047bSLouis Dionne size_t N = 10;
12863b62047bSLouis Dionne Sequence<T> in(N, [](size_t v) -> T { return T(v); });
12873b62047bSLouis Dionne
12883b62047bSLouis Dionne invoke_on_all_policies(f, in.begin());
12893b62047bSLouis Dionne }
12903b62047bSLouis Dionne
12913b62047bSLouis Dionne // Should be used with binary predicate
12923b62047bSLouis Dionne template <typename T, typename F>
12933b62047bSLouis Dionne static void
12943b62047bSLouis Dionne test_algo_basic_double(F&& f)
12953b62047bSLouis Dionne {
12963b62047bSLouis Dionne size_t N = 10;
12973b62047bSLouis Dionne Sequence<T> in(N, [](size_t v) -> T { return T(v); });
12983b62047bSLouis Dionne Sequence<T> out(N, [](size_t v) -> T { return T(v); });
12993b62047bSLouis Dionne
13003b62047bSLouis Dionne invoke_on_all_policies(f, in.begin(), out.begin());
13013b62047bSLouis Dionne }
13023b62047bSLouis Dionne
13033b62047bSLouis Dionne template <typename Policy, typename F>
13043b62047bSLouis Dionne static void
13055c4c4431SLouis Dionne invoke_if(Policy&&, F f)
13063b62047bSLouis Dionne {
13073b9a1bb1SLouis Dionne #if defined(_PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN) || defined(_PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN)
1308*843c12d6SRuslan Arutyunyan using decay_policy = typename std::decay<Policy>::type;
1309*843c12d6SRuslan Arutyunyan using allow_unsequenced =
1310*843c12d6SRuslan Arutyunyan std::integral_constant<bool, (std::is_same<decay_policy, std::execution::unsequenced_policy>::value ||
1311*843c12d6SRuslan Arutyunyan std::is_same<decay_policy, std::execution::parallel_unsequenced_policy>::value)>;
1312*843c12d6SRuslan Arutyunyan __pstl::__internal::__invoke_if_not(allow_unsequenced{}, f);
13133b62047bSLouis Dionne #else
13143b62047bSLouis Dionne f();
13153b62047bSLouis Dionne #endif
13163b62047bSLouis Dionne }
13173b62047bSLouis Dionne
13183b62047bSLouis Dionne } /* namespace TestUtils */
1319