1 //----------------------------------------------------------------------------
2 /// @file range.hpp
3 /// @brief Define a range [first, last), and the associated operations
4 ///
5 /// @author Copyright (c) 2016 Francisco José Tapia (fjtapia@gmail.com )\n
6 /// Distributed under the Boost Software License, Version 1.0.\n
7 /// ( See accompanyingfile LICENSE_1_0.txt or copy at
8 /// http://www.boost.org/LICENSE_1_0.txt )
9 /// @version 0.1
10 ///
11 /// @remarks
12 //-----------------------------------------------------------------------------
13 #ifndef __BOOST_SORT_PARALLEL_DETAIL_UTIL_RANGE_HPP
14 #define __BOOST_SORT_PARALLEL_DETAIL_UTIL_RANGE_HPP
15
16 #include <boost/sort/common/util/algorithm.hpp>
17 #include <boost/sort/common/util/merge.hpp>
18 #include <boost/sort/common/util/traits.hpp>
19 #include <cassert>
20 #include <functional>
21 #include <memory>
22 #include <vector>
23
24 namespace boost
25 {
26 namespace sort
27 {
28 namespace common
29 {
30
31 ///---------------------------------------------------------------------------
32 /// @struct range
33 /// @brief this represent a range between two iterators
34 /// @remarks
35 //----------------------------------------------------------------------------
36 template <class Iter_t>
37 struct range
38 {
39 Iter_t first, last;
40 //
41 //------------------------------------------------------------------------
42 // function : range
43 /// @brief empty constructor
44 //------------------------------------------------------------------------
rangeboost::sort::common::range45 range(void) { };
46 //
47 //------------------------------------------------------------------------
48 // function : range
49 /// @brief constructor with two parameters
50 /// @param frs : iterator to the first element
51 /// @param lst : iterator to the last element
52 //-----------------------------------------------------------------------
rangeboost::sort::common::range53 range(const Iter_t &frs, const Iter_t &lst): first(frs), last(lst) { };
54 //
55 //-----------------------------------------------------------------------
56 // function : empty
57 /// @brief indicate if the range is empty
58 /// @return true : empty false : not empty
59 //-----------------------------------------------------------------------
emptyboost::sort::common::range60 bool empty(void) const { return (first == last); };
61 //
62 //-----------------------------------------------------------------------
63 // function : not_empty
64 /// @brief indicate if the range is not empty
65 /// @return true : not empty false : empty
66 //-----------------------------------------------------------------------
not_emptyboost::sort::common::range67 bool not_empty(void) const {return (first != last); };
68 //
69 //-----------------------------------------------------------------------
70 // function : valid
71 /// @brief Indicate if the range is well constructed, and valid
72 /// @return true : valid, false : not valid
73 //-----------------------------------------------------------------------
validboost::sort::common::range74 bool valid(void) const { return ((last - first) >= 0); };
75 //
76 //-----------------------------------------------------------------------
77 // function : size
78 /// @brief return the size of the range
79 /// @return size
80 //-----------------------------------------------------------------------
sizeboost::sort::common::range81 size_t size(void) const { return (last - first); };
82 //
83 //------------------------------------------------------------------------
84 // function : front
85 /// @brief return an iterator to the first element of the range
86 /// @return iterator
87 //-----------------------------------------------------------------------
frontboost::sort::common::range88 Iter_t front(void) const { return first; };
89 //
90 //-------------------------------------------------------------------------
91 // function : back
92 /// @brief return an iterator to the last element of the range
93 /// @return iterator
94 //-------------------------------------------------------------------------
backboost::sort::common::range95 Iter_t back(void) const {return (last - 1); };
96 };
97
98 //
99 //-----------------------------------------------------------------------------
100 // function : concat
101 /// @brief concatenate two contiguous ranges
102 /// @param it1 : first range
103 /// @param it2 : second range
104 /// @return range resulting of the concatenation
105 //-----------------------------------------------------------------------------
106 template<class Iter_t>
concat(const range<Iter_t> & it1,const range<Iter_t> & it2)107 inline range<Iter_t> concat(const range<Iter_t> &it1, const range<Iter_t> &it2)
108 {
109 return range<Iter_t>(it1.first, it2.last);
110 }
111 ;
112 //
113 //-----------------------------------------------------------------------------
114 // function : move_forward
115 /// @brief Move initialized objets from the range src to dest
116 /// @param dest : range where move the objects
117 /// @param src : range from where move the objects
118 /// @return range with the objects moved and the size adjusted
119 //-----------------------------------------------------------------------------
120 template <class Iter1_t, class Iter2_t>
move_forward(const range<Iter2_t> & dest,const range<Iter1_t> & src)121 inline range<Iter2_t> move_forward(const range<Iter2_t> &dest,
122 const range<Iter1_t> &src)
123 {
124 assert(dest.size() >= src.size());
125 Iter2_t it_aux = util::move_forward(dest.first, src.first, src.last);
126 return range<Iter2_t>(dest.first, it_aux);
127 };
128 //
129 //-----------------------------------------------------------------------------
130 // function : move_backward
131 /// @brief Move initialized objets from the range src to dest
132 /// @param dest : range where move the objects
133 /// @param src : range from where move the objects
134 /// @return range with the objects moved and the size adjusted
135 //-----------------------------------------------------------------------------
136 template <class Iter1_t, class Iter2_t>
move_backward(const range<Iter2_t> & dest,const range<Iter1_t> & src)137 inline range<Iter2_t> move_backward(const range<Iter2_t> &dest,
138 const range<Iter1_t> &src)
139 {
140 assert(dest.size() >= src.size());
141 Iter2_t it_aux = util::move_backward(dest.first + src.size(), src.first,
142 src.last);
143 return range<Iter2_t>(dest.first, dest.src.size());
144 };
145
146 //-----------------------------------------------------------------------------
147 // function : uninit_move
148 /// @brief Move uninitialized objets from the range src creating them in dest
149 ///
150 /// @param dest : range where move and create the objects
151 /// @param src : range from where move the objects
152 /// @return range with the objects moved and the size adjusted
153 //-----------------------------------------------------------------------------
154 template<class Iter_t, class Value_t = util::value_iter<Iter_t> >
move_construct(const range<Value_t * > & dest,const range<Iter_t> & src)155 inline range<Value_t*> move_construct(const range<Value_t*> &dest,
156 const range<Iter_t> &src)
157 {
158 Value_t *ptr_aux = util::move_construct(dest.first, src.first, src.last);
159 return range<Value_t*>(dest.first, ptr_aux);
160 };
161 //
162 //-----------------------------------------------------------------------------
163 // function : destroy
164 /// @brief destroy a range of objects
165 /// @param rng : range to destroy
166 //-----------------------------------------------------------------------------
167 template<class Iter_t>
destroy(range<Iter_t> rng)168 inline void destroy(range<Iter_t> rng)
169 {
170 util::destroy(rng.first, rng.last);
171 };
172 //
173 //-----------------------------------------------------------------------------
174 // function : initialize
175 /// @brief initialize a range of objects with the object val moving across them
176 /// @param rng : range of elements not initialized
177 /// @param val : object used for the initialization
178 /// @return range initialized
179 //-----------------------------------------------------------------------------
180 template<class Iter_t, class Value_t = util::value_iter<Iter_t> >
initialize(const range<Iter_t> & rng,Value_t & val)181 inline range<Iter_t> initialize(const range<Iter_t> &rng, Value_t &val)
182 {
183 util::initialize(rng.first, rng.last, val);
184 return rng;
185 };
186 //
187 //-----------------------------------------------------------------------------
188 // function : is_mergeable
189 /// @brief : indicate if two ranges have a possible merge
190 /// @param src1 : first range
191 /// @param src2 : second range
192 /// @param comp : object for to compare elements
193 /// @return true : they can be merged
194 /// false : they can't be merged
195 //-----------------------------------------------------------------------------
196 template<class Iter1_t, class Iter2_t, class Compare>
is_mergeable(const range<Iter1_t> & src1,const range<Iter2_t> & src2,Compare comp)197 inline bool is_mergeable(const range<Iter1_t> &src1, const range<Iter2_t> &src2,
198 Compare comp)
199 {
200 //------------------------------------------------------------------------
201 // Metaprogramming
202 //------------------------------------------------------------------------
203 typedef util::value_iter<Iter1_t> type1;
204 typedef util::value_iter<Iter2_t> type2;
205 static_assert (std::is_same< type1, type2 >::value,
206 "Incompatible iterators\n");
207 //------------------------------------------------------------------------
208 // Code
209 //------------------------------------------------------------------------
210 return comp(*(src2.front()), *(src1.back()));
211 };
212 //
213 //-----------------------------------------------------------------------------
214 // function : is_mergeable_stable
215 /// @brief : indicate if two ranges have a possible merge
216 /// @param src1 : first range
217 /// @param src2 : second range
218 /// @param comp : object for to compare elements
219 /// @return true : they can be merged
220 /// false : they can't be merged
221 //-----------------------------------------------------------------------------
222 template<class Iter1_t, class Iter2_t, class Compare>
is_mergeable_stable(const range<Iter1_t> & src1,const range<Iter2_t> & src2,Compare comp)223 inline bool is_mergeable_stable(const range<Iter1_t> &src1,
224 const range<Iter2_t> &src2, Compare comp)
225 {
226 //------------------------------------------------------------------------
227 // Metaprogramming
228 //------------------------------------------------------------------------
229 typedef util::value_iter<Iter1_t> type1;
230 typedef util::value_iter<Iter2_t> type2;
231 static_assert (std::is_same< type1, type2 >::value,
232 "Incompatible iterators\n");
233 //------------------------------------------------------------------------
234 // Code
235 //------------------------------------------------------------------------
236 return not comp(*(src1.back()), *(src2.front()));
237 };
238 //
239 //-----------------------------------------------------------------------------
240 // function : merge
241 /// @brief Merge two contiguous ranges src1 and src2, and put the result in
242 /// the range dest, returning the range merged
243 ///
244 /// @param dest : range where locate the lements merged. the size of dest
245 /// must be greater or equal than the sum of the sizes of
246 /// src1 and src2
247 /// @param src1 : first range to merge
248 /// @param src2 : second range to merge
249 /// @param comp : comparison object
250 /// @return range with the elements merged and the size adjusted
251 //-----------------------------------------------------------------------------
252 template<class Iter1_t, class Iter2_t, class Iter3_t, class Compare>
merge(const range<Iter3_t> & dest,const range<Iter1_t> & src1,const range<Iter2_t> & src2,Compare comp)253 inline range<Iter3_t> merge(const range<Iter3_t> &dest,
254 const range<Iter1_t> &src1,
255 const range<Iter2_t> &src2, Compare comp)
256 {
257 Iter3_t it_aux = util::merge(src1.first, src1.last, src2.first, src2.last,
258 dest.first, comp);
259 return range<Iter3_t>(dest.first, it_aux);
260 };
261
262 //-----------------------------------------------------------------------------
263 // function : merge_construct
264 /// @brief Merge two contiguous uninitialized ranges src1 and src2, and create
265 /// and move the result in the uninitialized range dest, returning the
266 /// range merged
267 //
268 /// @param dest : range where locate the elements merged. the size of dest
269 /// must be greater or equal than the sum of the sizes of
270 /// src1 and src2. Initially is uninitialize memory
271 /// @param src1 : first range to merge
272 /// @param src2 : second range to merge
273 /// @param comp : comparison object
274 /// @return range with the elements merged and the size adjusted
275 //-----------------------------------------------------------------------------
276 template<class Iter1_t, class Iter2_t, class Value_t, class Compare>
merge_construct(const range<Value_t * > & dest,const range<Iter1_t> & src1,const range<Iter2_t> & src2,Compare comp)277 inline range<Value_t *> merge_construct(const range<Value_t *> &dest,
278 const range<Iter1_t> &src1,
279 const range<Iter2_t> &src2,
280 Compare comp)
281 {
282 Value_t * ptr_aux = util::merge_construct(src1.first, src1.last, src2.first,
283 src2.last, dest.first, comp);
284 return range<Value_t*>(dest.first, ptr_aux);
285 };
286 //
287 //---------------------------------------------------------------------------
288 // function : half_merge
289 /// @brief : Merge two initialized buffers. The first buffer is in a separate
290 /// memory
291 //
292 /// @param dest : range where finish the two buffers merged
293 /// @param src1 : first range to merge in a separate memory
294 /// @param src2 : second range to merge, in the final part of the
295 /// range where deposit the final results
296 /// @param comp : object for compare two elements of the type pointed
297 /// by the Iter1_t and Iter2_t
298 /// @return : range with the two buffers merged
299 //---------------------------------------------------------------------------
300 template<class Iter1_t, class Iter2_t, class Compare>
merge_half(const range<Iter2_t> & dest,const range<Iter1_t> & src1,const range<Iter2_t> & src2,Compare comp)301 inline range<Iter2_t> merge_half(const range<Iter2_t> &dest,
302 const range<Iter1_t> &src1,
303 const range<Iter2_t> &src2, Compare comp)
304 {
305 Iter2_t it_aux = util::merge_half(src1.first, src1.last, src2.first,
306 src2.last, dest.first, comp);
307 return range<Iter2_t>(dest.first, it_aux);
308 };
309 //
310 //-----------------------------------------------------------------------------
311 // function : merge_uncontiguous
312 /// @brief : merge two non contiguous ranges src1, src2, using the range
313 /// aux as auxiliary memory. The results are in the original ranges
314 //
315 /// @param src1 : first range to merge
316 /// @param src2 : second range to merge
317 /// @param aux : auxiliary range used in the merge
318 /// @param comp : object for to compare elements
319 /// @return true : not changes done, false : changes in the buffers
320 //-----------------------------------------------------------------------------
321 template<class Iter1_t, class Iter2_t, class Iter3_t, class Compare>
merge_uncontiguous(const range<Iter1_t> & src1,const range<Iter2_t> & src2,const range<Iter3_t> & aux,Compare comp)322 inline bool merge_uncontiguous(const range<Iter1_t> &src1,
323 const range<Iter2_t> &src2,
324 const range<Iter3_t> &aux, Compare comp)
325 {
326 return util::merge_uncontiguous(src1.first, src1.last, src2.first,
327 src2.last, aux.first, comp);
328 };
329 //
330 //-----------------------------------------------------------------------------
331 // function : merge_contiguous
332 /// @brief : merge two contiguous ranges ( src1, src2) using buf as
333 /// auxiliary memory. The results are in the same ranges
334 /// @param src1 : first range to merge
335 /// @param src1 : second range to merge
336 /// @param buf : auxiliary memory used in the merge
337 /// @param comp : object for to compare elements
338 /// @return true : not changes done, false : changes in the buffers
339 //-----------------------------------------------------------------------------
340 template<class Iter1_t, class Iter2_t, class Compare>
merge_contiguous(const range<Iter1_t> & src1,const range<Iter1_t> & src2,const range<Iter2_t> & buf,Compare comp)341 inline range<Iter1_t> merge_contiguous(const range<Iter1_t> &src1,
342 const range<Iter1_t> &src2,
343 const range<Iter2_t> &buf, Compare comp)
344 {
345 util::merge_contiguous(src1.first, src1.last, src2.last, buf.first, comp);
346 return concat(src1, src2);
347 };
348 //
349 //-----------------------------------------------------------------------------
350 // function : merge_flow
351 /// @brief : merge two ranges, as part of a merge the ranges in a list. This
352 /// function reduce the number of movements compared with inplace_merge
353 /// when you need to merge a sequence of ranges.
354 /// This function merge the ranges rbuf and rng2, and the results
355 /// are in rng1 and rbuf
356 //
357 /// @param rng1 : range where locate the first elements of the merge
358 /// @param rbuf : range which provide the first elements, and where store
359 /// the last results of the merge
360 /// @param rng2 : range which provide the last elements to merge
361 /// @param comp : object for to compare elements
362 /// @return true : not changes done, false : changes in the buffers
363 //-----------------------------------------------------------------------------
364 template<class Iter1_t, class Iter2_t, class Compare>
merge_flow(range<Iter1_t> rng1,range<Iter2_t> rbuf,range<Iter1_t> rng2,Compare cmp)365 static void merge_flow(range<Iter1_t> rng1, range<Iter2_t> rbuf,
366 range<Iter1_t> rng2, Compare cmp)
367 {
368 //-------------------------------------------------------------------------
369 // Metaprogramming
370 //-------------------------------------------------------------------------
371 typedef util::value_iter<Iter1_t> type1;
372 typedef util::value_iter<Iter2_t> type2;
373 static_assert (std::is_same< type1, type2 >::value,
374 "Incompatible iterators\n");
375
376 //-------------------------------------------------------------------------
377 // Code
378 //-------------------------------------------------------------------------
379 range<Iter2_t> rbx(rbuf);
380 range<Iter1_t> rx1(rng1), rx2(rng2);
381 assert(rbx.size() == rx1.size() and rx1.size() == rx2.size());
382 while (rx1.first != rx1.last)
383 {
384 *(rx1.first++) = (cmp(*rbx.first, *rx2.first)) ?
385 std::move(*(rbx.first++)):
386 std::move(*(rx2.first++));
387 };
388 if (rx2.first == rx2.last) return;
389 if (rbx.first == rbx.last) move_forward(rbuf, rng2);
390 else merge_half(rbuf, rx2, rbx, cmp);
391 };
392
393 //****************************************************************************
394 };// End namespace common
395 };// End namespace sort
396 };// End namespace boost
397 //****************************************************************************
398 //
399 #endif
400