blob: 463aca3840d67c128112c165135e29c12f8fcc53 [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>
11#include <type_traits>
12#include <vector>
13
14#include "base/logging.h"
15
16// Collection of simple utilities used in for low-level computation.
17
18namespace zucchini {
19
20// Safely determines whether |[begin, begin + size)| is in |[0, bound)|. Note:
21// The special case |[bound, bound)| is not considered to be in |[0, bound)|.
22template <typename T>
23bool RangeIsBounded(T begin, T size, size_t bound) {
24 static_assert(std::is_unsigned<T>::value, "Value type must be unsigned.");
25 return begin < bound && size <= bound - begin;
26}
27
28// Safely determines whether |value| lies in |[begin, begin + size)|. Works
29// properly even if |begin + size| overflows -- although such ranges are
30// considered pathological, and should fail validation elsewhere.
31template <typename T>
32bool RangeCovers(T begin, T size, T value) {
33 static_assert(std::is_unsigned<T>::value, "Value type must be unsigned.");
34 return begin <= value && value - begin < size;
35}
36
37// Returns the integer in inclusive range |[lo, hi]| that's closest to |value|.
38// This departs from the usual usage of semi-inclusive ranges, but is useful
39// because (1) sentinels can use this, (2) a valid output always exists. It is
40// assumed that |lo <= hi|.
41template <class T>
42T InclusiveClamp(T value, T lo, T hi) {
43 static_assert(std::is_unsigned<T>::value, "Value type must be unsigned.");
44 DCHECK_LE(lo, hi);
45 return value <= lo ? lo : (value >= hi ? hi : value);
46}
47
48// Returns the minimum multiple of |m| that's no less than |x|. Assumes |m > 0|
49// and |x| is sufficiently small so that no overflow occurs.
50template <class T>
Samuel Huang607ce602018-06-13 17:47:39 +000051constexpr T AlignCeil(T x, T m) {
Samuel Huang06f1ae92018-03-13 18:19:34 +000052 static_assert(std::is_unsigned<T>::value, "Value type must be unsigned.");
53 return T((x + m - 1) / m) * m;
54}
55
56// Sorts values in |container| and removes duplicates.
57template <class T>
58void SortAndUniquify(std::vector<T>* container) {
59 std::sort(container->begin(), container->end());
60 container->erase(std::unique(container->begin(), container->end()),
61 container->end());
62 container->shrink_to_fit();
63}
64
Samuel Huang607ce602018-06-13 17:47:39 +000065// Extracts a single bit at |pos| from integer |v|.
66template <int pos, typename T>
67constexpr T GetBit(T v) {
68 return (v >> pos) & 1;
69}
70
71// Extracts bits in inclusive range [|lo|, |hi|] from integer |v|, and returns
72// the sign-extend result. For example, let the (MSB-first) bits in a 32-bit int
73// |v| be:
74// xxxxxxxx xxxxxSii iiiiiiii iyyyyyyy,
75// hi^ lo^ => lo = 7, hi = 18
76// To extract "Sii iiiiiiii i", calling
77// GetSignedBits<7, 18>(v);
78// produces the sign-extended result:
79// SSSSSSSS SSSSSSSS SSSSSiii iiiiiiii.
80template <int lo, int hi, typename T>
81constexpr typename std::make_signed<T>::type GetSignedBits(T v) {
82 constexpr int kNumBits = sizeof(T) * 8;
83 using SignedType = typename std::make_signed<T>::type;
84 // Assumes 0 <= |lo| <= |hi| < |kNumBits|.
85 // How this works:
86 // (1) Shift-left by |kNumBits - 1 - hi| to clear "left" bits.
87 // (2) Shift-right by |kNumBits - 1 - hi + lo| to clear "right" bits. The
88 // input is casted to a signed type to perform sign-extension.
89 return static_cast<SignedType>(v << (kNumBits - 1 - hi)) >>
90 (kNumBits - 1 - hi + lo);
91}
92
93// Similar to GetSignedBits(), but returns the zero-extended result. For the
94// above example, calling
95// GetUnsignedBits<7, 18>(v);
96// results in:
97// 00000000 00000000 0000Siii iiiiiiii.
98template <int lo, int hi, typename T>
99constexpr typename std::make_unsigned<T>::type GetUnsignedBits(T v) {
100 constexpr int kNumBits = sizeof(T) * 8;
101 using UnsignedType = typename std::make_unsigned<T>::type;
102 return static_cast<UnsignedType>(v << (kNumBits - 1 - hi)) >>
103 (kNumBits - 1 - hi + lo);
104}
105
Samuel Huang06f1ae92018-03-13 18:19:34 +0000106// Copies bits at |pos| in |v| to all higher bits, and returns the result as the
107// same int type as |v|.
108template <typename T>
109constexpr T SignExtend(int pos, T v) {
110 int kNumBits = sizeof(T) * 8;
111 int kShift = kNumBits - 1 - pos;
112 return static_cast<typename std::make_signed<T>::type>(v << kShift) >> kShift;
113}
114
115// Optimized version where |pos| becomes a template parameter.
116template <int pos, typename T>
117constexpr T SignExtend(T v) {
118 constexpr int kNumBits = sizeof(T) * 8;
119 constexpr int kShift = kNumBits - 1 - pos;
120 return static_cast<typename std::make_signed<T>::type>(v << kShift) >> kShift;
121}
122
Samuel Huang607ce602018-06-13 17:47:39 +0000123// Determines whether |v|, if interpreted as a signed integer, is representable
124// using |digs| bits. |1 <= digs <= sizeof(T)| is assumed.
125template <int digs, typename T>
126constexpr bool SignedFit(T v) {
127 return v == SignExtend<digs - 1, T>(v);
128}
129
Samuel Huang06f1ae92018-03-13 18:19:34 +0000130} // namespace zucchini
131
132#endif // COMPONENTS_ZUCCHINI_ALGORITHM_H_