• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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