1 /*
2 * Frozen
3 * Copyright 2016 QuarksLab
4 *
5 * Licensed to the Apache Software Foundation (ASF) under one
6 * or more contributor license agreements. See the NOTICE file
7 * distributed with this work for additional information
8 * regarding copyright ownership. The ASF licenses this file
9 * to you under the Apache License, Version 2.0 (the
10 * "License"); you may not use this file except in compliance
11 * with the License. You may obtain a copy of the License at
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing,
16 * software distributed under the License is distributed on an
17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18 * KIND, either express or implied. See the License for the
19 * specific language governing permissions and limitations
20 * under the License.
21 */
22
23 #ifndef FROZEN_LETITGO_BITS_ALGORITHMS_H
24 #define FROZEN_LETITGO_BITS_ALGORITHMS_H
25
26 #include "frozen/bits/basic_types.h"
27
28 #include <limits>
29 #include <tuple>
30
31 namespace frozen {
32
33 namespace bits {
34
next_highest_power_of_two(std::size_t v)35 auto constexpr next_highest_power_of_two(std::size_t v) {
36 // https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
37 constexpr auto trip_count = std::numeric_limits<decltype(v)>::digits;
38 v--;
39 for(std::size_t i = 1; i < trip_count; i <<= 1)
40 v |= v >> i;
41 v++;
42 return v;
43 }
44
45 template<class T>
log(T v)46 auto constexpr log(T v) {
47 std::size_t n = 0;
48 while (v > 1) {
49 n += 1;
50 v >>= 1;
51 }
52 return n;
53 }
54
bit_weight(std::size_t n)55 constexpr std::size_t bit_weight(std::size_t n) {
56 return (n <= 8*sizeof(unsigned int))
57 + (n <= 8*sizeof(unsigned long))
58 + (n <= 8*sizeof(unsigned long long))
59 + (n <= 128);
60 }
61
62 unsigned int select_uint_least(std::integral_constant<std::size_t, 4>);
63 unsigned long select_uint_least(std::integral_constant<std::size_t, 3>);
64 unsigned long long select_uint_least(std::integral_constant<std::size_t, 2>);
65 template<std::size_t N>
select_uint_least(std::integral_constant<std::size_t,N>)66 unsigned long long select_uint_least(std::integral_constant<std::size_t, N>) {
67 static_assert(N < 2, "unsupported type size");
68 return {};
69 }
70
71
72 template<std::size_t N>
73 using select_uint_least_t = decltype(select_uint_least(std::integral_constant<std::size_t, bit_weight(N)>()));
74
75 template <typename Iter, typename Compare>
min_element(Iter begin,const Iter end,Compare const & compare)76 constexpr auto min_element(Iter begin, const Iter end,
77 Compare const &compare) {
78 auto result = begin;
79 while (begin != end) {
80 if (compare(*begin, *result)) {
81 result = begin;
82 }
83 ++begin;
84 }
85 return result;
86 }
87
88 template <class T>
cswap(T & a,T & b)89 constexpr void cswap(T &a, T &b) {
90 auto tmp = a;
91 a = b;
92 b = tmp;
93 }
94
95 template <class T, class U>
cswap(std::pair<T,U> & a,std::pair<T,U> & b)96 constexpr void cswap(std::pair<T, U> & a, std::pair<T, U> & b) {
97 cswap(a.first, b.first);
98 cswap(a.second, b.second);
99 }
100
101 template <class... Tys, std::size_t... Is>
cswap(std::tuple<Tys...> & a,std::tuple<Tys...> & b,std::index_sequence<Is...>)102 constexpr void cswap(std::tuple<Tys...> &a, std::tuple<Tys...> &b, std::index_sequence<Is...>) {
103 using swallow = int[];
104 (void) swallow{(cswap(std::get<Is>(a), std::get<Is>(b)), 0)...};
105 }
106
107 template <class... Tys>
cswap(std::tuple<Tys...> & a,std::tuple<Tys...> & b)108 constexpr void cswap(std::tuple<Tys...> &a, std::tuple<Tys...> &b) {
109 cswap(a, b, std::make_index_sequence<sizeof...(Tys)>());
110 }
111
112 template <typename Iterator, class Compare>
partition(Iterator left,Iterator right,Compare const & compare)113 constexpr Iterator partition(Iterator left, Iterator right, Compare const &compare) {
114 auto pivot = left + (right - left) / 2;
115 auto value = *pivot;
116 cswap(*right, *pivot);
117 for (auto it = left; 0 < right - it; ++it) {
118 if (compare(*it, value)) {
119 cswap(*it, *left);
120 left++;
121 }
122 }
123 cswap(*right, *left);
124 return left;
125 }
126
127 template <typename Iterator, class Compare>
quicksort(Iterator left,Iterator right,Compare const & compare)128 constexpr void quicksort(Iterator left, Iterator right, Compare const &compare) {
129 while (0 < right - left) {
130 auto new_pivot = bits::partition(left, right, compare);
131 quicksort(left, new_pivot, compare);
132 left = new_pivot + 1;
133 }
134 }
135
136 template <typename T, std::size_t N, class Compare>
quicksort(bits::carray<T,N> const & array,Compare const & compare)137 constexpr bits::carray<T, N> quicksort(bits::carray<T, N> const &array,
138 Compare const &compare) {
139 bits::carray<T, N> res = array;
140 quicksort(res.begin(), res.end() - 1, compare);
141 return res;
142 }
143
144 template <class T, class Compare> struct LowerBound {
145 T const &value_;
146 Compare const &compare_;
LowerBoundLowerBound147 constexpr LowerBound(T const &value, Compare const &compare)
148 : value_(value), compare_(compare) {}
149
150 template <class ForwardIt>
doit_fastLowerBound151 inline constexpr ForwardIt doit_fast(ForwardIt first,
152 std::integral_constant<std::size_t, 0>) {
153 return first;
154 }
155
156 template <class ForwardIt, std::size_t N>
doit_fastLowerBound157 inline constexpr ForwardIt doit_fast(ForwardIt first,
158 std::integral_constant<std::size_t, N>) {
159 auto constexpr step = N / 2;
160 static_assert(N/2 == N - N / 2 - 1, "power of two minus 1");
161 auto it = first + step;
162 auto next_it = compare_(*it, value_) ? it + 1 : first;
163 return doit_fast(next_it, std::integral_constant<std::size_t, N / 2>{});
164 }
165
166 template <class ForwardIt, std::size_t N>
doitfirstLowerBound167 inline constexpr ForwardIt doitfirst(ForwardIt first, std::integral_constant<std::size_t, N>, std::integral_constant<bool, true>) {
168 return doit_fast(first, std::integral_constant<std::size_t, N>{});
169 }
170
171 template <class ForwardIt, std::size_t N>
doitfirstLowerBound172 inline constexpr ForwardIt doitfirst(ForwardIt first, std::integral_constant<std::size_t, N>, std::integral_constant<bool, false>) {
173 auto constexpr next_power = next_highest_power_of_two(N);
174 auto constexpr next_start = next_power / 2 - 1;
175 auto it = first + next_start;
176 if (compare_(*it, value_)) {
177 auto constexpr next = N - next_start - 1;
178 return doitfirst(it + 1, std::integral_constant<std::size_t, next>{}, std::integral_constant<bool, next_highest_power_of_two(next) - 1 == next>{});
179 }
180 else
181 return doit_fast(first, std::integral_constant<std::size_t, next_start>{});
182 }
183
184 template <class ForwardIt>
doitfirstLowerBound185 inline constexpr ForwardIt doitfirst(ForwardIt first, std::integral_constant<std::size_t, 1>, std::integral_constant<bool, false>) {
186 return doit_fast(first, std::integral_constant<std::size_t, 1>{});
187 }
188 };
189
190 template <std::size_t N, class ForwardIt, class T, class Compare>
lower_bound(ForwardIt first,const T & value,Compare const & compare)191 constexpr ForwardIt lower_bound(ForwardIt first, const T &value, Compare const &compare) {
192 return LowerBound<T, Compare>{value, compare}.doitfirst(first, std::integral_constant<std::size_t, N>{}, std::integral_constant<bool, next_highest_power_of_two(N) - 1 == N>{});
193 }
194
195 template <std::size_t N, class Compare, class ForwardIt, class T>
binary_search(ForwardIt first,const T & value,Compare const & compare)196 constexpr bool binary_search(ForwardIt first, const T &value,
197 Compare const &compare) {
198 ForwardIt where = lower_bound<N>(first, value, compare);
199 return (!(where == first + N) && !(compare(value, *where)));
200 }
201
202
203 template<class InputIt1, class InputIt2>
equal(InputIt1 first1,InputIt1 last1,InputIt2 first2)204 constexpr bool equal(InputIt1 first1, InputIt1 last1, InputIt2 first2)
205 {
206 for (; first1 != last1; ++first1, ++first2) {
207 if (!(*first1 == *first2)) {
208 return false;
209 }
210 }
211 return true;
212 }
213
214 template<class InputIt1, class InputIt2>
lexicographical_compare(InputIt1 first1,InputIt1 last1,InputIt2 first2,InputIt2 last2)215 constexpr bool lexicographical_compare(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2)
216 {
217 for (; (first1 != last1) && (first2 != last2); ++first1, ++first2) {
218 if (*first1 < *first2)
219 return true;
220 if (*first2 < *first1)
221 return false;
222 }
223 return (first1 == last1) && (first2 != last2);
224 }
225
226 } // namespace bits
227 } // namespace frozen
228
229 #endif
230