1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /* Provides saturation arithmetics for scalar types. */
9 #ifndef mozilla_Saturate_h
10 #define mozilla_Saturate_h
14 #include <type_traits>
17 #include "mozilla/Attributes.h"
23 * |SaturateOp<T>| wraps scalar values for saturation arithmetics. Usage:
27 * ++SaturateOp<uint32_t>(value); // value is 2
28 * --SaturateOp<uint32_t>(value); // value is 1
29 * --SaturateOp<uint32_t>(value); // value is 0
30 * --SaturateOp<uint32_t>(value); // value is still 0
32 * Please add new operators when required.
34 * |SaturateOp<T>| will saturate at the minimum and maximum values of
35 * type T. If you need other bounds, implement a clamped-type class and
36 * specialize the type traits accordingly.
41 explicit SaturateOp(T
& aValue
) : mValue(aValue
) {
42 // We should actually check for |std::is_scalar<T>::value| to be
43 // true, but this type trait is not available everywhere. Relax
44 // this assertion if you want to use floating point values as well.
45 static_assert(std::is_integral_v
<T
>,
46 "Integral type required in instantiation");
49 // Add and subtract operators
51 T
operator+(const T
& aRhs
) const { return T(mValue
) += aRhs
; }
53 T
operator-(const T
& aRhs
) const { return T(mValue
) -= aRhs
; }
57 const T
& operator+=(const T
& aRhs
) const {
58 const T min
= std::numeric_limits
<T
>::min();
59 const T max
= std::numeric_limits
<T
>::max();
61 if (aRhs
> static_cast<T
>(0)) {
62 mValue
= (max
- aRhs
) < mValue
? max
: mValue
+ aRhs
;
64 mValue
= (min
- aRhs
) > mValue
? min
: mValue
+ aRhs
;
69 const T
& operator-=(const T
& aRhs
) const {
70 const T min
= std::numeric_limits
<T
>::min();
71 const T max
= std::numeric_limits
<T
>::max();
73 if (aRhs
> static_cast<T
>(0)) {
74 mValue
= (min
+ aRhs
) > mValue
? min
: mValue
- aRhs
;
76 mValue
= (max
+ aRhs
) < mValue
? max
: mValue
- aRhs
;
81 // Increment and decrement operators
83 const T
& operator++() const // prefix
85 return operator+=(static_cast<T
>(1));
88 T
operator++(int) const // postfix
90 const T
value(mValue
);
95 const T
& operator--() const // prefix
97 return operator-=(static_cast<T
>(1));
100 T
operator--(int) const // postfix
102 const T
value(mValue
);
108 SaturateOp(const SaturateOp
<T
>&) = delete;
109 SaturateOp(SaturateOp
<T
>&&) = delete;
110 SaturateOp
& operator=(const SaturateOp
<T
>&) = delete;
111 SaturateOp
& operator=(SaturateOp
<T
>&&) = delete;
117 * |Saturate<T>| is a value type for saturation arithmetics. It's
118 * built on top of |SaturateOp<T>|.
120 template <typename T
>
123 Saturate() = default;
124 MOZ_IMPLICIT
Saturate(const Saturate
<T
>&) = default;
126 MOZ_IMPLICIT
Saturate(Saturate
<T
>&& aValue
) {
127 mValue
= std::move(aValue
.mValue
);
130 explicit Saturate(const T
& aValue
) : mValue(aValue
) {}
132 const T
& value() const { return mValue
; }
136 bool operator==(const Saturate
<T
>& aRhs
) const {
137 return mValue
== aRhs
.mValue
;
140 bool operator!=(const Saturate
<T
>& aRhs
) const { return !operator==(aRhs
); }
142 bool operator==(const T
& aRhs
) const { return mValue
== aRhs
; }
144 bool operator!=(const T
& aRhs
) const { return !operator==(aRhs
); }
146 // Assignment operators
148 Saturate
<T
>& operator=(const Saturate
<T
>&) = default;
150 Saturate
<T
>& operator=(Saturate
<T
>&& aRhs
) {
151 mValue
= std::move(aRhs
.mValue
);
155 // Add and subtract operators
157 Saturate
<T
> operator+(const Saturate
<T
>& aRhs
) const {
158 Saturate
<T
> lhs(mValue
);
159 return lhs
+= aRhs
.mValue
;
162 Saturate
<T
> operator+(const T
& aRhs
) const {
163 Saturate
<T
> lhs(mValue
);
167 Saturate
<T
> operator-(const Saturate
<T
>& aRhs
) const {
168 Saturate
<T
> lhs(mValue
);
169 return lhs
-= aRhs
.mValue
;
172 Saturate
<T
> operator-(const T
& aRhs
) const {
173 Saturate
<T
> lhs(mValue
);
177 // Compound operators
179 Saturate
<T
>& operator+=(const Saturate
<T
>& aRhs
) {
180 SaturateOp
<T
>(mValue
) += aRhs
.mValue
;
184 Saturate
<T
>& operator+=(const T
& aRhs
) {
185 SaturateOp
<T
>(mValue
) += aRhs
;
189 Saturate
<T
>& operator-=(const Saturate
<T
>& aRhs
) {
190 SaturateOp
<T
>(mValue
) -= aRhs
.mValue
;
194 Saturate
<T
>& operator-=(const T
& aRhs
) {
195 SaturateOp
<T
>(mValue
) -= aRhs
;
199 // Increment and decrement operators
201 Saturate
<T
>& operator++() // prefix
203 ++SaturateOp
<T
>(mValue
);
207 Saturate
<T
> operator++(int) // postfix
209 return Saturate
<T
>(SaturateOp
<T
>(mValue
)++);
212 Saturate
<T
>& operator--() // prefix
214 --SaturateOp
<T
>(mValue
);
218 Saturate
<T
> operator--(int) // postfix
220 return Saturate
<T
>(SaturateOp
<T
>(mValue
)--);
227 } // namespace detail
229 typedef detail::Saturate
<int8_t> SaturateInt8
;
230 typedef detail::Saturate
<int16_t> SaturateInt16
;
231 typedef detail::Saturate
<int32_t> SaturateInt32
;
232 typedef detail::Saturate
<uint8_t> SaturateUint8
;
233 typedef detail::Saturate
<uint16_t> SaturateUint16
;
234 typedef detail::Saturate
<uint32_t> SaturateUint32
;
236 } // namespace mozilla
238 template <typename LhsT
, typename RhsT
>
239 bool operator==(LhsT aLhs
, const mozilla::detail::Saturate
<RhsT
>& aRhs
) {
240 return aRhs
.operator==(static_cast<RhsT
>(aLhs
));
243 template <typename LhsT
, typename RhsT
>
244 bool operator!=(LhsT aLhs
, const mozilla::detail::Saturate
<RhsT
>& aRhs
) {
245 return !(aLhs
== aRhs
);
248 #endif // mozilla_Saturate_h