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