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
15 #include "mozilla/Attributes.h"
16 #include "mozilla/TypeTraits.h"
22 * |SaturateOp<T>| wraps scalar values for saturation arithmetics. Usage:
26 * ++SaturateOp<uint32_t>(value); // value is 2
27 * --SaturateOp<uint32_t>(value); // value is 1
28 * --SaturateOp<uint32_t>(value); // value is 0
29 * --SaturateOp<uint32_t>(value); // value is still 0
31 * Please add new operators when required.
33 * |SaturateOp<T>| will saturate at the minimum and maximum values of
34 * type T. If you need other bounds, implement a clamped-type class and
35 * specialize the type traits accordingly.
40 explicit SaturateOp(T
& aValue
) : mValue(aValue
) {
41 // We should actually check for |std::is_scalar<T>::value| to be
42 // true, but this type trait is not available everywhere. Relax
43 // this assertion if you want to use floating point values as well.
44 static_assert(IsIntegral
<T
>::value
,
45 "Integral type required in instantiation");
48 // Add and subtract operators
50 T
operator+(const T
& aRhs
) const { return T(mValue
) += aRhs
; }
52 T
operator-(const T
& aRhs
) const { return T(mValue
) -= aRhs
; }
56 const T
& operator+=(const T
& aRhs
) const {
57 const T min
= std::numeric_limits
<T
>::min();
58 const T max
= std::numeric_limits
<T
>::max();
60 if (aRhs
> static_cast<T
>(0)) {
61 mValue
= (max
- aRhs
) < mValue
? max
: mValue
+ aRhs
;
63 mValue
= (min
- aRhs
) > mValue
? min
: mValue
+ aRhs
;
68 const T
& operator-=(const T
& aRhs
) const {
69 const T min
= std::numeric_limits
<T
>::min();
70 const T max
= std::numeric_limits
<T
>::max();
72 if (aRhs
> static_cast<T
>(0)) {
73 mValue
= (min
+ aRhs
) > mValue
? min
: mValue
- aRhs
;
75 mValue
= (max
+ aRhs
) < mValue
? max
: mValue
- aRhs
;
80 // Increment and decrement operators
82 const T
& operator++() const // prefix
84 return operator+=(static_cast<T
>(1));
87 T
operator++(int) const // postfix
89 const T
value(mValue
);
94 const T
& operator--() const // prefix
96 return operator-=(static_cast<T
>(1));
99 T
operator--(int) const // postfix
101 const T
value(mValue
);
107 SaturateOp(const SaturateOp
<T
>&) = delete;
108 SaturateOp(SaturateOp
<T
>&&) = delete;
109 SaturateOp
& operator=(const SaturateOp
<T
>&) = delete;
110 SaturateOp
& operator=(SaturateOp
<T
>&&) = delete;
116 * |Saturate<T>| is a value type for saturation arithmetics. It's
117 * built on top of |SaturateOp<T>|.
119 template <typename T
>
122 Saturate() = default;
123 MOZ_IMPLICIT
Saturate(const Saturate
<T
>&) = default;
125 MOZ_IMPLICIT
Saturate(Saturate
<T
>&& aValue
) {
126 mValue
= std::move(aValue
.mValue
);
129 explicit Saturate(const T
& aValue
) : mValue(aValue
) {}
131 const T
& value() const { return mValue
; }
135 bool operator==(const Saturate
<T
>& aRhs
) const {
136 return mValue
== aRhs
.mValue
;
139 bool operator!=(const Saturate
<T
>& aRhs
) const { return !operator==(aRhs
); }
141 bool operator==(const T
& aRhs
) const { return mValue
== aRhs
; }
143 bool operator!=(const T
& aRhs
) const { return !operator==(aRhs
); }
145 // Assignment operators
147 Saturate
<T
>& operator=(const Saturate
<T
>&) = default;
149 Saturate
<T
>& operator=(Saturate
<T
>&& aRhs
) {
150 mValue
= std::move(aRhs
.mValue
);
154 // Add and subtract operators
156 Saturate
<T
> operator+(const Saturate
<T
>& aRhs
) const {
157 Saturate
<T
> lhs(mValue
);
158 return lhs
+= aRhs
.mValue
;
161 Saturate
<T
> operator+(const T
& aRhs
) const {
162 Saturate
<T
> lhs(mValue
);
166 Saturate
<T
> operator-(const Saturate
<T
>& aRhs
) const {
167 Saturate
<T
> lhs(mValue
);
168 return lhs
-= aRhs
.mValue
;
171 Saturate
<T
> operator-(const T
& aRhs
) const {
172 Saturate
<T
> lhs(mValue
);
176 // Compound operators
178 Saturate
<T
>& operator+=(const Saturate
<T
>& aRhs
) {
179 SaturateOp
<T
>(mValue
) += aRhs
.mValue
;
183 Saturate
<T
>& operator+=(const T
& aRhs
) {
184 SaturateOp
<T
>(mValue
) += aRhs
;
188 Saturate
<T
>& operator-=(const Saturate
<T
>& aRhs
) {
189 SaturateOp
<T
>(mValue
) -= aRhs
.mValue
;
193 Saturate
<T
>& operator-=(const T
& aRhs
) {
194 SaturateOp
<T
>(mValue
) -= aRhs
;
198 // Increment and decrement operators
200 Saturate
<T
>& operator++() // prefix
202 ++SaturateOp
<T
>(mValue
);
206 Saturate
<T
> operator++(int) // postfix
208 return Saturate
<T
>(SaturateOp
<T
>(mValue
)++);
211 Saturate
<T
>& operator--() // prefix
213 --SaturateOp
<T
>(mValue
);
217 Saturate
<T
> operator--(int) // postfix
219 return Saturate
<T
>(SaturateOp
<T
>(mValue
)--);
226 } // namespace detail
228 typedef detail::Saturate
<int8_t> SaturateInt8
;
229 typedef detail::Saturate
<int16_t> SaturateInt16
;
230 typedef detail::Saturate
<int32_t> SaturateInt32
;
231 typedef detail::Saturate
<uint8_t> SaturateUint8
;
232 typedef detail::Saturate
<uint16_t> SaturateUint16
;
233 typedef detail::Saturate
<uint32_t> SaturateUint32
;
235 } // namespace mozilla
237 template <typename LhsT
, typename RhsT
>
238 bool operator==(LhsT aLhs
, const mozilla::detail::Saturate
<RhsT
>& aRhs
) {
239 return aRhs
.operator==(static_cast<RhsT
>(aLhs
));
242 template <typename LhsT
, typename RhsT
>
243 bool operator!=(LhsT aLhs
, const mozilla::detail::Saturate
<RhsT
>& aRhs
) {
244 return !(aLhs
== aRhs
);
247 #endif // mozilla_Saturate_h