1 //////////////////////////////////////////////////////////////////////////////
3 // (C) Copyright Ion Gaztanaga 2015-2016.
4 // Distributed under the Boost Software License, Version 1.0.
5 // (See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
8 // See http://www.boost.org/libs/move for documentation.
10 //////////////////////////////////////////////////////////////////////////////
11 #ifndef BOOST_MOVE_MERGE_HPP
12 #define BOOST_MOVE_MERGE_HPP
14 #include <boost/core/ignore_unused.hpp>
15 #include <boost/move/algo/move.hpp>
16 #include <boost/move/adl_move_swap.hpp>
17 #include <boost/move/algo/detail/basic_op.hpp>
18 #include <boost/move/detail/iterator_traits.hpp>
19 #include <boost/move/detail/destruct_n.hpp>
20 #include <boost/move/algo/predicate.hpp>
21 #include <boost/move/detail/iterator_to_raw_pointer.hpp>
22 #include <boost/assert.hpp>
25 #if defined(BOOST_CLANG) || (defined(BOOST_GCC) && (BOOST_GCC >= 40600))
26 #pragma GCC diagnostic push
27 #pragma GCC diagnostic ignored "-Wsign-conversion"
33 template<class T, class RandRawIt = T*, class SizeType = typename iter_size<RandRawIt>::type>
36 adaptive_xbuf(const adaptive_xbuf &);
37 adaptive_xbuf & operator=(const adaptive_xbuf &);
39 #if !defined(UINTPTR_MAX)
40 typedef std::size_t uintptr_t;
44 typedef RandRawIt iterator;
45 typedef SizeType size_type;
47 BOOST_MOVE_FORCEINLINE adaptive_xbuf()
48 : m_ptr(), m_size(0), m_capacity(0)
51 BOOST_MOVE_FORCEINLINE adaptive_xbuf(RandRawIt raw_memory, size_type cap)
52 : m_ptr(raw_memory), m_size(0), m_capacity(cap)
55 template<class RandIt>
56 void move_assign(RandIt first, size_type n)
58 typedef typename iterator_traits<RandIt>::difference_type rand_diff_t;
60 boost::move(first, first+rand_diff_t(n), m_ptr);
61 size_type sz = m_size;
68 RandRawIt result = boost::move(first, first+rand_diff_t(m_size), m_ptr);
69 boost::uninitialized_move(first+rand_diff_t(m_size), first+rand_diff_t(n), result);
74 template<class RandIt>
75 void push_back(RandIt first, size_type n)
77 BOOST_ASSERT(m_capacity - m_size >= n);
78 boost::uninitialized_move(first, first+n, m_ptr+m_size);
82 template<class RandIt>
83 iterator add(RandIt it)
85 BOOST_ASSERT(m_size < m_capacity);
86 RandRawIt p_ret = m_ptr + m_size;
87 ::new(&*p_ret) T(::boost::move(*it));
92 template<class RandIt>
93 void insert(iterator pos, RandIt it)
95 if(pos == (m_ptr + m_size)){
99 this->add(m_ptr+m_size-1);
101 boost::move_backward(pos, m_ptr+m_size-2, m_ptr+m_size-1);
102 *pos = boost::move(*it);
106 BOOST_MOVE_FORCEINLINE void set_size(size_type sz)
111 void shrink_to_fit(size_type const sz)
114 for(size_type szt_i = sz; szt_i != m_size; ++szt_i){
121 void initialize_until(size_type const sz, T &t)
123 BOOST_ASSERT(m_size < m_capacity);
127 ::new((void*)&m_ptr[m_size]) T(::boost::move(t));
129 for(; m_size != sz; ++m_size){
130 ::new((void*)&m_ptr[m_size]) T(::boost::move(m_ptr[m_size-1]));
132 t = ::boost::move(m_ptr[m_size-1]);
148 BOOST_MOVE_FORCEINLINE static bool is_raw_ptr(RIt)
153 BOOST_MOVE_FORCEINLINE static bool is_raw_ptr(T*)
160 bool supports_aligned_trailing(size_type sz, size_type trail_count) const
162 if(this->is_raw_ptr(this->data()) && m_capacity){
163 uintptr_t u_addr_sz = uintptr_t(&*(this->data()+sz));
164 uintptr_t u_addr_cp = uintptr_t(&*(this->data()+this->capacity()));
165 u_addr_sz = ((u_addr_sz + sizeof(U)-1)/sizeof(U))*sizeof(U);
166 return (u_addr_cp >= u_addr_sz) && ((u_addr_cp - u_addr_sz)/sizeof(U) >= trail_count);
172 BOOST_MOVE_FORCEINLINE U *aligned_trailing() const
174 return this->aligned_trailing<U>(this->size());
178 BOOST_MOVE_FORCEINLINE U *aligned_trailing(size_type pos) const
180 uintptr_t u_addr = uintptr_t(&*(this->data()+pos));
181 u_addr = ((u_addr + sizeof(U)-1)/sizeof(U))*sizeof(U);
185 BOOST_MOVE_FORCEINLINE ~adaptive_xbuf()
190 BOOST_MOVE_FORCEINLINE size_type capacity() const
191 { return m_capacity; }
193 BOOST_MOVE_FORCEINLINE iterator data() const
196 BOOST_MOVE_FORCEINLINE iterator begin() const
199 BOOST_MOVE_FORCEINLINE iterator end() const
200 { return m_ptr+m_size; }
202 BOOST_MOVE_FORCEINLINE size_type size() const
205 BOOST_MOVE_FORCEINLINE bool empty() const
208 BOOST_MOVE_FORCEINLINE void clear()
210 this->shrink_to_fit(0u);
216 size_type m_capacity;
219 template<class Iterator, class SizeType, class Op>
222 range_xbuf(const range_xbuf &);
223 range_xbuf & operator=(const range_xbuf &);
226 typedef SizeType size_type;
227 typedef Iterator iterator;
229 range_xbuf(Iterator first, Iterator last)
230 : m_first(first), m_last(first), m_cap(last)
233 template<class RandIt>
234 void move_assign(RandIt first, size_type n)
236 BOOST_ASSERT(size_type(n) <= size_type(m_cap-m_first));
237 typedef typename iter_difference<RandIt>::type d_type;
238 m_last = Op()(forward_t(), first, first+d_type(n), m_first);
244 size_type capacity() const
245 { return m_cap-m_first; }
247 Iterator data() const
253 size_type size() const
254 { return m_last-m_first; }
257 { return m_first == m_last; }
264 template<class RandIt>
265 iterator add(RandIt it)
267 Iterator pos(m_last);
268 *pos = boost::move(*it);
273 void set_size(size_type sz)
280 Iterator const m_first;
282 Iterator const m_cap;
290 template<typename Unsigned>
291 inline Unsigned gcd(Unsigned x, Unsigned y)
293 if(0 == ((x &(x-1)) | (y & (y-1)))){
294 return x < y ? x : y;
308 //Modified version from "An Optimal In-Place Array Rotation Algorithm", Ching-Kuang Shene
309 template<typename Unsigned>
310 Unsigned gcd(Unsigned x, Unsigned y)
312 if(0 == ((x &(x-1)) | (y & (y-1)))){
313 return x < y ? x : y;
317 while((!(x&1)) & (!(y&1))){
318 z = Unsigned(z << 1);
319 x = Unsigned(x >> 1);
320 y = Unsigned(y >> 1);
324 x = Unsigned(x >> 1);
326 y = Unsigned (y >> 1);
328 x = Unsigned((x-y) >> 1u);
330 y = Unsigned((y-x) >> 1);
332 return Unsigned(z*(x+y));
336 template<typename RandIt>
337 RandIt rotate_gcd(RandIt first, RandIt middle, RandIt last)
339 typedef typename iter_size<RandIt>::type size_type;
340 typedef typename iterator_traits<RandIt>::value_type value_type;
346 const size_type middle_pos = size_type(middle - first);
347 RandIt ret = last - middle_pos;
349 boost::adl_move_swap_ranges(first, middle, middle);
352 const size_type length = size_type(last - first);
353 for( RandIt it_i(first), it_gcd(it_i + gcd(length, middle_pos))
356 value_type temp(boost::move(*it_i));
358 RandIt it_k = it_j+middle_pos;
360 *it_j = boost::move(*it_k);
362 size_type const left = size_type(last - it_j);
363 it_k = left > middle_pos ? it_j + middle_pos : first + middle_pos - left;
364 } while(it_k != it_i);
365 *it_j = boost::move(temp);
371 template <class RandIt, class T, class Compare>
373 (RandIt first, const RandIt last, const T& key, Compare comp)
375 typedef typename iter_size<RandIt>::type size_type;
376 size_type len = size_type(last - first);
380 size_type step = size_type(len >> 1);
384 if (comp(*middle, key)) {
386 len = size_type(len - (step + 1));
395 template <class RandIt, class T, class Compare>
397 (RandIt first, const RandIt last, const T& key, Compare comp)
399 typedef typename iter_size<RandIt>::type size_type;
400 size_type len = size_type(last - first);
404 size_type step = size_type(len >> 1);
408 if (!comp(key, *middle)) {
410 len = size_type(len - (step + 1));
420 template<class RandIt, class Compare, class Op>
421 void op_merge_left( RandIt buf_first
428 for(RandIt first2=last1; first2 != last2; ++buf_first){
430 op(forward_t(), first2, last2, buf_first);
433 else if(comp(*first2, *first1)){
434 op(first2, buf_first);
438 op(first1, buf_first);
442 if(buf_first != first1){//In case all remaining elements are in the same place
443 //(e.g. buffer is exactly the size of the second half
444 //and all elements from the second half are less)
445 op(forward_t(), first1, last1, buf_first);
449 // [buf_first, first1) -> buffer
450 // [first1, last1) merge [last1,last2) -> [buf_first,buf_first+(last2-first1))
451 // Elements from buffer are moved to [last2 - (first1-buf_first), last2)
452 // Note: distance(buf_first, first1) >= distance(last1, last2), so no overlapping occurs
453 template<class RandIt, class Compare>
455 (RandIt buf_first, RandIt first1, RandIt const last1, RandIt const last2, Compare comp)
457 op_merge_left(buf_first, first1, last1, last2, comp, move_op());
460 // [buf_first, first1) -> buffer
461 // [first1, last1) merge [last1,last2) -> [buf_first,buf_first+(last2-first1))
462 // Elements from buffer are swapped to [last2 - (first1-buf_first), last2)
463 // Note: distance(buf_first, first1) >= distance(last1, last2), so no overlapping occurs
464 template<class RandIt, class Compare>
466 (RandIt buf_first, RandIt first1, RandIt const last1, RandIt const last2, Compare comp)
468 op_merge_left(buf_first, first1, last1, last2, comp, swap_op());
471 template<class RandIt, class Compare, class Op>
473 (RandIt const first1, RandIt last1, RandIt last2, RandIt buf_last, Compare comp, Op op)
475 RandIt const first2 = last1;
476 while(first1 != last1){
478 op(backward_t(), first1, last1, buf_last);
484 if(comp(*last2, *last1)){
493 if(last2 != buf_last){ //In case all remaining elements are in the same place
494 //(e.g. buffer is exactly the size of the first half
495 //and all elements from the second half are less)
496 op(backward_t(), first2, last2, buf_last);
500 // [last2, buf_last) - buffer
501 // [first1, last1) merge [last1,last2) -> [first1+(buf_last-last2), buf_last)
502 // Note: distance[last2, buf_last) >= distance[first1, last1), so no overlapping occurs
503 template<class RandIt, class Compare>
505 (RandIt first1, RandIt last1, RandIt last2, RandIt buf_last, Compare comp)
507 op_merge_right(first1, last1, last2, buf_last, comp, move_op());
510 // [last2, buf_last) - buffer
511 // [first1, last1) merge [last1,last2) -> [first1+(buf_last-last2), buf_last)
512 // Note: distance[last2, buf_last) >= distance[first1, last1), so no overlapping occurs
513 template<class RandIt, class Compare>
514 void swap_merge_right
515 (RandIt first1, RandIt last1, RandIt last2, RandIt buf_last, Compare comp)
517 op_merge_right(first1, last1, last2, buf_last, comp, swap_op());
520 ///////////////////////////////////////////////////////////////////////////////
524 ///////////////////////////////////////////////////////////////////////////////
525 template<class RandIt, class Compare, class Op, class Buf>
526 void op_buffered_merge
527 ( RandIt first, RandIt const middle, RandIt last
528 , Compare comp, Op op
531 if(first != middle && middle != last && comp(*middle, middle[-1])){
532 typedef typename iter_size<RandIt>::type size_type;
533 size_type const len1 = size_type(middle-first);
534 size_type const len2 = size_type(last-middle);
536 first = boost::movelib::upper_bound(first, middle, *middle, comp);
537 xbuf.move_assign(first, size_type(middle-first));
538 op_merge_with_right_placed
539 (xbuf.data(), xbuf.end(), first, middle, last, comp, op);
542 last = boost::movelib::lower_bound(middle, last, middle[-1], comp);
543 xbuf.move_assign(middle, size_type(last-middle));
544 op_merge_with_left_placed
545 (first, middle, last, xbuf.data(), xbuf.end(), comp, op);
550 template<class RandIt, class Compare, class XBuf>
552 ( RandIt first, RandIt const middle, RandIt last
556 op_buffered_merge(first, middle, last, comp, move_op(), xbuf);
559 //Complexity: min(len1,len2)^2 + max(len1,len2)
560 template<class RandIt, class Compare>
561 void merge_bufferless_ON2(RandIt first, RandIt middle, RandIt last, Compare comp)
563 if((middle - first) < (last - middle)){
564 while(first != middle){
565 RandIt const old_last1 = middle;
566 middle = boost::movelib::lower_bound(middle, last, *first, comp);
567 first = rotate_gcd(first, old_last1, middle);
573 } while(first != middle && !comp(*middle, *first));
577 while(middle != last){
578 RandIt p = boost::movelib::upper_bound(first, middle, last[-1], comp);
579 last = rotate_gcd(p, middle, last);
587 } while(middle != last && !comp(last[-1], *p));
592 static const std::size_t MergeBufferlessONLogNRotationThreshold = 16u;
594 template <class RandIt, class Compare>
595 void merge_bufferless_ONlogN_recursive
596 ( RandIt first, RandIt middle, RandIt last
597 , typename iter_size<RandIt>::type len1
598 , typename iter_size<RandIt>::type len2
601 typedef typename iter_size<RandIt>::type size_type;
611 else if (size_type(len1 | len2) == 1u) {
612 if (comp(*middle, *first))
613 adl_move_swap(*first, *middle);
616 else if(size_type(len1+len2) < MergeBufferlessONLogNRotationThreshold){
617 merge_bufferless_ON2(first, middle, last, comp);
621 RandIt first_cut = first;
622 RandIt second_cut = middle;
628 second_cut = boost::movelib::lower_bound(middle, last, *first_cut, comp);
629 len22 = size_type(second_cut - middle);
634 first_cut = boost::movelib::upper_bound(first, middle, *second_cut, comp);
635 len11 = size_type(first_cut - first);
637 RandIt new_middle = rotate_gcd(first_cut, middle, second_cut);
639 //Avoid one recursive call doing a manual tail call elimination on the biggest range
640 const size_type len_internal = size_type(len11+len22);
641 if( len_internal < (len1 + len2 - len_internal) ) {
642 merge_bufferless_ONlogN_recursive(first, first_cut, new_middle, len11, len22, comp);
645 len1 = size_type(len1-len11);
646 len2 = size_type(len2-len22);
649 merge_bufferless_ONlogN_recursive
650 (new_middle, second_cut, last, size_type(len1 - len11), size_type(len2 - len22), comp);
661 template<class RandIt, class Compare>
662 void merge_bufferless_ONlogN(RandIt first, RandIt middle, RandIt last, Compare comp)
664 typedef typename iter_size<RandIt>::type size_type;
665 merge_bufferless_ONlogN_recursive
666 (first, middle, last, size_type(middle - first), size_type(last - middle), comp);
669 template<class RandIt, class Compare>
670 void merge_bufferless(RandIt first, RandIt middle, RandIt last, Compare comp)
672 #define BOOST_ADAPTIVE_MERGE_NLOGN_MERGE
673 #ifdef BOOST_ADAPTIVE_MERGE_NLOGN_MERGE
674 merge_bufferless_ONlogN(first, middle, last, comp);
676 merge_bufferless_ON2(first, middle, last, comp);
677 #endif //BOOST_ADAPTIVE_MERGE_NLOGN_MERGE
680 // [r_first, r_last) are already in the right part of the destination range.
681 template <class Compare, class InputIterator, class InputOutIterator, class Op>
682 void op_merge_with_right_placed
683 ( InputIterator first, InputIterator last
684 , InputOutIterator dest_first, InputOutIterator r_first, InputOutIterator r_last
685 , Compare comp, Op op)
687 BOOST_ASSERT((last - first) == (r_first - dest_first));
688 while ( first != last ) {
689 if (r_first == r_last) {
690 InputOutIterator end = op(forward_t(), first, last, dest_first);
691 BOOST_ASSERT(end == r_last);
692 boost::ignore_unused(end);
695 else if (comp(*r_first, *first)) {
696 op(r_first, dest_first);
700 op(first, dest_first);
705 // Remaining [r_first, r_last) already in the correct place
708 template <class Compare, class InputIterator, class InputOutIterator>
709 void swap_merge_with_right_placed
710 ( InputIterator first, InputIterator last
711 , InputOutIterator dest_first, InputOutIterator r_first, InputOutIterator r_last
714 op_merge_with_right_placed(first, last, dest_first, r_first, r_last, comp, swap_op());
717 // [first, last) are already in the right part of the destination range.
718 template <class Compare, class Op, class BidirIterator, class BidirOutIterator>
719 void op_merge_with_left_placed
720 ( BidirOutIterator const first, BidirOutIterator last, BidirOutIterator dest_last
721 , BidirIterator const r_first, BidirIterator r_last
722 , Compare comp, Op op)
724 BOOST_ASSERT((dest_last - last) == (r_last - r_first));
725 while( r_first != r_last ) {
727 BidirOutIterator res = op(backward_t(), r_first, r_last, dest_last);
728 BOOST_ASSERT(last == res);
729 boost::ignore_unused(res);
734 if(comp(*r_last, *last)){
742 op(r_last, dest_last);
745 // Remaining [first, last) already in the correct place
750 // [first, last) are already in the right part of the destination range.
751 template <class Compare, class BidirIterator, class BidirOutIterator>
752 void merge_with_left_placed
753 ( BidirOutIterator const first, BidirOutIterator last, BidirOutIterator dest_last
754 , BidirIterator const r_first, BidirIterator r_last
757 op_merge_with_left_placed(first, last, dest_last, r_first, r_last, comp, move_op());
760 // [r_first, r_last) are already in the right part of the destination range.
761 template <class Compare, class InputIterator, class InputOutIterator>
762 void merge_with_right_placed
763 ( InputIterator first, InputIterator last
764 , InputOutIterator dest_first, InputOutIterator r_first, InputOutIterator r_last
767 op_merge_with_right_placed(first, last, dest_first, r_first, r_last, comp, move_op());
770 // [r_first, r_last) are already in the right part of the destination range.
771 // [dest_first, r_first) is uninitialized memory
772 template <class Compare, class InputIterator, class InputOutIterator>
773 void uninitialized_merge_with_right_placed
774 ( InputIterator first, InputIterator last
775 , InputOutIterator dest_first, InputOutIterator r_first, InputOutIterator r_last
778 BOOST_ASSERT((last - first) == (r_first - dest_first));
779 typedef typename iterator_traits<InputOutIterator>::value_type value_type;
780 InputOutIterator const original_r_first = r_first;
782 destruct_n<value_type, InputOutIterator> d(dest_first);
784 while ( first != last && dest_first != original_r_first ) {
785 if (r_first == r_last) {
786 for(; dest_first != original_r_first; ++dest_first, ++first){
787 ::new((iterator_to_raw_pointer)(dest_first)) value_type(::boost::move(*first));
791 InputOutIterator end = ::boost::move(first, last, original_r_first);
792 BOOST_ASSERT(end == r_last);
793 boost::ignore_unused(end);
796 else if (comp(*r_first, *first)) {
797 ::new((iterator_to_raw_pointer)(dest_first)) value_type(::boost::move(*r_first));
802 ::new((iterator_to_raw_pointer)(dest_first)) value_type(::boost::move(*first));
809 merge_with_right_placed(first, last, original_r_first, r_first, r_last, comp);
812 /// This is a helper function for the merge routines.
813 template<typename BidirectionalIterator1, typename BidirectionalIterator2>
814 BidirectionalIterator1
815 rotate_adaptive(BidirectionalIterator1 first,
816 BidirectionalIterator1 middle,
817 BidirectionalIterator1 last,
818 typename iter_size<BidirectionalIterator1>::type len1,
819 typename iter_size<BidirectionalIterator1>::type len2,
820 BidirectionalIterator2 buffer,
821 typename iter_size<BidirectionalIterator1>::type buffer_size)
823 if (len1 > len2 && len2 <= buffer_size)
825 if(len2) //Protect against self-move ranges
827 BidirectionalIterator2 buffer_end = boost::move(middle, last, buffer);
828 boost::move_backward(first, middle, last);
829 return boost::move(buffer, buffer_end, first);
834 else if (len1 <= buffer_size)
836 if(len1) //Protect against self-move ranges
838 BidirectionalIterator2 buffer_end = boost::move(first, middle, buffer);
839 BidirectionalIterator1 ret = boost::move(middle, last, first);
840 boost::move(buffer, buffer_end, ret);
847 return rotate_gcd(first, middle, last);
850 template<typename BidirectionalIterator,
851 typename Pointer, typename Compare>
852 void merge_adaptive_ONlogN_recursive
853 (BidirectionalIterator first,
854 BidirectionalIterator middle,
855 BidirectionalIterator last,
856 typename iter_size<BidirectionalIterator>::type len1,
857 typename iter_size<BidirectionalIterator>::type len2,
859 typename iter_size<BidirectionalIterator>::type buffer_size,
862 typedef typename iter_size<BidirectionalIterator>::type size_type;
864 if (!len2 || !len1) {
867 else if (len1 <= buffer_size || len2 <= buffer_size) {
868 range_xbuf<Pointer, size_type, move_op> rxbuf(buffer, buffer + buffer_size);
869 buffered_merge(first, middle, last, comp, rxbuf);
871 else if (size_type(len1 + len2) == 2u) {
872 if (comp(*middle, *first))
873 adl_move_swap(*first, *middle);
875 else if (size_type(len1 + len2) < MergeBufferlessONLogNRotationThreshold) {
876 merge_bufferless_ON2(first, middle, last, comp);
879 BidirectionalIterator first_cut = first;
880 BidirectionalIterator second_cut = middle;
883 if (len1 > len2) //(len1 < len2)
887 second_cut = boost::movelib::lower_bound(middle, last, *first_cut, comp);
888 len22 = size_type(second_cut - middle);
894 first_cut = boost::movelib::upper_bound(first, middle, *second_cut, comp);
895 len11 = size_type(first_cut - first);
898 BidirectionalIterator new_middle
899 = rotate_adaptive(first_cut, middle, second_cut,
900 size_type(len1 - len11), len22, buffer,
902 merge_adaptive_ONlogN_recursive(first, first_cut, new_middle, len11,
903 len22, buffer, buffer_size, comp);
904 merge_adaptive_ONlogN_recursive(new_middle, second_cut, last,
905 size_type(len1 - len11), size_type(len2 - len22), buffer, buffer_size, comp);
910 template<typename BidirectionalIterator, typename Compare, typename RandRawIt>
911 void merge_adaptive_ONlogN(BidirectionalIterator first,
912 BidirectionalIterator middle,
913 BidirectionalIterator last,
915 RandRawIt uninitialized,
916 typename iter_size<BidirectionalIterator>::type uninitialized_len)
918 typedef typename iterator_traits<BidirectionalIterator>::value_type value_type;
919 typedef typename iter_size<BidirectionalIterator>::type size_type;
921 if (first == middle || middle == last)
924 if(uninitialized_len)
926 const size_type len1 = size_type(middle - first);
927 const size_type len2 = size_type(last - middle);
929 ::boost::movelib::adaptive_xbuf<value_type, RandRawIt> xbuf(uninitialized, uninitialized_len);
930 xbuf.initialize_until(uninitialized_len, *first);
931 merge_adaptive_ONlogN_recursive(first, middle, last, len1, len2, xbuf.begin(), uninitialized_len, comp);
935 merge_bufferless(first, middle, last, comp);
939 } //namespace movelib {
940 } //namespace boost {
942 #if defined(BOOST_CLANG) || (defined(BOOST_GCC) && (BOOST_GCC >= 40600))
943 #pragma GCC diagnostic pop
946 #endif //#define BOOST_MOVE_MERGE_HPP