1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #pragma once
6
7 #include <fbl/type_support.h>
8 #include <stdlib.h>
9
10 namespace fbl {
11
12 template<class T>
min(const T & a,const T & b)13 constexpr const T& min(const T& a, const T& b) {
14 return (b < a) ? b : a;
15 }
16
17 template<class T>
max(const T & a,const T & b)18 constexpr const T& max(const T& a, const T& b) {
19 return (a < b) ? b : a;
20 }
21
22 template<class T>
clamp(const T & v,const T & lo,const T & hi)23 constexpr const T& clamp(const T& v, const T& lo, const T& hi) {
24 return (v < lo) ? lo : (hi < v) ? hi : v;
25 }
26
27 // is_pow2
28 //
29 // Test to see if an unsigned integer type is an exact power of two or
30 // not. Note, this needs to use a helper struct because we are not
31 // allowed to partially specialize functions (because C++).
32 namespace internal {
33 template <typename T, typename Enable = void> struct IsPow2Helper;
34
35 template <typename T>
36 struct IsPow2Helper<T, typename enable_if<is_unsigned_integer<T>::value>::type> {
37 static constexpr bool is_pow2(T val) {
38 return (val != 0) && (((val - 1u) & val) == 0);
39 }
40 };
41 }
42
43 // is_pow2<T>(T val)
44 //
45 // Tests to see if val (which may be any unsigned integer type) is a power of 2
46 // or not. 0 is not considered to be a power of 2.
47 //
48 template <typename T>
49 constexpr bool is_pow2(T val) {
50 return internal::IsPow2Helper<T>::is_pow2(val);
51 }
52
53 // round_up rounds up val until it is divisible by multiple.
54 // Zero is divisible by all multiples.
55 template<class T, class U,
56 class L = typename conditional<sizeof(T) >= sizeof(U), T, U>::type,
57 class = typename enable_if<is_unsigned_integer<T>::value>::type,
58 class = typename enable_if<is_unsigned_integer<U>::value>::type>
59 constexpr const L round_up(const T& val_, const U& multiple_) {
60 const L val = static_cast<L>(val_);
61 const L multiple = static_cast<L>(multiple_);
62 return val == 0 ? 0 :
63 is_pow2<L>(multiple) ? (val + (multiple - 1)) & ~(multiple - 1) :
64 ((val + (multiple - 1)) / multiple) * multiple;
65 }
66
67 // round_down rounds down val until it is divisible by multiple.
68 // Zero is divisible by all multiples.
69 template<class T, class U,
70 class L = typename conditional<sizeof(T) >= sizeof(U), T, U>::type,
71 class = typename enable_if<is_unsigned_integer<T>::value>::type,
72 class = typename enable_if<is_unsigned_integer<U>::value>::type>
73 constexpr const L round_down(const T& val_, const U& multiple_) {
74 const L val = static_cast<L>(val_);
75 const L multiple = static_cast<L>(multiple_);
76 return val == 0 ? 0 :
77 is_pow2<L>(multiple) ? val & ~(multiple - 1) :
78 (val / multiple) * multiple;
79 }
80
81 // Returns an iterator to the maximum element in the range [|first|, |last|).
82 //
83 // |first| and |last| must be forward iterators.
84 //
85 // Similar to: <http://en.cppreference.com/w/cpp/algorithm/max_element>
86 template<class FwIterator>
87 FwIterator max_element(FwIterator first, FwIterator last) {
88 FwIterator max = first;
89 while (first < last) {
90 if (*first > *max) {
91 max = first;
92 }
93 first++;
94 }
95 return max;
96 }
97
98 // Returns an iterator to the maximum element in the range [|first|, |last|).
99 // using |comp| to compare elements instead of operator>
100 //
101 // |first| and |last| must be forward iterators.
102 //
103 // Similar to: <http://en.cppreference.com/w/cpp/algorithm/max_element>
104 template<class FwIterator, class Compare>
105 FwIterator max_element(FwIterator first, FwIterator last, Compare comp) {
106 FwIterator max = first;
107 while (first < last) {
108 if (comp(*first, *max)) {
109 max = first;
110 }
111 first++;
112 }
113 return max;
114 }
115
116 // Returns an iterator to the minimum element in the range [|first|, |last|).
117 //
118 // |first| and |last| must be forward iterators.
119 //
120 // Similar to: <http://en.cppreference.com/w/cpp/algorithm/min_element>
121 template<class FwIterator>
122 FwIterator min_element(FwIterator first, FwIterator last) {
123 FwIterator min = first;
124 while (first < last) {
125 if (*first < *min) {
126 min = first;
127 }
128 first++;
129 }
130 return min;
131 }
132
133 // Returns an iterator to the minimum element in the range [|first|, |last|)
134 // using |comp| to compare elements instead of operator<
135 //
136 // |first| and |last| must be forward iterators.
137 //
138 // Similar to: <http://en.cppreference.com/w/cpp/algorithm/min_element>
139 template<class FwIterator, class Compare>
140 FwIterator min_element(FwIterator first, FwIterator last, Compare comp) {
141 FwIterator min = first;
142 while (first < last) {
143 if (comp(*first, *min)) {
144 min = first;
145 }
146 first++;
147 }
148 return min;
149 }
150
151 // Returns a pointer to the first element that is not less than |value|, or
152 // |last| if no such element is found.
153 //
154 // Similar to <http://en.cppreference.com/w/cpp/algorithm/lower_bound>
155 template<class T, class U>
156 const T* lower_bound(const T* first, const T* last, const U& value) {
157 while (first < last) {
158 const T* probe = first + (last - first) / 2;
159 if (*probe < value) {
160 first = probe + 1;
161 } else {
162 last = probe;
163 }
164 }
165 return last;
166 }
167
168 // Returns a pointer to the first element that is not less than |value|, or
169 // |last| if no such element is found.
170 //
171 // |comp| is used to compare the elements rather than operator<.
172 //
173 // Similar to <http://en.cppreference.com/w/cpp/algorithm/lower_bound>
174 template<class T, class U, class Compare>
175 const T* lower_bound(const T* first, const T* last, const U& value, Compare comp) {
176 while (first < last) {
177 const T* probe = first + (last - first) / 2;
178 if (comp(*probe, value)) {
179 first = probe + 1;
180 } else {
181 last = probe;
182 }
183 }
184 return last;
185 }
186
187 template <typename T, size_t N>
188 constexpr size_t count_of(T const(&)[N]) {
189 return N;
190 }
191
192 // 2017-12-10: On ARM/release/GCC, a div(mod)-based implementation runs at 2x
193 // the speed of subtract-based ones, with no O(n) scaling as input values grow.
194 // For x86-64/release/GCC, sub-based methods are initially 20-40% faster (depending
195 // on int type) but scale linearly; they are comparable for values 100000-200000.
196 //
197 // gcd (greatest common divisor) returns the largest non-negative integer that cleanly
198 // divides both inputs. Inputs are unsigned integers. gcd(x,0)=x; gcd(x,1)=1
199 template <typename T, class = typename enable_if<is_unsigned_integer<T>::value>::type>
200 T gcd(T first, T second) {
201 // If function need not support uint8 or uint16, static_casts can be removed
202 while (second != 0) {
203 first = static_cast<T>(first % second);
204 if (first == 0) {
205 return second;
206 }
207 second = static_cast<T>(second % first);
208 }
209
210 return first;
211 }
212
213 // lcm (least common multiple) returns the smallest non-negative integer that is
214 // cleanly divided by both inputs.
215 // Inputs are unsigned integers. lcm(x,0)=0; lcm(x,1)=x
216 template <typename T, class = typename enable_if<is_unsigned_integer<T>::value>::type>
217 T lcm(T first, T second) {
218 if (first == 0 && second == 0) {
219 return 0;
220 }
221
222 // If function need not support uint8 or uint16, static_cast can be removed
223 return static_cast<T>((first / gcd(first, second)) * second);
224 }
225
226 // Accumulates the elements in the range [|first|, |last|) with |initial_value|.
227 // Returns the accumulated value.
228 //
229 // |first| and |last| must be InputIterators.
230 //
231 // Similar to <http://en.cppreference.com/w/cpp/algorithm/accumulate>.
232 template <class InputIterator, class T>
233 T accumulate(InputIterator first, InputIterator last, T initial_value) {
234 while(first < last) {
235 initial_value += *first;
236 first++;
237 }
238 return initial_value;
239 }
240
241 // Accumulates the elements in the range [|first|, |last|) with |initial_value|
242 // using |op| instead of operator+. Returns the accumulated value.
243 //
244 // |first| and |last| must be InputIterators.
245 //
246 // Similar to <http://en.cppreference.com/w/cpp/algorithm/accumulate>.
247 template <class InputIterator, class T, class BinaryOp>
248 T accumulate(InputIterator first, InputIterator last, T initial_value, BinaryOp op) {
249 while(first < last) {
250 initial_value = op(initial_value, *first);
251 first++;
252 }
253 return initial_value;
254 }
255
256 } // namespace fbl
257