File indexing completed on 2025-01-18 09:51:46
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef __BOOST_SORT_COMMON_MERGE_BLOCK_HPP
0015 #define __BOOST_SORT_COMMON_MERGE_BLOCK_HPP
0016
0017 #include <ciso646>
0018 #include <boost/sort/common/range.hpp>
0019 #include <boost/sort/common/rearrange.hpp>
0020 #include <boost/sort/common/util/merge.hpp>
0021 #include <boost/sort/common/util/traits.hpp>
0022
0023 namespace boost
0024 {
0025 namespace sort
0026 {
0027 namespace common
0028 {
0029
0030
0031
0032
0033
0034
0035 template<class Iter_t, class Compare, uint32_t Power2 = 10>
0036 struct merge_block
0037 {
0038
0039
0040
0041 typedef util::value_iter<Iter_t> value_t;
0042 typedef range<size_t> range_pos;
0043 typedef range<Iter_t> range_it;
0044 typedef range<value_t *> range_buf;
0045 typedef typename std::vector<size_t>::iterator it_index;
0046 typedef util::circular_buffer<value_t, Power2 + 1> circular_t;
0047
0048
0049
0050
0051 const size_t BLOCK_SIZE = (size_t) 1 << Power2;
0052 const size_t LOG_BLOCK = Power2;
0053
0054
0055
0056
0057
0058 range<Iter_t> global_range;
0059
0060
0061 std::vector<size_t> index;
0062
0063
0064 size_t nelem;
0065
0066
0067 size_t nblock;
0068
0069
0070 size_t ntail;
0071
0072
0073 Compare cmp;
0074
0075
0076 range_it range_tail;
0077
0078
0079 circular_t * ptr_circ;
0080
0081
0082
0083 bool owned;
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099 merge_block (Iter_t first, Iter_t last, Compare comp,
0100 circular_t *pcirc_buffer)
0101 : global_range(first, last), cmp(comp), ptr_circ(pcirc_buffer),
0102 owned(pcirc_buffer == nullptr)
0103 {
0104 assert((last - first) >= 0);
0105 if (first == last) return;
0106
0107 nelem = size_t(last - first);
0108 nblock = (nelem + BLOCK_SIZE - 1) / BLOCK_SIZE;
0109 ntail = (nelem % BLOCK_SIZE);
0110 index.reserve(nblock + 1);
0111
0112 for (size_t i = 0; i < nblock; ++i)
0113 index.emplace_back(i);
0114
0115 range_tail.first = first + ((nblock - 1) << LOG_BLOCK);
0116 range_tail.last = last;
0117 if (owned)
0118 {
0119 ptr_circ = new circular_t;
0120 ptr_circ->initialize(*first);
0121 };
0122 }
0123
0124 merge_block(Iter_t first, Iter_t last, Compare comp)
0125 : merge_block(first, last, comp, nullptr) { };
0126
0127 ~ merge_block()
0128 {
0129 if (ptr_circ != nullptr and owned)
0130 {
0131 delete ptr_circ;
0132 ptr_circ = nullptr;
0133 };
0134 };
0135
0136
0137
0138
0139
0140
0141 range_it get_range(size_t pos) const
0142 {
0143 Iter_t it1 = global_range.first + (pos << LOG_BLOCK);
0144 Iter_t it2 = (pos == (nblock - 1)) ?
0145 global_range.last : it1 + BLOCK_SIZE;
0146 return range_it(it1, it2);
0147 };
0148
0149
0150
0151
0152
0153
0154
0155
0156 range_it get_group_range(size_t pos, size_t nrange) const
0157 {
0158 Iter_t it1 = global_range.first + (pos << LOG_BLOCK);
0159
0160 Iter_t it2 = ((pos + nrange) == nblock)?global_range.last: global_range.first + ((pos + nrange) << LOG_BLOCK);
0161
0162
0163
0164 return range_it(it1, it2);
0165 };
0166
0167
0168
0169
0170
0171
0172 bool is_tail(size_t pos) const
0173 {
0174 return (pos == (nblock - 1) and ntail != 0);
0175 };
0176
0177
0178
0179
0180
0181
0182 void merge_range_pos(it_index itx_first, it_index itx_mid,
0183 it_index itx_last);
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193 void move_range_pos_backward(it_index itx_first, it_index itx_last,
0194 size_t npos);
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204 void rearrange_with_index(void);
0205
0206
0207 };
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222 template<class Iter_t, class Compare, uint32_t Power2>
0223 void merge_block<Iter_t, Compare, Power2>
0224 ::merge_range_pos(it_index itx_first, it_index itx_mid,it_index itx_last)
0225 {
0226 assert((itx_last - itx_mid) >= 0 and (itx_mid - itx_first) >= 0);
0227
0228 size_t nelemA = (itx_mid - itx_first), nelemB = (itx_last - itx_mid);
0229 if (nelemA == 0 or nelemB == 0) return;
0230
0231
0232
0233
0234 std::vector<size_t> indexA, indexB;
0235 indexA.reserve(nelemA + 1);
0236 indexB.reserve(nelemB);
0237
0238 indexA.insert(indexA.begin(), itx_first, itx_mid);
0239 indexB.insert(indexB.begin(), itx_mid, itx_last);
0240
0241 it_index itx_out = itx_first;
0242 it_index itxA = indexA.begin(), itxB = indexB.begin();
0243 range_it rngA, rngB;
0244 Iter_t itA = global_range.first, itB = global_range.first;
0245 bool validA = false, validB = false;
0246
0247 while (itxA != indexA.end() and itxB != indexB.end())
0248 {
0249
0250
0251 if (not validA)
0252 {
0253 rngA = get_range(*itxA);
0254 itA = rngA.first;
0255 validA = true;
0256 };
0257 if (not validB)
0258 {
0259 rngB = get_range(*itxB);
0260 itB = rngB.first;
0261 validB = true;
0262 };
0263
0264
0265
0266
0267 if (ptr_circ->size() == 0)
0268 {
0269 if (not cmp(*rngB.front(), *rngA.back()))
0270 {
0271 *(itx_out++) = *(itxA++);
0272 validA = false;
0273 continue;
0274 };
0275 if (cmp(*rngB.back(), *rngA.front()))
0276 {
0277 if (not is_tail(*itxB))
0278 *(itx_out++) = *itxB;
0279 else ptr_circ->push_move_back(rngB.first, rngB.size());
0280 ++itxB;
0281 validB = false;
0282 continue;
0283 };
0284 };
0285
0286
0287
0288 bool side = util::merge_circular(itA, rngA.last, itB, rngB.last,
0289 *ptr_circ, cmp, itA, itB);
0290 if (side)
0291 {
0292 ptr_circ->pop_move_front(rngA.first, rngA.size());
0293 *(itx_out++) = *(itxA++);
0294 validA = false;
0295 }
0296 else
0297 {
0298 if (not is_tail(*itxB))
0299 {
0300 ptr_circ->pop_move_front(rngB.first, rngB.size());
0301 *(itx_out++) = *itxB;
0302 };
0303 ++itxB;
0304 validB = false;
0305 };
0306 };
0307
0308 if (itxA == indexA.end())
0309 {
0310 rngB = get_range(*itxB);
0311 ptr_circ->pop_move_front(rngB.first, ptr_circ->size());
0312 while (itxB != indexB.end())
0313 *(itx_out++) = *(itxB++);
0314 }
0315 else
0316 {
0317 rngA = get_range(*itxA);
0318 if (ntail != 0 and indexB.back() == (nblock - 1))
0319 {
0320 indexA.push_back(indexB.back());
0321 size_t numA = size_t(itA - rngA.first);
0322 ptr_circ->pop_move_back(rngA.first, numA);
0323 move_range_pos_backward(itxA, indexA.end(), ntail);
0324 };
0325
0326 ptr_circ->pop_move_front(rngA.first, ptr_circ->size());
0327 while (itxA != indexA.end())
0328 *(itx_out++) = *(itxA++);
0329 };
0330 };
0331
0332
0333
0334
0335
0336
0337
0338
0339
0340 template<class Iter_t, class Compare, uint32_t Power2>
0341 void merge_block<Iter_t, Compare, Power2>
0342 ::move_range_pos_backward(it_index itx_first, it_index itx_last, size_t npos)
0343 {
0344 assert((itx_last - itx_first) >= 0 and npos <= BLOCK_SIZE);
0345
0346
0347
0348
0349
0350 range_it rng1 = get_range(*(itx_last - 1));
0351 assert(rng1.size() >= npos);
0352 if (rng1.size() > npos)
0353 {
0354 size_t nmove = rng1.size() - npos;
0355 util::move_backward(rng1.last, rng1.first, rng1.first + nmove);
0356 };
0357
0358
0359
0360 for (it_index itx = itx_last - 1; itx != itx_first;)
0361 {
0362 --itx;
0363 range_it rng2 = rng1;
0364 rng1 = get_range(*itx);
0365 Iter_t it_mid1 = rng1.last - npos, it_mid2 = rng2.first + npos;
0366 util::move_backward(it_mid2, it_mid1, rng1.last);
0367 util::move_backward(rng1.last, rng1.first, it_mid1);
0368 };
0369 };
0370
0371
0372
0373
0374
0375
0376
0377
0378 template<class Iter_t, class Compare, uint32_t Power2>
0379 void merge_block<Iter_t, Compare, Power2>
0380 ::rearrange_with_index(void)
0381 {
0382
0383
0384 size_t pos_dest, pos_src, pos_ini;
0385 size_t nelem = index.size();
0386
0387 ptr_circ->clear();
0388 value_t * aux = ptr_circ->get_buffer();
0389 range_buf rng_buf(aux, aux + ptr_circ->NMAX);
0390
0391 pos_ini = 0;
0392 while (pos_ini < nelem)
0393 {
0394 while (pos_ini < nelem and index[pos_ini] == pos_ini)
0395 ++pos_ini;
0396 if (pos_ini == nelem) return;
0397 pos_dest = pos_src = pos_ini;
0398 rng_buf = move_forward(rng_buf, get_range(pos_ini));
0399 pos_src = index[pos_ini];
0400
0401 while (pos_src != pos_ini)
0402 {
0403 move_forward(get_range(pos_dest), get_range(pos_src));
0404 index[pos_dest] = pos_dest;
0405 pos_dest = pos_src;
0406 pos_src = index[pos_src];
0407 };
0408 move_forward(get_range(pos_dest), rng_buf);
0409 index[pos_dest] = pos_dest;
0410 ++pos_ini;
0411 };
0412 };
0413
0414
0415 };
0416 };
0417 };
0418
0419 #endif