Saturate.h 6.1 KB

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