1*a03ca8b9SKrzysztof Kosiński // Copyright 2017 The Chromium Authors. All rights reserved.
2*a03ca8b9SKrzysztof Kosiński // Use of this source code is governed by a BSD-style license that can be
3*a03ca8b9SKrzysztof Kosiński // found in the LICENSE file.
4*a03ca8b9SKrzysztof Kosiński
5*a03ca8b9SKrzysztof Kosiński #ifndef COMPONENTS_ZUCCHINI_ALGORITHM_H_
6*a03ca8b9SKrzysztof Kosiński #define COMPONENTS_ZUCCHINI_ALGORITHM_H_
7*a03ca8b9SKrzysztof Kosiński
8*a03ca8b9SKrzysztof Kosiński #include <stddef.h>
9*a03ca8b9SKrzysztof Kosiński
10*a03ca8b9SKrzysztof Kosiński #include <algorithm>
11*a03ca8b9SKrzysztof Kosiński #include <deque>
12*a03ca8b9SKrzysztof Kosiński #include <type_traits>
13*a03ca8b9SKrzysztof Kosiński #include <vector>
14*a03ca8b9SKrzysztof Kosiński
15*a03ca8b9SKrzysztof Kosiński #include "base/check_op.h"
16*a03ca8b9SKrzysztof Kosiński
17*a03ca8b9SKrzysztof Kosiński // Collection of simple utilities used in for low-level computation.
18*a03ca8b9SKrzysztof Kosiński
19*a03ca8b9SKrzysztof Kosiński namespace zucchini {
20*a03ca8b9SKrzysztof Kosiński
21*a03ca8b9SKrzysztof Kosiński // Safely determines whether |[begin, begin + size)| is in |[0, bound)|. Note:
22*a03ca8b9SKrzysztof Kosiński // The special case |[bound, bound)| is not considered to be in |[0, bound)|.
23*a03ca8b9SKrzysztof Kosiński template <typename T>
RangeIsBounded(T begin,T size,size_t bound)24*a03ca8b9SKrzysztof Kosiński bool RangeIsBounded(T begin, T size, size_t bound) {
25*a03ca8b9SKrzysztof Kosiński static_assert(std::is_unsigned<T>::value, "Value type must be unsigned.");
26*a03ca8b9SKrzysztof Kosiński return begin < bound && size <= bound - begin;
27*a03ca8b9SKrzysztof Kosiński }
28*a03ca8b9SKrzysztof Kosiński
29*a03ca8b9SKrzysztof Kosiński // Safely determines whether |value| lies in |[begin, begin + size)|. Works
30*a03ca8b9SKrzysztof Kosiński // properly even if |begin + size| overflows -- although such ranges are
31*a03ca8b9SKrzysztof Kosiński // considered pathological, and should fail validation elsewhere.
32*a03ca8b9SKrzysztof Kosiński template <typename T>
RangeCovers(T begin,T size,T value)33*a03ca8b9SKrzysztof Kosiński bool RangeCovers(T begin, T size, T value) {
34*a03ca8b9SKrzysztof Kosiński static_assert(std::is_unsigned<T>::value, "Value type must be unsigned.");
35*a03ca8b9SKrzysztof Kosiński return begin <= value && value - begin < size;
36*a03ca8b9SKrzysztof Kosiński }
37*a03ca8b9SKrzysztof Kosiński
38*a03ca8b9SKrzysztof Kosiński // Returns the integer in inclusive range |[lo, hi]| that's closest to |value|.
39*a03ca8b9SKrzysztof Kosiński // This departs from the usual usage of semi-inclusive ranges, but is useful
40*a03ca8b9SKrzysztof Kosiński // because (1) sentinels can use this, (2) a valid output always exists. It is
41*a03ca8b9SKrzysztof Kosiński // assumed that |lo <= hi|.
42*a03ca8b9SKrzysztof Kosiński template <class T>
InclusiveClamp(T value,T lo,T hi)43*a03ca8b9SKrzysztof Kosiński T InclusiveClamp(T value, T lo, T hi) {
44*a03ca8b9SKrzysztof Kosiński static_assert(std::is_unsigned<T>::value, "Value type must be unsigned.");
45*a03ca8b9SKrzysztof Kosiński DCHECK_LE(lo, hi);
46*a03ca8b9SKrzysztof Kosiński return value <= lo ? lo : (value >= hi ? hi : value);
47*a03ca8b9SKrzysztof Kosiński }
48*a03ca8b9SKrzysztof Kosiński
49*a03ca8b9SKrzysztof Kosiński // Returns the minimum multiple of |m| that's no less than |x|. Assumes |m > 0|
50*a03ca8b9SKrzysztof Kosiński // and |x| is sufficiently small so that no overflow occurs.
51*a03ca8b9SKrzysztof Kosiński template <class T>
AlignCeil(T x,T m)52*a03ca8b9SKrzysztof Kosiński constexpr T AlignCeil(T x, T m) {
53*a03ca8b9SKrzysztof Kosiński static_assert(std::is_unsigned<T>::value, "Value type must be unsigned.");
54*a03ca8b9SKrzysztof Kosiński return T((x + m - 1) / m) * m;
55*a03ca8b9SKrzysztof Kosiński }
56*a03ca8b9SKrzysztof Kosiński
57*a03ca8b9SKrzysztof Kosiński // Specialized alignment helpers that returns the increment to |pos| to get the
58*a03ca8b9SKrzysztof Kosiński // next n-aligned value, where n is in {2, 4}. This is useful for aligning
59*a03ca8b9SKrzysztof Kosiński // iterators relative to a base iterator using:
60*a03ca8b9SKrzysztof Kosiński // it += IncrementForAlignCeil2(it - base);
61*a03ca8b9SKrzysztof Kosiński template <class T>
IncrementForAlignCeil2(T pos)62*a03ca8b9SKrzysztof Kosiński inline int IncrementForAlignCeil2(T pos) {
63*a03ca8b9SKrzysztof Kosiński return static_cast<int>(pos & 1); // Optimized from (-pos) & 1.
64*a03ca8b9SKrzysztof Kosiński }
65*a03ca8b9SKrzysztof Kosiński
66*a03ca8b9SKrzysztof Kosiński template <class T>
IncrementForAlignCeil4(T pos)67*a03ca8b9SKrzysztof Kosiński inline int IncrementForAlignCeil4(T pos) {
68*a03ca8b9SKrzysztof Kosiński return static_cast<int>((-pos) & 3);
69*a03ca8b9SKrzysztof Kosiński }
70*a03ca8b9SKrzysztof Kosiński
71*a03ca8b9SKrzysztof Kosiński // Sorts values in |container| and removes duplicates.
72*a03ca8b9SKrzysztof Kosiński template <class T>
SortAndUniquify(std::deque<T> * container)73*a03ca8b9SKrzysztof Kosiński void SortAndUniquify(std::deque<T>* container) {
74*a03ca8b9SKrzysztof Kosiński std::sort(container->begin(), container->end());
75*a03ca8b9SKrzysztof Kosiński container->erase(std::unique(container->begin(), container->end()),
76*a03ca8b9SKrzysztof Kosiński container->end());
77*a03ca8b9SKrzysztof Kosiński container->shrink_to_fit();
78*a03ca8b9SKrzysztof Kosiński }
79*a03ca8b9SKrzysztof Kosiński
80*a03ca8b9SKrzysztof Kosiński // Extracts a single bit at |pos| from integer |v|.
81*a03ca8b9SKrzysztof Kosiński template <int pos, typename T>
GetBit(T v)82*a03ca8b9SKrzysztof Kosiński constexpr T GetBit(T v) {
83*a03ca8b9SKrzysztof Kosiński return (v >> pos) & 1;
84*a03ca8b9SKrzysztof Kosiński }
85*a03ca8b9SKrzysztof Kosiński
86*a03ca8b9SKrzysztof Kosiński // Extracts bits in inclusive range [|lo|, |hi|] from integer |v|, and returns
87*a03ca8b9SKrzysztof Kosiński // the sign-extend result. For example, let the (MSB-first) bits in a 32-bit int
88*a03ca8b9SKrzysztof Kosiński // |v| be:
89*a03ca8b9SKrzysztof Kosiński // xxxxxxxx xxxxxSii iiiiiiii iyyyyyyy,
90*a03ca8b9SKrzysztof Kosiński // hi^ lo^ => lo = 7, hi = 18
91*a03ca8b9SKrzysztof Kosiński // To extract "Sii iiiiiiii i", calling
92*a03ca8b9SKrzysztof Kosiński // GetSignedBits<7, 18>(v);
93*a03ca8b9SKrzysztof Kosiński // produces the sign-extended result:
94*a03ca8b9SKrzysztof Kosiński // SSSSSSSS SSSSSSSS SSSSSiii iiiiiiii.
95*a03ca8b9SKrzysztof Kosiński template <int lo, int hi, typename T>
GetSignedBits(T v)96*a03ca8b9SKrzysztof Kosiński constexpr typename std::make_signed<T>::type GetSignedBits(T v) {
97*a03ca8b9SKrzysztof Kosiński constexpr int kNumBits = sizeof(T) * 8;
98*a03ca8b9SKrzysztof Kosiński using SignedType = typename std::make_signed<T>::type;
99*a03ca8b9SKrzysztof Kosiński // Assumes 0 <= |lo| <= |hi| < |kNumBits|.
100*a03ca8b9SKrzysztof Kosiński // How this works:
101*a03ca8b9SKrzysztof Kosiński // (1) Shift-left by |kNumBits - 1 - hi| to clear "left" bits.
102*a03ca8b9SKrzysztof Kosiński // (2) Shift-right by |kNumBits - 1 - hi + lo| to clear "right" bits. The
103*a03ca8b9SKrzysztof Kosiński // input is casted to a signed type to perform sign-extension.
104*a03ca8b9SKrzysztof Kosiński return static_cast<SignedType>(v << (kNumBits - 1 - hi)) >>
105*a03ca8b9SKrzysztof Kosiński (kNumBits - 1 - hi + lo);
106*a03ca8b9SKrzysztof Kosiński }
107*a03ca8b9SKrzysztof Kosiński
108*a03ca8b9SKrzysztof Kosiński // Similar to GetSignedBits(), but returns the zero-extended result. For the
109*a03ca8b9SKrzysztof Kosiński // above example, calling
110*a03ca8b9SKrzysztof Kosiński // GetUnsignedBits<7, 18>(v);
111*a03ca8b9SKrzysztof Kosiński // results in:
112*a03ca8b9SKrzysztof Kosiński // 00000000 00000000 0000Siii iiiiiiii.
113*a03ca8b9SKrzysztof Kosiński template <int lo, int hi, typename T>
GetUnsignedBits(T v)114*a03ca8b9SKrzysztof Kosiński constexpr typename std::make_unsigned<T>::type GetUnsignedBits(T v) {
115*a03ca8b9SKrzysztof Kosiński constexpr int kNumBits = sizeof(T) * 8;
116*a03ca8b9SKrzysztof Kosiński using UnsignedType = typename std::make_unsigned<T>::type;
117*a03ca8b9SKrzysztof Kosiński return static_cast<UnsignedType>(v << (kNumBits - 1 - hi)) >>
118*a03ca8b9SKrzysztof Kosiński (kNumBits - 1 - hi + lo);
119*a03ca8b9SKrzysztof Kosiński }
120*a03ca8b9SKrzysztof Kosiński
121*a03ca8b9SKrzysztof Kosiński // Copies bits at |pos| in |v| to all higher bits, and returns the result as the
122*a03ca8b9SKrzysztof Kosiński // same int type as |v|.
123*a03ca8b9SKrzysztof Kosiński template <typename T>
SignExtend(int pos,T v)124*a03ca8b9SKrzysztof Kosiński constexpr T SignExtend(int pos, T v) {
125*a03ca8b9SKrzysztof Kosiński int kNumBits = sizeof(T) * 8;
126*a03ca8b9SKrzysztof Kosiński int kShift = kNumBits - 1 - pos;
127*a03ca8b9SKrzysztof Kosiński return static_cast<typename std::make_signed<T>::type>(v << kShift) >> kShift;
128*a03ca8b9SKrzysztof Kosiński }
129*a03ca8b9SKrzysztof Kosiński
130*a03ca8b9SKrzysztof Kosiński // Optimized version where |pos| becomes a template parameter.
131*a03ca8b9SKrzysztof Kosiński template <int pos, typename T>
SignExtend(T v)132*a03ca8b9SKrzysztof Kosiński constexpr T SignExtend(T v) {
133*a03ca8b9SKrzysztof Kosiński constexpr int kNumBits = sizeof(T) * 8;
134*a03ca8b9SKrzysztof Kosiński constexpr int kShift = kNumBits - 1 - pos;
135*a03ca8b9SKrzysztof Kosiński return static_cast<typename std::make_signed<T>::type>(v << kShift) >> kShift;
136*a03ca8b9SKrzysztof Kosiński }
137*a03ca8b9SKrzysztof Kosiński
138*a03ca8b9SKrzysztof Kosiński // Determines whether |v|, if interpreted as a signed integer, is representable
139*a03ca8b9SKrzysztof Kosiński // using |digs| bits. |1 <= digs <= sizeof(T)| is assumed.
140*a03ca8b9SKrzysztof Kosiński template <int digs, typename T>
SignedFit(T v)141*a03ca8b9SKrzysztof Kosiński constexpr bool SignedFit(T v) {
142*a03ca8b9SKrzysztof Kosiński return v == SignExtend<digs - 1, T>(v);
143*a03ca8b9SKrzysztof Kosiński }
144*a03ca8b9SKrzysztof Kosiński
145*a03ca8b9SKrzysztof Kosiński } // namespace zucchini
146*a03ca8b9SKrzysztof Kosiński
147*a03ca8b9SKrzysztof Kosiński #endif // COMPONENTS_ZUCCHINI_ALGORITHM_H_
148