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