PodOperations.h 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  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. /*
  6. * Operations for zeroing POD types, arrays, and so on.
  7. *
  8. * These operations are preferable to memset, memcmp, and the like because they
  9. * don't require remembering to multiply by sizeof(T), array lengths, and so on
  10. * everywhere.
  11. */
  12. #ifndef mozilla_PodOperations_h
  13. #define mozilla_PodOperations_h
  14. #include "mozilla/Array.h"
  15. #include "mozilla/ArrayUtils.h"
  16. #include "mozilla/Attributes.h"
  17. #include <stdint.h>
  18. #include <string.h>
  19. namespace mozilla {
  20. /** Set the contents of |aT| to 0. */
  21. template<typename T>
  22. static MOZ_ALWAYS_INLINE void
  23. PodZero(T* aT)
  24. {
  25. memset(aT, 0, sizeof(T));
  26. }
  27. /** Set the contents of |aNElem| elements starting at |aT| to 0. */
  28. template<typename T>
  29. static MOZ_ALWAYS_INLINE void
  30. PodZero(T* aT, size_t aNElem)
  31. {
  32. /*
  33. * This function is often called with 'aNElem' small; we use an inline loop
  34. * instead of calling 'memset' with a non-constant length. The compiler
  35. * should inline the memset call with constant size, though.
  36. */
  37. for (T* end = aT + aNElem; aT < end; aT++) {
  38. memset(aT, 0, sizeof(T));
  39. }
  40. }
  41. /*
  42. * Arrays implicitly convert to pointers to their first element, which is
  43. * dangerous when combined with the above PodZero definitions. Adding an
  44. * overload for arrays is ambiguous, so we need another identifier. The
  45. * ambiguous overload is left to catch mistaken uses of PodZero; if you get a
  46. * compile error involving PodZero and array types, use PodArrayZero instead.
  47. */
  48. template<typename T, size_t N>
  49. static void PodZero(T (&aT)[N]) = delete;
  50. template<typename T, size_t N>
  51. static void PodZero(T (&aT)[N], size_t aNElem) = delete;
  52. /** Set the contents of the array |aT| to zero. */
  53. template <class T, size_t N>
  54. static MOZ_ALWAYS_INLINE void
  55. PodArrayZero(T (&aT)[N])
  56. {
  57. memset(aT, 0, N * sizeof(T));
  58. }
  59. template <typename T, size_t N>
  60. static MOZ_ALWAYS_INLINE void
  61. PodArrayZero(Array<T, N>& aArr)
  62. {
  63. memset(&aArr[0], 0, N * sizeof(T));
  64. }
  65. /**
  66. * Assign |*aSrc| to |*aDst|. The locations must not be the same and must not
  67. * overlap.
  68. */
  69. template<typename T>
  70. static MOZ_ALWAYS_INLINE void
  71. PodAssign(T* aDst, const T* aSrc)
  72. {
  73. MOZ_ASSERT(aDst + 1 <= aSrc || aSrc + 1 <= aDst,
  74. "destination and source must not overlap");
  75. memcpy(reinterpret_cast<char*>(aDst), reinterpret_cast<const char*>(aSrc),
  76. sizeof(T));
  77. }
  78. /**
  79. * Copy |aNElem| T elements from |aSrc| to |aDst|. The two memory ranges must
  80. * not overlap!
  81. */
  82. template<typename T>
  83. static MOZ_ALWAYS_INLINE void
  84. PodCopy(T* aDst, const T* aSrc, size_t aNElem)
  85. {
  86. MOZ_ASSERT(aDst + aNElem <= aSrc || aSrc + aNElem <= aDst,
  87. "destination and source must not overlap");
  88. if (aNElem < 128) {
  89. /*
  90. * Avoid using operator= in this loop, as it may have been
  91. * intentionally deleted by the POD type.
  92. */
  93. for (const T* srcend = aSrc + aNElem; aSrc < srcend; aSrc++, aDst++) {
  94. PodAssign(aDst, aSrc);
  95. }
  96. } else {
  97. memcpy(aDst, aSrc, aNElem * sizeof(T));
  98. }
  99. }
  100. template<typename T>
  101. static MOZ_ALWAYS_INLINE void
  102. PodCopy(volatile T* aDst, const volatile T* aSrc, size_t aNElem)
  103. {
  104. MOZ_ASSERT(aDst + aNElem <= aSrc || aSrc + aNElem <= aDst,
  105. "destination and source must not overlap");
  106. /*
  107. * Volatile |aDst| requires extra work, because it's undefined behavior to
  108. * modify volatile objects using the mem* functions. Just write out the
  109. * loops manually, using operator= rather than memcpy for the same reason,
  110. * and let the compiler optimize to the extent it can.
  111. */
  112. for (const volatile T* srcend = aSrc + aNElem;
  113. aSrc < srcend;
  114. aSrc++, aDst++) {
  115. *aDst = *aSrc;
  116. }
  117. }
  118. /*
  119. * Copy the contents of the array |aSrc| into the array |aDst|, both of size N.
  120. * The arrays must not overlap!
  121. */
  122. template <class T, size_t N>
  123. static MOZ_ALWAYS_INLINE void
  124. PodArrayCopy(T (&aDst)[N], const T (&aSrc)[N])
  125. {
  126. PodCopy(aDst, aSrc, N);
  127. }
  128. /**
  129. * Copy the memory for |aNElem| T elements from |aSrc| to |aDst|. If the two
  130. * memory ranges overlap, then the effect is as if the |aNElem| elements are
  131. * first copied from |aSrc| to a temporary array, and then from the temporary
  132. * array to |aDst|.
  133. */
  134. template<typename T>
  135. static MOZ_ALWAYS_INLINE void
  136. PodMove(T* aDst, const T* aSrc, size_t aNElem)
  137. {
  138. MOZ_ASSERT(aNElem <= SIZE_MAX / sizeof(T),
  139. "trying to move an impossible number of elements");
  140. memmove(aDst, aSrc, aNElem * sizeof(T));
  141. }
  142. /**
  143. * Determine whether the |len| elements at |one| are memory-identical to the
  144. * |len| elements at |two|.
  145. */
  146. template<typename T>
  147. static MOZ_ALWAYS_INLINE bool
  148. PodEqual(const T* one, const T* two, size_t len)
  149. {
  150. if (len < 128) {
  151. const T* p1end = one + len;
  152. const T* p1 = one;
  153. const T* p2 = two;
  154. for (; p1 < p1end; p1++, p2++) {
  155. if (*p1 != *p2) {
  156. return false;
  157. }
  158. }
  159. return true;
  160. }
  161. return !memcmp(one, two, len * sizeof(T));
  162. }
  163. /*
  164. * Determine whether the |N| elements at |one| are memory-identical to the
  165. * |N| elements at |two|.
  166. */
  167. template <class T, size_t N>
  168. static MOZ_ALWAYS_INLINE bool
  169. PodEqual(const T (&one)[N], const T (&two)[N])
  170. {
  171. return PodEqual(one, two, N);
  172. }
  173. } // namespace mozilla
  174. #endif /* mozilla_PodOperations_h */