148 lines
5.3 KiB
C++
148 lines
5.3 KiB
C++
// Copyright 2017 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#ifndef COMPONENTS_ZUCCHINI_ALGORITHM_H_
|
|
#define COMPONENTS_ZUCCHINI_ALGORITHM_H_
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <algorithm>
|
|
#include <deque>
|
|
#include <type_traits>
|
|
#include <vector>
|
|
|
|
#include "base/check_op.h"
|
|
|
|
// Collection of simple utilities used in for low-level computation.
|
|
|
|
namespace zucchini {
|
|
|
|
// Safely determines whether |[begin, begin + size)| is in |[0, bound)|. Note:
|
|
// The special case |[bound, bound)| is not considered to be in |[0, bound)|.
|
|
template <typename T>
|
|
bool RangeIsBounded(T begin, T size, size_t bound) {
|
|
static_assert(std::is_unsigned<T>::value, "Value type must be unsigned.");
|
|
return begin < bound && size <= bound - begin;
|
|
}
|
|
|
|
// Safely determines whether |value| lies in |[begin, begin + size)|. Works
|
|
// properly even if |begin + size| overflows -- although such ranges are
|
|
// considered pathological, and should fail validation elsewhere.
|
|
template <typename T>
|
|
bool RangeCovers(T begin, T size, T value) {
|
|
static_assert(std::is_unsigned<T>::value, "Value type must be unsigned.");
|
|
return begin <= value && value - begin < size;
|
|
}
|
|
|
|
// Returns the integer in inclusive range |[lo, hi]| that's closest to |value|.
|
|
// This departs from the usual usage of semi-inclusive ranges, but is useful
|
|
// because (1) sentinels can use this, (2) a valid output always exists. It is
|
|
// assumed that |lo <= hi|.
|
|
template <class T>
|
|
T InclusiveClamp(T value, T lo, T hi) {
|
|
static_assert(std::is_unsigned<T>::value, "Value type must be unsigned.");
|
|
DCHECK_LE(lo, hi);
|
|
return value <= lo ? lo : (value >= hi ? hi : value);
|
|
}
|
|
|
|
// Returns the minimum multiple of |m| that's no less than |x|. Assumes |m > 0|
|
|
// and |x| is sufficiently small so that no overflow occurs.
|
|
template <class T>
|
|
constexpr T AlignCeil(T x, T m) {
|
|
static_assert(std::is_unsigned<T>::value, "Value type must be unsigned.");
|
|
return T((x + m - 1) / m) * m;
|
|
}
|
|
|
|
// Specialized alignment helpers that returns the increment to |pos| to get the
|
|
// next n-aligned value, where n is in {2, 4}. This is useful for aligning
|
|
// iterators relative to a base iterator using:
|
|
// it += IncrementForAlignCeil2(it - base);
|
|
template <class T>
|
|
inline int IncrementForAlignCeil2(T pos) {
|
|
return static_cast<int>(pos & 1); // Optimized from (-pos) & 1.
|
|
}
|
|
|
|
template <class T>
|
|
inline int IncrementForAlignCeil4(T pos) {
|
|
return static_cast<int>((-pos) & 3);
|
|
}
|
|
|
|
// Sorts values in |container| and removes duplicates.
|
|
template <class T>
|
|
void SortAndUniquify(std::deque<T>* container) {
|
|
std::sort(container->begin(), container->end());
|
|
container->erase(std::unique(container->begin(), container->end()),
|
|
container->end());
|
|
container->shrink_to_fit();
|
|
}
|
|
|
|
// Extracts a single bit at |pos| from integer |v|.
|
|
template <int pos, typename T>
|
|
constexpr T GetBit(T v) {
|
|
return (v >> pos) & 1;
|
|
}
|
|
|
|
// Extracts bits in inclusive range [|lo|, |hi|] from integer |v|, and returns
|
|
// the sign-extend result. For example, let the (MSB-first) bits in a 32-bit int
|
|
// |v| be:
|
|
// xxxxxxxx xxxxxSii iiiiiiii iyyyyyyy,
|
|
// hi^ lo^ => lo = 7, hi = 18
|
|
// To extract "Sii iiiiiiii i", calling
|
|
// GetSignedBits<7, 18>(v);
|
|
// produces the sign-extended result:
|
|
// SSSSSSSS SSSSSSSS SSSSSiii iiiiiiii.
|
|
template <int lo, int hi, typename T>
|
|
constexpr typename std::make_signed<T>::type GetSignedBits(T v) {
|
|
constexpr int kNumBits = sizeof(T) * 8;
|
|
using SignedType = typename std::make_signed<T>::type;
|
|
// Assumes 0 <= |lo| <= |hi| < |kNumBits|.
|
|
// How this works:
|
|
// (1) Shift-left by |kNumBits - 1 - hi| to clear "left" bits.
|
|
// (2) Shift-right by |kNumBits - 1 - hi + lo| to clear "right" bits. The
|
|
// input is casted to a signed type to perform sign-extension.
|
|
return static_cast<SignedType>(v << (kNumBits - 1 - hi)) >>
|
|
(kNumBits - 1 - hi + lo);
|
|
}
|
|
|
|
// Similar to GetSignedBits(), but returns the zero-extended result. For the
|
|
// above example, calling
|
|
// GetUnsignedBits<7, 18>(v);
|
|
// results in:
|
|
// 00000000 00000000 0000Siii iiiiiiii.
|
|
template <int lo, int hi, typename T>
|
|
constexpr typename std::make_unsigned<T>::type GetUnsignedBits(T v) {
|
|
constexpr int kNumBits = sizeof(T) * 8;
|
|
using UnsignedType = typename std::make_unsigned<T>::type;
|
|
return static_cast<UnsignedType>(v << (kNumBits - 1 - hi)) >>
|
|
(kNumBits - 1 - hi + lo);
|
|
}
|
|
|
|
// Copies bits at |pos| in |v| to all higher bits, and returns the result as the
|
|
// same int type as |v|.
|
|
template <typename T>
|
|
constexpr T SignExtend(int pos, T v) {
|
|
int kNumBits = sizeof(T) * 8;
|
|
int kShift = kNumBits - 1 - pos;
|
|
return static_cast<typename std::make_signed<T>::type>(v << kShift) >> kShift;
|
|
}
|
|
|
|
// Optimized version where |pos| becomes a template parameter.
|
|
template <int pos, typename T>
|
|
constexpr T SignExtend(T v) {
|
|
constexpr int kNumBits = sizeof(T) * 8;
|
|
constexpr int kShift = kNumBits - 1 - pos;
|
|
return static_cast<typename std::make_signed<T>::type>(v << kShift) >> kShift;
|
|
}
|
|
|
|
// Determines whether |v|, if interpreted as a signed integer, is representable
|
|
// using |digs| bits. |1 <= digs <= sizeof(T)| is assumed.
|
|
template <int digs, typename T>
|
|
constexpr bool SignedFit(T v) {
|
|
return v == SignExtend<digs - 1, T>(v);
|
|
}
|
|
|
|
} // namespace zucchini
|
|
|
|
#endif // COMPONENTS_ZUCCHINI_ALGORITHM_H_
|