forked from mozilla/gecko-dev
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Bug 1194721: Add |Saturate| template for saturation arithmetics, r=nf…
…royd |Saturate<T>| implements saturation arithmetics for arbitrary basic types. Operations on its value won't over- or underflow the type's range.
- Loading branch information
Showing
5 changed files
with
505 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,287 @@ | ||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | ||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */ | ||
/* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
|
||
/* Provides saturation arithmetics for scalar types. */ | ||
|
||
#ifndef mozilla_Saturate_h | ||
#define mozilla_Saturate_h | ||
|
||
#include "mozilla/Attributes.h" | ||
#include "mozilla/Move.h" | ||
#include "mozilla/NumericLimits.h" | ||
#include "mozilla/TypeTraits.h" | ||
|
||
namespace mozilla { | ||
namespace detail { | ||
|
||
/** | ||
* |SaturateOp<T>| wraps scalar values for saturation arithmetics. Usage: | ||
* | ||
* uint32_t value = 1; | ||
* | ||
* ++SaturateOp<uint32_t>(value); // value is 2 | ||
* --SaturateOp<uint32_t>(value); // value is 1 | ||
* --SaturateOp<uint32_t>(value); // value is 0 | ||
* --SaturateOp<uint32_t>(value); // value is still 0 | ||
* | ||
* Please add new operators when required. | ||
* | ||
* |SaturateOp<T>| will saturate at the minimum and maximum values of | ||
* type T. If you need other bounds, implement a clamped-type class and | ||
* specialize the type traits accordingly. | ||
*/ | ||
template <typename T> | ||
class SaturateOp | ||
{ | ||
public: | ||
explicit SaturateOp(T& aValue) | ||
: mValue(aValue) | ||
{ | ||
// We should actually check for |std::is_scalar<T>::value| to be | ||
// true, but this type trait is not available everywhere. Relax | ||
// this assertion if you want to use floating point values as well. | ||
static_assert(IsIntegral<T>::value, | ||
"Integral type required in instantiation"); | ||
} | ||
|
||
// Add and subtract operators | ||
|
||
T operator+(const T& aRhs) const | ||
{ | ||
return T(mValue) += aRhs; | ||
} | ||
|
||
T operator-(const T& aRhs) const | ||
{ | ||
return T(mValue) -= aRhs; | ||
} | ||
|
||
// Compound operators | ||
|
||
const T& operator+=(const T& aRhs) const | ||
{ | ||
const T min = NumericLimits<T>::min(); | ||
const T max = NumericLimits<T>::max(); | ||
|
||
if (aRhs > static_cast<T>(0)) { | ||
mValue = (max - aRhs) < mValue ? max : mValue + aRhs; | ||
} else { | ||
mValue = (min - aRhs) > mValue ? min : mValue + aRhs; | ||
} | ||
return mValue; | ||
} | ||
|
||
const T& operator-=(const T& aRhs) const | ||
{ | ||
const T min = NumericLimits<T>::min(); | ||
const T max = NumericLimits<T>::max(); | ||
|
||
if (aRhs > static_cast<T>(0)) { | ||
mValue = (min + aRhs) > mValue ? min : mValue - aRhs; | ||
} else { | ||
mValue = (max + aRhs) < mValue ? max : mValue - aRhs; | ||
} | ||
return mValue; | ||
} | ||
|
||
// Increment and decrement operators | ||
|
||
const T& operator++() const // prefix | ||
{ | ||
return operator+=(static_cast<T>(1)); | ||
} | ||
|
||
T operator++(int) const // postfix | ||
{ | ||
const T value(mValue); | ||
operator++(); | ||
return value; | ||
} | ||
|
||
const T& operator--() const // prefix | ||
{ | ||
return operator-=(static_cast<T>(1)); | ||
} | ||
|
||
T operator--(int) const // postfix | ||
{ | ||
const T value(mValue); | ||
operator--(); | ||
return value; | ||
} | ||
|
||
private: | ||
SaturateOp(const SaturateOp<T>&) = delete; | ||
SaturateOp(SaturateOp<T>&&) = delete; | ||
SaturateOp& operator=(const SaturateOp<T>&) = delete; | ||
SaturateOp& operator=(SaturateOp<T>&&) = delete; | ||
|
||
T& mValue; | ||
}; | ||
|
||
/** | ||
* |Saturate<T>| is a value type for saturation arithmetics. It's | ||
* build on top of |SaturateOp<T>|. | ||
*/ | ||
template <typename T> | ||
class Saturate | ||
{ | ||
public: | ||
Saturate() = default; | ||
MOZ_IMPLICIT Saturate(const Saturate<T>&) = default; | ||
|
||
MOZ_IMPLICIT Saturate(Saturate<T>&& aValue) | ||
{ | ||
mValue = Move(aValue.mValue); | ||
} | ||
|
||
explicit Saturate(const T& aValue) | ||
: mValue(aValue) | ||
{ } | ||
|
||
const T& value() const | ||
{ | ||
return mValue; | ||
} | ||
|
||
// Compare operators | ||
|
||
bool operator==(const Saturate<T>& aRhs) const | ||
{ | ||
return mValue == aRhs.mValue; | ||
} | ||
|
||
bool operator!=(const Saturate<T>& aRhs) const | ||
{ | ||
return !operator==(aRhs); | ||
} | ||
|
||
bool operator==(const T& aRhs) const | ||
{ | ||
return mValue == aRhs; | ||
} | ||
|
||
bool operator!=(const T& aRhs) const | ||
{ | ||
return !operator==(aRhs); | ||
} | ||
|
||
// Assignment operators | ||
|
||
Saturate<T>& operator=(const Saturate<T>&) = default; | ||
|
||
Saturate<T>& operator=(Saturate<T>&& aRhs) | ||
{ | ||
mValue = Move(aRhs.mValue); | ||
return *this; | ||
} | ||
|
||
// Add and subtract operators | ||
|
||
Saturate<T> operator+(const Saturate<T>& aRhs) const | ||
{ | ||
Saturate<T> lhs(mValue); | ||
return lhs += aRhs.mValue; | ||
} | ||
|
||
Saturate<T> operator+(const T& aRhs) const | ||
{ | ||
Saturate<T> lhs(mValue); | ||
return lhs += aRhs; | ||
} | ||
|
||
Saturate<T> operator-(const Saturate<T>& aRhs) const | ||
{ | ||
Saturate<T> lhs(mValue); | ||
return lhs -= aRhs.mValue; | ||
} | ||
|
||
Saturate<T> operator-(const T& aRhs) const | ||
{ | ||
Saturate<T> lhs(mValue); | ||
return lhs -= aRhs; | ||
} | ||
|
||
// Compound operators | ||
|
||
Saturate<T>& operator+=(const Saturate<T>& aRhs) | ||
{ | ||
SaturateOp<T>(mValue) += aRhs.mValue; | ||
return *this; | ||
} | ||
|
||
Saturate<T>& operator+=(const T& aRhs) | ||
{ | ||
SaturateOp<T>(mValue) += aRhs; | ||
return *this; | ||
} | ||
|
||
Saturate<T>& operator-=(const Saturate<T>& aRhs) | ||
{ | ||
SaturateOp<T>(mValue) -= aRhs.mValue; | ||
return *this; | ||
} | ||
|
||
Saturate<T>& operator-=(const T& aRhs) | ||
{ | ||
SaturateOp<T>(mValue) -= aRhs; | ||
return *this; | ||
} | ||
|
||
// Increment and decrement operators | ||
|
||
Saturate<T>& operator++() // prefix | ||
{ | ||
++SaturateOp<T>(mValue); | ||
return *this; | ||
} | ||
|
||
Saturate<T> operator++(int) // postfix | ||
{ | ||
return Saturate<T>(SaturateOp<T>(mValue)++); | ||
} | ||
|
||
Saturate<T>& operator--() // prefix | ||
{ | ||
--SaturateOp<T>(mValue); | ||
return *this; | ||
} | ||
|
||
Saturate<T> operator--(int) // postfix | ||
{ | ||
return Saturate<T>(SaturateOp<T>(mValue)--); | ||
} | ||
|
||
private: | ||
T mValue; | ||
}; | ||
|
||
} // namespace detail | ||
|
||
typedef detail::Saturate<int8_t> SaturateInt8; | ||
typedef detail::Saturate<int16_t> SaturateInt16; | ||
typedef detail::Saturate<int32_t> SaturateInt32; | ||
typedef detail::Saturate<uint8_t> SaturateUint8; | ||
typedef detail::Saturate<uint16_t> SaturateUint16; | ||
typedef detail::Saturate<uint32_t> SaturateUint32; | ||
|
||
} // namespace mozilla | ||
|
||
template<typename LhsT, typename RhsT> | ||
bool | ||
operator==(LhsT aLhs, const mozilla::detail::Saturate<RhsT>& aRhs) | ||
{ | ||
return aRhs.operator==(static_cast<RhsT>(aLhs)); | ||
} | ||
|
||
template<typename LhsT, typename RhsT> | ||
bool | ||
operator!=(LhsT aLhs, const mozilla::detail::Saturate<RhsT>& aRhs) | ||
{ | ||
return !(aLhs == aRhs); | ||
} | ||
|
||
#endif // mozilla_Saturate_h |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.