File indexing completed on 2025-07-02 08:17:51
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #ifndef BOOST_MOVE_ADAPTIVE_MERGE_HPP
0013 #define BOOST_MOVE_ADAPTIVE_MERGE_HPP
0014
0015 #include <boost/move/detail/config_begin.hpp>
0016 #include <boost/move/algo/detail/adaptive_sort_merge.hpp>
0017 #include <cassert>
0018
0019 #if defined(BOOST_CLANG) || (defined(BOOST_GCC) && (BOOST_GCC >= 40600))
0020 #pragma GCC diagnostic push
0021 #pragma GCC diagnostic ignored "-Wsign-conversion"
0022 #pragma GCC diagnostic ignored "-Wconversion"
0023 #endif
0024
0025 namespace boost {
0026 namespace movelib {
0027
0028
0029 namespace detail_adaptive {
0030
0031 template<class RandIt, class Compare, class XBuf>
0032 inline void adaptive_merge_combine_blocks( RandIt first
0033 , typename iter_size<RandIt>::type len1
0034 , typename iter_size<RandIt>::type len2
0035 , typename iter_size<RandIt>::type collected
0036 , typename iter_size<RandIt>::type n_keys
0037 , typename iter_size<RandIt>::type l_block
0038 , bool use_internal_buf
0039 , bool xbuf_used
0040 , Compare comp
0041 , XBuf & xbuf
0042 )
0043 {
0044 typedef typename iter_size<RandIt>::type size_type;
0045
0046 size_type const len = size_type(len1+len2);
0047 size_type const l_combine = size_type(len-collected);
0048 size_type const l_combine1 = size_type(len1-collected);
0049
0050 if(n_keys){
0051 RandIt const first_data = first+collected;
0052 RandIt const keys = first;
0053 BOOST_MOVE_ADAPTIVE_SORT_PRINT_L2(" A combine: ", len);
0054 if(xbuf_used){
0055 if(xbuf.size() < l_block){
0056 xbuf.initialize_until(l_block, *first);
0057 }
0058 assert(xbuf.size() >= l_block);
0059 size_type n_block_a, n_block_b, l_irreg1, l_irreg2;
0060 combine_params( keys, comp, l_combine
0061 , l_combine1, l_block, xbuf
0062 , n_block_a, n_block_b, l_irreg1, l_irreg2);
0063 op_merge_blocks_with_buf
0064 (keys, comp, first_data, l_block, l_irreg1, n_block_a, n_block_b, l_irreg2, comp, move_op(), xbuf.data());
0065 BOOST_MOVE_ADAPTIVE_SORT_PRINT_L1(" A mrg xbf: ", len);
0066 }
0067 else{
0068 size_type n_block_a, n_block_b, l_irreg1, l_irreg2;
0069 combine_params( keys, comp, l_combine
0070 , l_combine1, l_block, xbuf
0071 , n_block_a, n_block_b, l_irreg1, l_irreg2);
0072 if(use_internal_buf){
0073 op_merge_blocks_with_buf
0074 ( keys, comp, first_data, l_block, l_irreg1, n_block_a, n_block_b
0075 , l_irreg2, comp, swap_op(), first_data-l_block);
0076 BOOST_MOVE_ADAPTIVE_SORT_PRINT_L2(" A mrg buf: ", len);
0077 }
0078 else{
0079 merge_blocks_bufferless
0080 (keys, comp, first_data, l_block, l_irreg1, n_block_a, n_block_b, l_irreg2, comp);
0081 BOOST_MOVE_ADAPTIVE_SORT_PRINT_L1(" A mrg nbf: ", len);
0082 }
0083 }
0084 }
0085 else{
0086 xbuf.shrink_to_fit(l_block);
0087 if(xbuf.size() < l_block){
0088 xbuf.initialize_until(l_block, *first);
0089 }
0090 size_type *const uint_keys = xbuf.template aligned_trailing<size_type>(l_block);
0091 size_type n_block_a, n_block_b, l_irreg1, l_irreg2;
0092 combine_params( uint_keys, less(), l_combine
0093 , l_combine1, l_block, xbuf
0094 , n_block_a, n_block_b, l_irreg1, l_irreg2, true);
0095 BOOST_MOVE_ADAPTIVE_SORT_PRINT_L2(" A combine: ", len);
0096 assert(xbuf.size() >= l_block);
0097 op_merge_blocks_with_buf
0098 (uint_keys, less(), first, l_block, l_irreg1, n_block_a, n_block_b, l_irreg2, comp, move_op(), xbuf.data());
0099 xbuf.clear();
0100 BOOST_MOVE_ADAPTIVE_SORT_PRINT_L1(" A mrg buf: ", len);
0101 }
0102 }
0103
0104 template<class RandIt, class Compare, class XBuf>
0105 inline void adaptive_merge_final_merge( RandIt first
0106 , typename iter_size<RandIt>::type len1
0107 , typename iter_size<RandIt>::type len2
0108 , typename iter_size<RandIt>::type collected
0109 , typename iter_size<RandIt>::type l_intbuf
0110 , typename iter_size<RandIt>::type
0111 , bool
0112 , bool xbuf_used
0113 , Compare comp
0114 , XBuf & xbuf
0115 )
0116 {
0117 typedef typename iter_size<RandIt>::type size_type;
0118
0119 size_type n_keys = size_type(collected-l_intbuf);
0120 size_type len = size_type(len1+len2);
0121 if (!xbuf_used || n_keys) {
0122 xbuf.clear();
0123 const size_type middle = xbuf_used && n_keys ? n_keys: collected;
0124 unstable_sort(first, first + middle, comp, xbuf);
0125 BOOST_MOVE_ADAPTIVE_SORT_PRINT_L2(" A k/b srt: ", len);
0126 stable_merge(first, first + middle, first + len, comp, xbuf);
0127 }
0128 BOOST_MOVE_ADAPTIVE_SORT_PRINT_L1(" A fin mrg: ", len);
0129 }
0130
0131 template<class SizeType>
0132 inline static SizeType adaptive_merge_n_keys_without_external_keys(SizeType l_block, SizeType len1, SizeType len2, SizeType l_intbuf)
0133 {
0134 typedef SizeType size_type;
0135
0136 size_type n_keys = size_type(len1/l_block + len2/l_block);
0137 const size_type second_half_blocks = size_type(len2/l_block);
0138 const size_type first_half_aux = size_type(len1 - l_intbuf);
0139 while(n_keys >= ((first_half_aux-n_keys)/l_block + second_half_blocks)){
0140 --n_keys;
0141 }
0142 ++n_keys;
0143 return n_keys;
0144 }
0145
0146 template<class SizeType>
0147 inline static SizeType adaptive_merge_n_keys_with_external_keys(SizeType l_block, SizeType len1, SizeType len2, SizeType l_intbuf)
0148 {
0149 typedef SizeType size_type;
0150
0151 size_type n_keys = size_type((len1-l_intbuf)/l_block + len2/l_block);
0152 return n_keys;
0153 }
0154
0155 template<class SizeType, class Xbuf>
0156 inline SizeType adaptive_merge_n_keys_intbuf(SizeType &rl_block, SizeType len1, SizeType len2, Xbuf & xbuf, SizeType &l_intbuf_inout)
0157 {
0158 typedef SizeType size_type;
0159 size_type l_block = rl_block;
0160 size_type l_intbuf = xbuf.capacity() >= l_block ? 0u : l_block;
0161
0162 if (xbuf.capacity() > l_block){
0163 l_block = xbuf.capacity();
0164 }
0165
0166
0167 size_type n_keys = adaptive_merge_n_keys_without_external_keys(l_block, len1, len2, l_intbuf);
0168 assert(n_keys >= ((len1-l_intbuf-n_keys)/l_block + len2/l_block));
0169
0170 if(xbuf.template supports_aligned_trailing<size_type>
0171 ( l_block
0172 , adaptive_merge_n_keys_with_external_keys(l_block, len1, len2, l_intbuf)))
0173 {
0174 n_keys = 0u;
0175 }
0176 l_intbuf_inout = l_intbuf;
0177 rl_block = l_block;
0178 return n_keys;
0179 }
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224 template<class RandIt, class Compare, class XBuf>
0225 void adaptive_merge_impl
0226 ( RandIt first
0227 , typename iter_size<RandIt>::type len1
0228 , typename iter_size<RandIt>::type len2
0229 , Compare comp
0230 , XBuf & xbuf
0231 )
0232 {
0233 typedef typename iter_size<RandIt>::type size_type;
0234
0235 if(xbuf.capacity() >= min_value<size_type>(len1, len2)){
0236 buffered_merge( first, first+len1
0237 , first + len1+len2, comp, xbuf);
0238 }
0239 else{
0240 const size_type len = size_type(len1+len2);
0241
0242 size_type l_block = size_type(ceil_sqrt(len));
0243
0244
0245
0246 if(len1 <= l_block*2 || len2 <= l_block*2){
0247 merge_bufferless(first, first+len1, first+len1+len2, comp);
0248 return;
0249 }
0250
0251
0252
0253 size_type l_intbuf = 0;
0254 size_type n_keys = adaptive_merge_n_keys_intbuf(l_block, len1, len2, xbuf, l_intbuf);
0255 size_type const to_collect = size_type(l_intbuf+n_keys);
0256
0257 size_type const collected = collect_unique(first, first+len1, to_collect, comp, xbuf);
0258 BOOST_MOVE_ADAPTIVE_SORT_PRINT_L1("\n A collect: ", len);
0259
0260
0261 if(collected != to_collect && collected < 4){
0262 merge_bufferless(first, first+collected, first+len1, comp);
0263 merge_bufferless(first, first + len1, first + len1 + len2, comp);
0264 return;
0265 }
0266
0267
0268 bool use_internal_buf = collected == to_collect;
0269 if (!use_internal_buf){
0270 l_intbuf = 0u;
0271 n_keys = collected;
0272 l_block = lblock_for_combine(l_intbuf, n_keys, len, use_internal_buf);
0273
0274 l_intbuf = use_internal_buf ? l_block : 0u;
0275 }
0276
0277 bool const xbuf_used = collected == to_collect && xbuf.capacity() >= l_block;
0278
0279 adaptive_merge_combine_blocks(first, len1, len2, collected, n_keys, l_block, use_internal_buf, xbuf_used, comp, xbuf);
0280
0281 adaptive_merge_final_merge (first, len1, len2, collected, l_intbuf, l_block, use_internal_buf, xbuf_used, comp, xbuf);
0282 }
0283 }
0284
0285 }
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305
0306
0307
0308
0309
0310
0311
0312
0313
0314
0315
0316
0317
0318 template<class RandIt, class Compare>
0319 void adaptive_merge( RandIt first, RandIt middle, RandIt last, Compare comp
0320 , typename iterator_traits<RandIt>::value_type* uninitialized = 0
0321 , typename iter_size<RandIt>::type uninitialized_len = 0)
0322 {
0323 typedef typename iter_size<RandIt>::type size_type;
0324 typedef typename iterator_traits<RandIt>::value_type value_type;
0325
0326 if (first == middle || middle == last){
0327 return;
0328 }
0329
0330
0331 do {
0332 if (comp(*middle, *first)){
0333 break;
0334 }
0335 ++first;
0336 if (first == middle)
0337 return;
0338 } while(1);
0339
0340 RandIt first_high(middle);
0341 --first_high;
0342 do {
0343 --last;
0344 if (comp(*last, *first_high)){
0345 ++last;
0346 break;
0347 }
0348 if (last == middle)
0349 return;
0350 } while(1);
0351
0352 ::boost::movelib::adaptive_xbuf<value_type, value_type*, size_type> xbuf(uninitialized, size_type(uninitialized_len));
0353 ::boost::movelib::detail_adaptive::adaptive_merge_impl(first, size_type(middle - first), size_type(last - middle), comp, xbuf);
0354 }
0355
0356 }
0357 }
0358
0359 #if defined(BOOST_CLANG) || (defined(BOOST_GCC) && (BOOST_GCC >= 40600))
0360 #pragma GCC diagnostic pop
0361 #endif
0362
0363 #include <boost/move/detail/config_end.hpp>
0364
0365 #endif