1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mfbt/PodOperations.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,184 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* 1.11 + * Operations for zeroing POD types, arrays, and so on. 1.12 + * 1.13 + * These operations are preferable to memset, memcmp, and the like because they 1.14 + * don't require remembering to multiply by sizeof(T), array lengths, and so on 1.15 + * everywhere. 1.16 + */ 1.17 + 1.18 +#ifndef mozilla_PodOperations_h 1.19 +#define mozilla_PodOperations_h 1.20 + 1.21 +#include "mozilla/Array.h" 1.22 +#include "mozilla/ArrayUtils.h" 1.23 +#include "mozilla/Attributes.h" 1.24 + 1.25 +#include <stdint.h> 1.26 +#include <string.h> 1.27 + 1.28 +namespace mozilla { 1.29 + 1.30 +/** Set the contents of |t| to 0. */ 1.31 +template<typename T> 1.32 +static MOZ_ALWAYS_INLINE void 1.33 +PodZero(T* t) 1.34 +{ 1.35 + memset(t, 0, sizeof(T)); 1.36 +} 1.37 + 1.38 +/** Set the contents of |nelem| elements starting at |t| to 0. */ 1.39 +template<typename T> 1.40 +static MOZ_ALWAYS_INLINE void 1.41 +PodZero(T* t, size_t nelem) 1.42 +{ 1.43 + /* 1.44 + * This function is often called with 'nelem' small; we use an inline loop 1.45 + * instead of calling 'memset' with a non-constant length. The compiler 1.46 + * should inline the memset call with constant size, though. 1.47 + */ 1.48 + for (T* end = t + nelem; t < end; t++) 1.49 + memset(t, 0, sizeof(T)); 1.50 +} 1.51 + 1.52 +/* 1.53 + * Arrays implicitly convert to pointers to their first element, which is 1.54 + * dangerous when combined with the above PodZero definitions. Adding an 1.55 + * overload for arrays is ambiguous, so we need another identifier. The 1.56 + * ambiguous overload is left to catch mistaken uses of PodZero; if you get a 1.57 + * compile error involving PodZero and array types, use PodArrayZero instead. 1.58 + */ 1.59 +template<typename T, size_t N> 1.60 +static void PodZero(T (&t)[N]) MOZ_DELETE; 1.61 +template<typename T, size_t N> 1.62 +static void PodZero(T (&t)[N], size_t nelem) MOZ_DELETE; 1.63 + 1.64 +/** Set the contents of the array |t| to zero. */ 1.65 +template <class T, size_t N> 1.66 +static MOZ_ALWAYS_INLINE void 1.67 +PodArrayZero(T (&t)[N]) 1.68 +{ 1.69 + memset(t, 0, N * sizeof(T)); 1.70 +} 1.71 + 1.72 +template <typename T, size_t N> 1.73 +static MOZ_ALWAYS_INLINE void 1.74 +PodArrayZero(Array<T, N>& arr) 1.75 +{ 1.76 + memset(&arr[0], 0, N * sizeof(T)); 1.77 +} 1.78 + 1.79 +/** 1.80 + * Assign |*src| to |*dst|. The locations must not be the same and must not 1.81 + * overlap. 1.82 + */ 1.83 +template<typename T> 1.84 +static MOZ_ALWAYS_INLINE void 1.85 +PodAssign(T* dst, const T* src) 1.86 +{ 1.87 + MOZ_ASSERT(dst != src); 1.88 + MOZ_ASSERT_IF(src < dst, PointerRangeSize(src, static_cast<const T*>(dst)) >= 1); 1.89 + MOZ_ASSERT_IF(dst < src, PointerRangeSize(static_cast<const T*>(dst), src) >= 1); 1.90 + memcpy(reinterpret_cast<char*>(dst), reinterpret_cast<const char*>(src), sizeof(T)); 1.91 +} 1.92 + 1.93 +/** 1.94 + * Copy |nelem| T elements from |src| to |dst|. The two memory ranges must not 1.95 + * overlap! 1.96 + */ 1.97 +template<typename T> 1.98 +static MOZ_ALWAYS_INLINE void 1.99 +PodCopy(T* dst, const T* src, size_t nelem) 1.100 +{ 1.101 + MOZ_ASSERT(dst != src); 1.102 + MOZ_ASSERT_IF(src < dst, PointerRangeSize(src, static_cast<const T*>(dst)) >= nelem); 1.103 + MOZ_ASSERT_IF(dst < src, PointerRangeSize(static_cast<const T*>(dst), src) >= nelem); 1.104 + 1.105 + if (nelem < 128) { 1.106 + /* 1.107 + * Avoid using operator= in this loop, as it may have been 1.108 + * intentionally deleted by the POD type. 1.109 + */ 1.110 + for (const T* srcend = src + nelem; src < srcend; src++, dst++) 1.111 + PodAssign(dst, src); 1.112 + } else { 1.113 + memcpy(dst, src, nelem * sizeof(T)); 1.114 + } 1.115 +} 1.116 + 1.117 +template<typename T> 1.118 +static MOZ_ALWAYS_INLINE void 1.119 +PodCopy(volatile T* dst, const volatile T* src, size_t nelem) 1.120 +{ 1.121 + MOZ_ASSERT(dst != src); 1.122 + MOZ_ASSERT_IF(src < dst, 1.123 + PointerRangeSize(src, static_cast<const volatile T*>(dst)) >= nelem); 1.124 + MOZ_ASSERT_IF(dst < src, 1.125 + PointerRangeSize(static_cast<const volatile T*>(dst), src) >= nelem); 1.126 + 1.127 + /* 1.128 + * Volatile |dst| requires extra work, because it's undefined behavior to 1.129 + * modify volatile objects using the mem* functions. Just write out the 1.130 + * loops manually, using operator= rather than memcpy for the same reason, 1.131 + * and let the compiler optimize to the extent it can. 1.132 + */ 1.133 + for (const volatile T* srcend = src + nelem; src < srcend; src++, dst++) 1.134 + *dst = *src; 1.135 +} 1.136 + 1.137 +/* 1.138 + * Copy the contents of the array |src| into the array |dst|, both of size N. 1.139 + * The arrays must not overlap! 1.140 + */ 1.141 +template <class T, size_t N> 1.142 +static MOZ_ALWAYS_INLINE void 1.143 +PodArrayCopy(T (&dst)[N], const T (&src)[N]) 1.144 +{ 1.145 + PodCopy(dst, src, N); 1.146 +} 1.147 + 1.148 +/** 1.149 + * Copy the memory for |nelem| T elements from |src| to |dst|. If the two 1.150 + * memory ranges overlap, then the effect is as if the |nelem| elements are 1.151 + * first copied from |src| to a temporary array, and then from the temporary 1.152 + * array to |dst|. 1.153 + */ 1.154 +template<typename T> 1.155 +static MOZ_ALWAYS_INLINE void 1.156 +PodMove(T* dst, const T* src, size_t nelem) 1.157 +{ 1.158 + MOZ_ASSERT(nelem <= SIZE_MAX / sizeof(T), 1.159 + "trying to move an impossible number of elements"); 1.160 + memmove(dst, src, nelem * sizeof(T)); 1.161 +} 1.162 + 1.163 +/** 1.164 + * Determine whether the |len| elements at |one| are memory-identical to the 1.165 + * |len| elements at |two|. 1.166 + */ 1.167 +template<typename T> 1.168 +static MOZ_ALWAYS_INLINE bool 1.169 +PodEqual(const T* one, const T* two, size_t len) 1.170 +{ 1.171 + if (len < 128) { 1.172 + const T* p1end = one + len; 1.173 + const T* p1 = one; 1.174 + const T* p2 = two; 1.175 + for (; p1 < p1end; p1++, p2++) { 1.176 + if (*p1 != *p2) 1.177 + return false; 1.178 + } 1.179 + return true; 1.180 + } 1.181 + 1.182 + return !memcmp(one, two, len * sizeof(T)); 1.183 +} 1.184 + 1.185 +} // namespace mozilla 1.186 + 1.187 +#endif /* mozilla_PodOperations_h */