1 /* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License, version 2.0,
5    as published by the Free Software Foundation.
6 
7    This program is also distributed with certain software (including
8    but not limited to OpenSSL) that is licensed under separate terms,
9    as designated in a particular file or component or in included license
10    documentation.  The authors of MySQL hereby grant you an additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License, version 2.0, for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
22 */
23 
24 #ifndef MERGE_SORT_INCLUDED
25 #define MERGE_SORT_INCLUDED
26 
27 /**
28   @file
29 
30   @brief
31   Merge sort and insert sort implementations. These sorting functions
32   are primarily intended for sorting of JOIN_TABs before the greedy
33   search algorithm is applied. Since the JOIN_TAB comparison functions
34   (Join_tab_compare*) are not transitive, the resulting order depends
35   on the sorting implementation to a certain degree.
36 
37   Since the std::stable_sort and std::sort implementations differ
38   between platforms, the result of sorting JOIN_TABs may also differ.
39   In turn, the query execution plan would differ between platforms and
40   that is a problem with mtr tests (EXPLAIN output would vary).
41 
42   If you intend to sort something transitive (which means almost
43   everything except JOIN_TABs) you should most likely use one of the
44   std sorting functions instead of this.
45 */
46 
47 #include <queue>
48 
49 #include "my_dbug.h"
50 
51 /**
52  Sorts the elements in the range [first,last) into ascending order
53  using insertion sort.
54 
55  @param first   First element in an array of pointers to be sorted
56  @param last    Element after the last element in an array of pointers
57                 to be sorted
58  @param comp    Comparison function object that, taking two pointers
59                 of the same type as those contained in the range,
60                 returns true if the first argument goes before the
61                 second argument in the specific strict weak ordering
62                 it defines, and false otherwise.
63 
64  In our case comp should be a function object with an operator:
65 
66  bool operator()(Element_type*, Element_type*)
67 */
68 
69 template <typename Element_type, typename Comp_func>
insert_sort(Element_type ** first,Element_type ** last,Comp_func comp)70 void insert_sort(Element_type **first, Element_type **last, Comp_func comp) {
71   for (Element_type **high_water_mark = first + 1; high_water_mark < last;
72        high_water_mark++) {
73     for (Element_type **cur = high_water_mark; cur > first; cur--) {
74       if (comp(*(cur - 1), *cur)) break;
75 
76       Element_type *tmp = *(cur - 1);
77       *(cur - 1) = *cur;
78       *cur = tmp;
79     }
80   }
81 }
82 
83 /**
84  Sorts the elements in the range [first,last) into ascending order
85  using merge sort.
86 
87  @param first   First element in an array of pointers to be sorted
88  @param last    Element after the last element in an array of pointers
89                 to be sorted
90  @param comp    Comparison function object that, taking two pointers
91                 of the same type as those contained in the range,
92                 returns true if the first argument goes before the
93                 second argument in the specific strict weak ordering
94                 it defines, and false otherwise.
95 
96  In our case comp should be a function object with an operator:
97 
98  bool operator()(Element_type*, Element_type*)
99 */
100 
101 template <typename Element_type, typename Comp_func>
merge_sort(Element_type ** first,Element_type ** last,Comp_func comp)102 void merge_sort(Element_type **first, Element_type **last, Comp_func comp) {
103   const uint elements = static_cast<uint>(last - first);
104 
105   /*
106     Tests showed that the value 5 was a good number for JOIN_TAB
107     ordering, which is the primary use case for this function
108   */
109   if (elements < 5) {
110     insert_sort(first, last, comp);
111     return;
112   }
113   Element_type **middle = first + (elements) / 2;
114 
115   merge_sort(first, middle, comp);
116   merge_sort(middle, last, comp);
117 
118   std::queue<Element_type *> merged;
119 
120   Element_type **cur1 = first;
121   Element_type **cur2 = middle;
122 
123   for (uint i = 0; i < elements; i++) {
124     DBUG_ASSERT(cur1 < middle || cur2 < last);
125 
126     if (cur1 == middle)
127       merged.push(*cur2++);
128     else if (cur2 == last)
129       merged.push(*cur1++);
130     else if (comp(*cur1, *cur2))
131       merged.push(*cur1++);
132     else
133       merged.push(*cur2++);
134   }
135 
136   Element_type **result = first;
137   while (!merged.empty()) {
138     *result++ = merged.front();
139     merged.pop();
140   }
141 }
142 
143 #endif /* MERGE_SORT_INCLUDED */
144