neoGFX
Cross-platform C++ app/game engine
Loading...
Searching...
No Matches
intrusive_sort.hpp
Go to the documentation of this file.
1// intrusive_sort.hpp
2/*
3 * Copyright (c) 2018, 2020 Leigh Johnston.
4 *
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
9 * met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * * Neither the name of Leigh Johnston nor the names of any
19 * other contributors to this software may be used to endorse or
20 * promote products derived from this software without specific prior
21 * written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
24 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
25 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34*/
35
36#pragma once
37
38#include <neolib/neolib.hpp>
39
40namespace neolib
41{
42 namespace detail
43 {
44 template <typename RandomIt, typename Swapper, typename Compare>
45 inline RandomIt partition(RandomIt first, RandomIt last, Swapper swapper, Compare comp)
46 {
47 auto lo = first;
48 auto hi = std::prev(last);
49 auto mid = lo + std::distance(lo, hi) / 2;
50 if (comp(*mid, *lo))
51 swapper(lo, mid);
52 if (comp(*hi, *lo))
53 swapper(lo, hi);
54 if (comp(*mid, *hi))
55 swapper(mid, hi);
56 auto& pivot = *hi;
57 auto i = lo;
58 for (auto j = lo; j != hi; ++j)
59 if (comp(*j, pivot))
60 {
61 swapper(i, j);
62 ++i;
63 }
64 swapper(i, hi);
65 return i;
66 }
67
68 template <typename RandomIt>
69 inline RandomIt heap_parent(RandomIt first, RandomIt node)
70 {
71 return first + (std::distance(first, node) - 1) / 2;
72 }
73
74 template <typename RandomIt>
75 inline RandomIt heap_left_child(RandomIt first, RandomIt node)
76 {
77 return first + 2 * std::distance(first, node) + 1;
78 }
79
80 template <typename RandomIt>
81 inline RandomIt heap_right_child(RandomIt first, RandomIt node)
82 {
83 return first + 2 * std::distance(first, node) + 2;
84 }
85
86 template <typename RandomIt, typename Swapper, typename Compare>
87 inline void siftDown(RandomIt first, RandomIt start, RandomIt end, Swapper swapper, Compare comp)
88 {
89 auto root = start;
90 while (heap_left_child(first, root) < end)
91 {
92 auto child = heap_left_child(first, root);
93 auto swap = root;
94 if (comp(*swap, *child))
95 swap = child;
96 ++child;
97 if (child < end && comp(*swap, *child))
98 swap = child;
99 if (swap == root)
100 return;
101 swapper(root, swap);
102 root = swap;
103 }
104 }
105
106 template <typename RandomIt, typename Swapper, typename Compare>
107 inline void heapify(RandomIt first, RandomIt last, Swapper swapper, Compare comp)
108 {
109 auto end = std::prev(last);
110 auto start = std::next(heap_parent(first, end));
111 while (start > first)
112 {
113 --start;
114 siftDown(first, start, end, swapper, comp);
115 }
116 }
117
118 template <typename RandomIt, typename Swapper, typename Compare>
119 inline void heapsort(RandomIt first, RandomIt last, Swapper swapper, Compare comp)
120 {
121 heapify(first, last, swapper, comp);
122
123 auto end = std::prev(last);
124 while (end > first)
125 {
126 swapper(end, first);
127 siftDown(first, first, end, swapper, comp);
128 --end;
129 }
130 }
131
132 template <typename RandomIt, typename Swapper, typename Compare>
133 inline void introsort(RandomIt first, RandomIt last, Swapper swapper, Compare comp, uint32_t depth)
134 {
135 if (std::distance(first, last) > 1)
136 {
137 if (depth == 0)
138 heapsort(first, last, swapper, comp);
139 else
140 {
141 auto p = partition(first, last, swapper, comp);
142 introsort(first, p, swapper, comp, depth - 1);
143 introsort(p + 1, last, swapper, comp, depth - 1);
144 }
145 }
146 }
147 }
148
149 template <typename RandomIt, typename Swapper, typename Compare>
150 inline void intrusive_sort(RandomIt first, RandomIt last, Swapper swapper, Compare comp)
151 {
152 auto n = std::distance(first, last);
153 if (n <= 1)
154 return;
155 uint32_t maxdepth = static_cast<uint32_t>(std::log2(n)) * 2;
156 detail::introsort(first, last, swapper, comp, maxdepth);
157 }
158
159 template <typename RandomIt, typename Swapper>
160 inline void intrusive_sort(RandomIt first, RandomIt last, Swapper swapper)
161 {
162 intrusive_sort(first, last, swapper, std::less<typename std::iterator_traits<RandomIt>::value_type>{});
163 }
164}
RandomIt partition(RandomIt first, RandomIt last, Swapper swapper, Compare comp)
void heapsort(RandomIt first, RandomIt last, Swapper swapper, Compare comp)
void introsort(RandomIt first, RandomIt last, Swapper swapper, Compare comp, uint32_t depth)
void siftDown(RandomIt first, RandomIt start, RandomIt end, Swapper swapper, Compare comp)
RandomIt heap_parent(RandomIt first, RandomIt node)
void heapify(RandomIt first, RandomIt last, Swapper swapper, Compare comp)
RandomIt heap_right_child(RandomIt first, RandomIt node)
RandomIt heap_left_child(RandomIt first, RandomIt node)
void swap(any &aLhs, any &aRhs)
Definition any.hpp:261
void intrusive_sort(RandomIt first, RandomIt last, Swapper swapper, Compare comp)
it_type next(it_type it, const typename iterator_traits< it_type >::difference_type distance=1)
Definition plf_hive.h:89
iterator_traits< it_type >::difference_type distance(const it_type first, const it_type last)
Definition plf_hive.h:107
it_type prev(it_type it, const typename iterator_traits< it_type >::difference_type distance=1)
Definition plf_hive.h:98