1 //  Copyright (c) 2014-2015 Hartmut Kaiser
2 //  Copyright (c)      2018 Taeguk Kwon
3 //
4 //  Distributed under the Boost Software License, Version 1.0. (See accompanying
5 //  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 
7 #if !defined(HPX_PARALLEL_TEST_ITERATOR_MAY_29_2014_0110PM)
8 #define HPX_PARALLEL_TEST_ITERATOR_MAY_29_2014_0110PM
9 
10 #include <hpx/include/parallel_execution_policy.hpp>
11 #include <hpx/include/util.hpp>
12 
13 #include <atomic>
14 #include <cstddef>
15 #include <iostream>
16 #include <numeric>
17 #include <random>
18 #include <utility>
19 #include <vector>
20 
21 namespace test
22 {
23     ///////////////////////////////////////////////////////////////////////////
24     template <typename BaseIterator, typename IteratorTag>
25     struct test_iterator
26       : hpx::util::iterator_adaptor<
27             test_iterator<BaseIterator, IteratorTag>,
28             BaseIterator, void, IteratorTag>
29     {
30     private:
31         typedef hpx::util::iterator_adaptor<
32             test_iterator<BaseIterator, IteratorTag>,
33             BaseIterator, void, IteratorTag>
34         base_type;
35 
36     public:
test_iteratortest::test_iterator37         test_iterator() : base_type() {}
test_iteratortest::test_iterator38         test_iterator(BaseIterator base) : base_type(base) {}
39     };
40 
41     ///////////////////////////////////////////////////////////////////////////
42     template <typename BaseContainer, typename IteratorTag>
43     struct test_container : BaseContainer
44     {
45         template <typename ... Ts>
test_containertest::test_container46         test_container(Ts && ...ts)
47           : BaseContainer(std::forward<Ts>(ts)...)
48         {}
49 
basetest::test_container50         BaseContainer& base() { return *this; }
basetest::test_container51         BaseContainer const& base() const { return *this; }
52 
53         typedef test_iterator<
54                 typename BaseContainer::iterator, IteratorTag
55             > iterator;
56         typedef test_iterator<
57                 typename BaseContainer::const_iterator, IteratorTag
58             > const_iterator;
59 
begintest::test_container60         iterator begin()
61         {
62             return iterator(this->BaseContainer::begin());
63         }
begintest::test_container64         const_iterator begin() const
65         {
66             return const_iterator(this->BaseContainer::begin());
67         }
cbegintest::test_container68         const_iterator cbegin() const
69         {
70             return const_iterator(this->BaseContainer::cbegin());
71         }
72 
endtest::test_container73         iterator end()
74         {
75             return iterator(this->BaseContainer::end());
76         }
endtest::test_container77         const_iterator end() const
78         {
79             return const_iterator(this->BaseContainer::end());
80         }
cendtest::test_container81         const_iterator cend() const
82         {
83             return const_iterator(this->BaseContainer::cend());
84         }
85     };
86 
87     ///////////////////////////////////////////////////////////////////////////
88     template <typename BaseIterator, typename IteratorTag>
89     struct decorated_iterator
90       : hpx::util::iterator_adaptor<
91             decorated_iterator<BaseIterator, IteratorTag>,
92             BaseIterator, void, IteratorTag>
93     {
94     private:
95         typedef hpx::util::iterator_adaptor<
96             decorated_iterator<BaseIterator, IteratorTag>,
97             BaseIterator, void, IteratorTag>
98         base_type;
99 
100     public:
decorated_iteratortest::decorated_iterator101         decorated_iterator()
102         {}
103 
decorated_iteratortest::decorated_iterator104         decorated_iterator(BaseIterator base)
105           : base_type(base)
106         {}
107 
decorated_iteratortest::decorated_iterator108         decorated_iterator(BaseIterator base, std::function<void()> f)
109           : base_type(base), m_callback(f)
110         {}
111 
112     private:
113         friend class hpx::util::iterator_core_access;
114 
dereferencetest::decorated_iterator115         typename base_type::reference dereference() const
116         {
117             if (m_callback)
118                 m_callback();
119             return *(this->base());
120         }
121 
122     private:
123         std::function<void()> m_callback;
124     };
125 
126     ///////////////////////////////////////////////////////////////////////////
127     struct count_instances
128     {
count_instancestest::count_instances129         count_instances()
130           : value_(std::size_t(-1))
131         {
132             ++instance_count;
133         }
count_instancestest::count_instances134         count_instances(int value)
135           : value_(value)
136         {
137             ++instance_count;
138         }
count_instancestest::count_instances139         count_instances(count_instances const& rhs)
140           : value_(rhs.value_)
141         {
142             ++instance_count;
143         }
144 
operator =test::count_instances145         count_instances& operator=(count_instances const& rhs)
146         {
147             value_ = rhs.value_;
148             return *this;
149         }
150 
~count_instancestest::count_instances151         ~count_instances()
152         {
153             --instance_count;
154         }
155 
156         std::size_t value_;
157         static std::atomic<std::size_t> instance_count;
158     };
159 
160     std::atomic<std::size_t> count_instances::instance_count(0);
161 
162     ///////////////////////////////////////////////////////////////////////////
163     template <typename ExPolicy, typename IteratorTag>
164     struct test_num_exceptions
165     {
calltest::test_num_exceptions166         static void call(ExPolicy, hpx::exception_list const& e)
167         {
168             // The static partitioner uses four times the number of
169             // threads/cores for the number chunks to create.
170             HPX_TEST_LTE(e.size(), 4 * hpx::get_num_worker_threads());
171         }
172     };
173 
174     template <typename IteratorTag>
175     struct test_num_exceptions<
176         hpx::parallel::execution::sequenced_policy, IteratorTag>
177     {
calltest::test_num_exceptions178         static void call(hpx::parallel::execution::sequenced_policy const&,
179             hpx::exception_list const& e)
180         {
181             HPX_TEST_EQ(e.size(), 1u);
182         }
183     };
184 
185     template <typename ExPolicy>
186     struct test_num_exceptions<ExPolicy, std::input_iterator_tag>
187     {
calltest::test_num_exceptions188         static void call(ExPolicy, hpx::exception_list const& e)
189         {
190             HPX_TEST_EQ(e.size(), 1u);
191         }
192     };
193 
194     template <>
195     struct test_num_exceptions<
196         hpx::parallel::execution::sequenced_policy, std::input_iterator_tag>
197     {
calltest::test_num_exceptions198         static void call(hpx::parallel::execution::sequenced_policy const&,
199             hpx::exception_list const& e)
200         {
201             HPX_TEST_EQ(e.size(), 1u);
202         }
203     };
204 
205     ///////////////////////////////////////////////////////////////////////////
iota(std::size_t size,std::size_t start)206     inline std::vector<std::size_t> iota(std::size_t size, std::size_t start)
207     {
208         std::vector<std::size_t> c(size);
209         std::iota(std::begin(c), std::end(c), start);
210         return c;
211     }
212 
random_iota(std::size_t size)213     inline std::vector<std::size_t> random_iota(std::size_t size)
214     {
215         std::vector<std::size_t> c(size);
216         std::iota(std::begin(c), std::end(c), 0);
217         std::random_device rd;
218         std::mt19937 g(rd());
219         std::shuffle(std::begin(c), std::end(c), g);
220         return c;
221     }
222 
223     template <typename Vector>
random_iota(std::size_t size)224     inline Vector random_iota(std::size_t size)
225     {
226         Vector c(size);
227         std::iota(std::begin(c.base()), std::end(c.base()), 0);
228         std::random_device rd;
229         std::mt19937 g(rd());
230         std::shuffle(std::begin(c.base()), std::end(c.base()), g);
231         return c;
232     }
233 
random_fill(std::size_t size)234     inline std::vector<std::size_t> random_fill(std::size_t size)
235     {
236         std::vector<std::size_t> c(size);
237         std::generate(std::begin(c), std::end(c), std::rand);
238         return c;
239     }
240 
241     ///////////////////////////////////////////////////////////////////////////
make_ready(std::vector<hpx::promise<std::size_t>> & p,std::vector<std::size_t> & idx)242     inline void make_ready(std::vector<hpx::promise<std::size_t> >& p,
243         std::vector<std::size_t>& idx)
244     {
245         std::for_each(std::begin(idx), std::end(idx),
246             [&p](std::size_t i)
247             {
248                 p[i].set_value(i);
249             });
250     }
251 
fill_with_futures(std::vector<hpx::promise<std::size_t>> & p)252     inline std::vector<hpx::future<std::size_t> > fill_with_futures(
253         std::vector<hpx::promise<std::size_t> >& p)
254     {
255         std::vector<hpx::future<std::size_t> > f;
256         std::transform(std::begin(p), std::end(p), std::back_inserter(f),
257             [](hpx::promise<std::size_t>& pr)
258             {
259                 return pr.get_future();
260             });
261 
262         return f;
263     }
264 
265     ///////////////////////////////////////////////////////////////////////////
266     inline std::vector<std::size_t>
fill_all_any_none(std::size_t size,std::size_t num_filled)267     fill_all_any_none(std::size_t size, std::size_t num_filled)
268     {
269         if (num_filled == 0)
270             return std::vector<std::size_t>(size, 0);
271 
272         if (num_filled == size)
273             return std::vector<std::size_t>(size, 1);
274 
275         std::vector<std::size_t> c(size, 0);
276         for (std::size_t i = 0; i < num_filled; /**/)
277         {
278             std::size_t pos = std::rand() % c.size(); //-V104
279             if (c[pos])
280                 continue;
281 
282             c[pos] = 1;
283             ++i;
284         }
285         return c;
286     }
287 
288     ///////////////////////////////////////////////////////////////////////////
289     template <typename InputIter1, typename InputIter2>
equal(InputIter1 first1,InputIter1 last1,InputIter2 first2,InputIter2 last2)290     bool equal(InputIter1 first1, InputIter1 last1,
291         InputIter2 first2, InputIter2 last2)
292     {
293         if (std::distance(first1, last1) != std::distance(first2, last2))
294             return false;
295 
296         return std::equal(first1, last1, first2);
297     }
298 }
299 
300 #endif
301