PodOperations.h 5.4 KB

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