Saturate.h 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. /* Provides saturation arithmetics for scalar types. */
  6. #ifndef mozilla_Saturate_h
  7. #define mozilla_Saturate_h
  8. #include "mozilla/Attributes.h"
  9. #include "mozilla/Move.h"
  10. #include "mozilla/TypeTraits.h"
  11. #include <limits>
  12. namespace mozilla {
  13. namespace detail {
  14. /**
  15. * |SaturateOp<T>| wraps scalar values for saturation arithmetics. Usage:
  16. *
  17. * uint32_t value = 1;
  18. *
  19. * ++SaturateOp<uint32_t>(value); // value is 2
  20. * --SaturateOp<uint32_t>(value); // value is 1
  21. * --SaturateOp<uint32_t>(value); // value is 0
  22. * --SaturateOp<uint32_t>(value); // value is still 0
  23. *
  24. * Please add new operators when required.
  25. *
  26. * |SaturateOp<T>| will saturate at the minimum and maximum values of
  27. * type T. If you need other bounds, implement a clamped-type class and
  28. * specialize the type traits accordingly.
  29. */
  30. template <typename T>
  31. class SaturateOp
  32. {
  33. public:
  34. explicit SaturateOp(T& aValue)
  35. : mValue(aValue)
  36. {
  37. // We should actually check for |std::is_scalar<T>::value| to be
  38. // true, but this type trait is not available everywhere. Relax
  39. // this assertion if you want to use floating point values as well.
  40. static_assert(IsIntegral<T>::value,
  41. "Integral type required in instantiation");
  42. }
  43. // Add and subtract operators
  44. T operator+(const T& aRhs) const
  45. {
  46. return T(mValue) += aRhs;
  47. }
  48. T operator-(const T& aRhs) const
  49. {
  50. return T(mValue) -= aRhs;
  51. }
  52. // Compound operators
  53. const T& operator+=(const T& aRhs) const
  54. {
  55. const T min = std::numeric_limits<T>::min();
  56. const T max = std::numeric_limits<T>::max();
  57. if (aRhs > static_cast<T>(0)) {
  58. mValue = (max - aRhs) < mValue ? max : mValue + aRhs;
  59. } else {
  60. mValue = (min - aRhs) > mValue ? min : mValue + aRhs;
  61. }
  62. return mValue;
  63. }
  64. const T& operator-=(const T& aRhs) const
  65. {
  66. const T min = std::numeric_limits<T>::min();
  67. const T max = std::numeric_limits<T>::max();
  68. if (aRhs > static_cast<T>(0)) {
  69. mValue = (min + aRhs) > mValue ? min : mValue - aRhs;
  70. } else {
  71. mValue = (max + aRhs) < mValue ? max : mValue - aRhs;
  72. }
  73. return mValue;
  74. }
  75. // Increment and decrement operators
  76. const T& operator++() const // prefix
  77. {
  78. return operator+=(static_cast<T>(1));
  79. }
  80. T operator++(int) const // postfix
  81. {
  82. const T value(mValue);
  83. operator++();
  84. return value;
  85. }
  86. const T& operator--() const // prefix
  87. {
  88. return operator-=(static_cast<T>(1));
  89. }
  90. T operator--(int) const // postfix
  91. {
  92. const T value(mValue);
  93. operator--();
  94. return value;
  95. }
  96. private:
  97. SaturateOp(const SaturateOp<T>&) = delete;
  98. SaturateOp(SaturateOp<T>&&) = delete;
  99. SaturateOp& operator=(const SaturateOp<T>&) = delete;
  100. SaturateOp& operator=(SaturateOp<T>&&) = delete;
  101. T& mValue;
  102. };
  103. /**
  104. * |Saturate<T>| is a value type for saturation arithmetics. It's
  105. * build on top of |SaturateOp<T>|.
  106. */
  107. template <typename T>
  108. class Saturate
  109. {
  110. public:
  111. Saturate() = default;
  112. MOZ_IMPLICIT Saturate(const Saturate<T>&) = default;
  113. MOZ_IMPLICIT Saturate(Saturate<T>&& aValue)
  114. {
  115. mValue = Move(aValue.mValue);
  116. }
  117. explicit Saturate(const T& aValue)
  118. : mValue(aValue)
  119. { }
  120. const T& value() const
  121. {
  122. return mValue;
  123. }
  124. // Compare operators
  125. bool operator==(const Saturate<T>& aRhs) const
  126. {
  127. return mValue == aRhs.mValue;
  128. }
  129. bool operator!=(const Saturate<T>& aRhs) const
  130. {
  131. return !operator==(aRhs);
  132. }
  133. bool operator==(const T& aRhs) const
  134. {
  135. return mValue == aRhs;
  136. }
  137. bool operator!=(const T& aRhs) const
  138. {
  139. return !operator==(aRhs);
  140. }
  141. // Assignment operators
  142. Saturate<T>& operator=(const Saturate<T>&) = default;
  143. Saturate<T>& operator=(Saturate<T>&& aRhs)
  144. {
  145. mValue = Move(aRhs.mValue);
  146. return *this;
  147. }
  148. // Add and subtract operators
  149. Saturate<T> operator+(const Saturate<T>& aRhs) const
  150. {
  151. Saturate<T> lhs(mValue);
  152. return lhs += aRhs.mValue;
  153. }
  154. Saturate<T> operator+(const T& aRhs) const
  155. {
  156. Saturate<T> lhs(mValue);
  157. return lhs += aRhs;
  158. }
  159. Saturate<T> operator-(const Saturate<T>& aRhs) const
  160. {
  161. Saturate<T> lhs(mValue);
  162. return lhs -= aRhs.mValue;
  163. }
  164. Saturate<T> operator-(const T& aRhs) const
  165. {
  166. Saturate<T> lhs(mValue);
  167. return lhs -= aRhs;
  168. }
  169. // Compound operators
  170. Saturate<T>& operator+=(const Saturate<T>& aRhs)
  171. {
  172. SaturateOp<T>(mValue) += aRhs.mValue;
  173. return *this;
  174. }
  175. Saturate<T>& operator+=(const T& aRhs)
  176. {
  177. SaturateOp<T>(mValue) += aRhs;
  178. return *this;
  179. }
  180. Saturate<T>& operator-=(const Saturate<T>& aRhs)
  181. {
  182. SaturateOp<T>(mValue) -= aRhs.mValue;
  183. return *this;
  184. }
  185. Saturate<T>& operator-=(const T& aRhs)
  186. {
  187. SaturateOp<T>(mValue) -= aRhs;
  188. return *this;
  189. }
  190. // Increment and decrement operators
  191. Saturate<T>& operator++() // prefix
  192. {
  193. ++SaturateOp<T>(mValue);
  194. return *this;
  195. }
  196. Saturate<T> operator++(int) // postfix
  197. {
  198. return Saturate<T>(SaturateOp<T>(mValue)++);
  199. }
  200. Saturate<T>& operator--() // prefix
  201. {
  202. --SaturateOp<T>(mValue);
  203. return *this;
  204. }
  205. Saturate<T> operator--(int) // postfix
  206. {
  207. return Saturate<T>(SaturateOp<T>(mValue)--);
  208. }
  209. private:
  210. T mValue;
  211. };
  212. } // namespace detail
  213. typedef detail::Saturate<int8_t> SaturateInt8;
  214. typedef detail::Saturate<int16_t> SaturateInt16;
  215. typedef detail::Saturate<int32_t> SaturateInt32;
  216. typedef detail::Saturate<uint8_t> SaturateUint8;
  217. typedef detail::Saturate<uint16_t> SaturateUint16;
  218. typedef detail::Saturate<uint32_t> SaturateUint32;
  219. } // namespace mozilla
  220. template<typename LhsT, typename RhsT>
  221. bool
  222. operator==(LhsT aLhs, const mozilla::detail::Saturate<RhsT>& aRhs)
  223. {
  224. return aRhs.operator==(static_cast<RhsT>(aLhs));
  225. }
  226. template<typename LhsT, typename RhsT>
  227. bool
  228. operator!=(LhsT aLhs, const mozilla::detail::Saturate<RhsT>& aRhs)
  229. {
  230. return !(aLhs == aRhs);
  231. }
  232. #endif // mozilla_Saturate_h