StdLibExtras.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. /*
  2. * Copyright (C) 2008 Apple Inc. All Rights Reserved.
  3. * Copyright (C) 2013 Patrick Gansterer <paroga@paroga.com>
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. *
  14. * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
  15. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  17. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
  18. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  19. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  20. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  21. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  22. * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  23. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  24. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. #ifndef WTF_StdLibExtras_h
  27. #define WTF_StdLibExtras_h
  28. #include <wtf/Assertions.h>
  29. #include <wtf/CheckedArithmetic.h>
  30. // Use these to declare and define a static local variable (static T;) so that
  31. // it is leaked so that its destructors are not called at exit. Using this
  32. // macro also allows workarounds a compiler bug present in Apple's version of GCC 4.0.1.
  33. #ifndef DEFINE_STATIC_LOCAL
  34. #if COMPILER(GCC) && defined(__APPLE_CC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 0 && __GNUC_PATCHLEVEL__ == 1
  35. #define DEFINE_STATIC_LOCAL(type, name, arguments) \
  36. static type* name##Ptr = new type arguments; \
  37. type& name = *name##Ptr
  38. #else
  39. #define DEFINE_STATIC_LOCAL(type, name, arguments) \
  40. static type& name = *new type arguments
  41. #endif
  42. #endif
  43. // Similar to DEFINE_STATIC_LOCAL except that the leaked object is allocated on the shared DATA heap
  44. #ifndef DEFINE_SHARED_STATIC_LOCAL
  45. #if ENABLE(DETACHED_JIT)
  46. #define DEFINE_SHARED_STATIC_LOCAL(type, name, arguments) \
  47. static type& name = *sharedNew<type> arguments
  48. #else
  49. #define DEFINE_SHARED_STATIC_LOCAL(type, name, arguments) \
  50. DEFINE_STATIC_LOCAL(type, name, arguments)
  51. #endif
  52. #endif
  53. // Use this macro to declare and define a debug-only global variable that may have a
  54. // non-trivial constructor and destructor. When building with clang, this will suppress
  55. // warnings about global constructors and exit-time destructors.
  56. #ifndef NDEBUG
  57. #if COMPILER(CLANG)
  58. #define DEFINE_DEBUG_ONLY_GLOBAL(type, name, arguments) \
  59. _Pragma("clang diagnostic push") \
  60. _Pragma("clang diagnostic ignored \"-Wglobal-constructors\"") \
  61. _Pragma("clang diagnostic ignored \"-Wexit-time-destructors\"") \
  62. static type name arguments; \
  63. _Pragma("clang diagnostic pop")
  64. #else
  65. #define DEFINE_DEBUG_ONLY_GLOBAL(type, name, arguments) \
  66. static type name arguments;
  67. #endif // COMPILER(CLANG)
  68. #else
  69. #define DEFINE_DEBUG_ONLY_GLOBAL(type, name, arguments)
  70. #endif // NDEBUG
  71. // OBJECT_OFFSETOF: Like the C++ offsetof macro, but you can use it with classes.
  72. // The magic number 0x4000 is insignificant. We use it to avoid using NULL, since
  73. // NULL can cause compiler problems, especially in cases of multiple inheritance.
  74. #define OBJECT_OFFSETOF(class, field) (reinterpret_cast<ptrdiff_t>(&(reinterpret_cast<class*>(0x4000)->field)) - 0x4000)
  75. // STRINGIZE: Can convert any value to quoted string, even expandable macros
  76. #define STRINGIZE(exp) #exp
  77. #define STRINGIZE_VALUE_OF(exp) STRINGIZE(exp)
  78. /*
  79. * The reinterpret_cast<Type1*>([pointer to Type2]) expressions - where
  80. * sizeof(Type1) > sizeof(Type2) - cause the following warning on ARM with GCC:
  81. * increases required alignment of target type.
  82. *
  83. * An implicit or an extra static_cast<void*> bypasses the warning.
  84. * For more info see the following bugzilla entries:
  85. * - https://bugs.webkit.org/show_bug.cgi?id=38045
  86. * - http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43976
  87. */
  88. #if (CPU(ARM) || CPU(MIPS)) && COMPILER(GCC)
  89. template<typename Type>
  90. bool isPointerTypeAlignmentOkay(Type* ptr)
  91. {
  92. return !(reinterpret_cast<intptr_t>(ptr) % __alignof__(Type));
  93. }
  94. template<typename TypePtr>
  95. TypePtr reinterpret_cast_ptr(void* ptr)
  96. {
  97. ASSERT(isPointerTypeAlignmentOkay(reinterpret_cast<TypePtr>(ptr)));
  98. return reinterpret_cast<TypePtr>(ptr);
  99. }
  100. template<typename TypePtr>
  101. TypePtr reinterpret_cast_ptr(const void* ptr)
  102. {
  103. ASSERT(isPointerTypeAlignmentOkay(reinterpret_cast<TypePtr>(ptr)));
  104. return reinterpret_cast<TypePtr>(ptr);
  105. }
  106. #else
  107. template<typename Type>
  108. bool isPointerTypeAlignmentOkay(Type*)
  109. {
  110. return true;
  111. }
  112. #define reinterpret_cast_ptr reinterpret_cast
  113. #endif
  114. namespace WTF {
  115. static const size_t KB = 1024;
  116. static const size_t MB = 1024 * 1024;
  117. inline bool isPointerAligned(void* p)
  118. {
  119. return !((intptr_t)(p) & (sizeof(char*) - 1));
  120. }
  121. inline bool is8ByteAligned(void* p)
  122. {
  123. return !((uintptr_t)(p) & (sizeof(double) - 1));
  124. }
  125. /*
  126. * C++'s idea of a reinterpret_cast lacks sufficient cojones.
  127. */
  128. template<typename TO, typename FROM>
  129. inline TO bitwise_cast(FROM from)
  130. {
  131. COMPILE_ASSERT(sizeof(TO) == sizeof(FROM), WTF_bitwise_cast_sizeof_casted_types_is_equal);
  132. union {
  133. FROM from;
  134. TO to;
  135. } u;
  136. u.from = from;
  137. return u.to;
  138. }
  139. template<typename To, typename From>
  140. inline To safeCast(From value)
  141. {
  142. ASSERT(isInBounds<To>(value));
  143. return static_cast<To>(value);
  144. }
  145. // Returns a count of the number of bits set in 'bits'.
  146. inline size_t bitCount(unsigned bits)
  147. {
  148. bits = bits - ((bits >> 1) & 0x55555555);
  149. bits = (bits & 0x33333333) + ((bits >> 2) & 0x33333333);
  150. return (((bits + (bits >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;
  151. }
  152. // Macro that returns a compile time constant with the length of an array, but gives an error if passed a non-array.
  153. template<typename T, size_t Size> char (&ArrayLengthHelperFunction(T (&)[Size]))[Size];
  154. // GCC needs some help to deduce a 0 length array.
  155. #if COMPILER(GCC)
  156. template<typename T> char (&ArrayLengthHelperFunction(T (&)[0]))[0];
  157. #endif
  158. #define WTF_ARRAY_LENGTH(array) sizeof(::WTF::ArrayLengthHelperFunction(array))
  159. // Efficient implementation that takes advantage of powers of two.
  160. inline size_t roundUpToMultipleOf(size_t divisor, size_t x)
  161. {
  162. ASSERT(divisor && !(divisor & (divisor - 1)));
  163. size_t remainderMask = divisor - 1;
  164. return (x + remainderMask) & ~remainderMask;
  165. }
  166. template<size_t divisor> inline size_t roundUpToMultipleOf(size_t x)
  167. {
  168. COMPILE_ASSERT(divisor && !(divisor & (divisor - 1)), divisor_is_a_power_of_two);
  169. return roundUpToMultipleOf(divisor, x);
  170. }
  171. enum BinarySearchMode {
  172. KeyMustBePresentInArray,
  173. KeyMightNotBePresentInArray,
  174. ReturnAdjacentElementIfKeyIsNotPresent
  175. };
  176. template<typename ArrayElementType, typename KeyType, typename ArrayType, typename ExtractKey, BinarySearchMode mode>
  177. inline ArrayElementType* binarySearchImpl(ArrayType& array, size_t size, KeyType key, const ExtractKey& extractKey = ExtractKey())
  178. {
  179. size_t offset = 0;
  180. while (size > 1) {
  181. size_t pos = (size - 1) >> 1;
  182. KeyType val = extractKey(&array[offset + pos]);
  183. if (val == key)
  184. return &array[offset + pos];
  185. // The item we are looking for is smaller than the item being check; reduce the value of 'size',
  186. // chopping off the right hand half of the array.
  187. if (key < val)
  188. size = pos;
  189. // Discard all values in the left hand half of the array, up to and including the item at pos.
  190. else {
  191. size -= (pos + 1);
  192. offset += (pos + 1);
  193. }
  194. ASSERT(mode != KeyMustBePresentInArray || size);
  195. }
  196. if (mode == KeyMightNotBePresentInArray && !size)
  197. return 0;
  198. ArrayElementType* result = &array[offset];
  199. if (mode == KeyMightNotBePresentInArray && key != extractKey(result))
  200. return 0;
  201. if (mode == KeyMustBePresentInArray) {
  202. ASSERT(size == 1);
  203. ASSERT(key == extractKey(result));
  204. }
  205. return result;
  206. }
  207. // If the element is not found, crash if asserts are enabled, and behave like approximateBinarySearch in release builds.
  208. template<typename ArrayElementType, typename KeyType, typename ArrayType, typename ExtractKey>
  209. inline ArrayElementType* binarySearch(ArrayType& array, size_t size, KeyType key, ExtractKey extractKey = ExtractKey())
  210. {
  211. return binarySearchImpl<ArrayElementType, KeyType, ArrayType, ExtractKey, KeyMustBePresentInArray>(array, size, key, extractKey);
  212. }
  213. // Return zero if the element is not found.
  214. template<typename ArrayElementType, typename KeyType, typename ArrayType, typename ExtractKey>
  215. inline ArrayElementType* tryBinarySearch(ArrayType& array, size_t size, KeyType key, ExtractKey extractKey = ExtractKey())
  216. {
  217. return binarySearchImpl<ArrayElementType, KeyType, ArrayType, ExtractKey, KeyMightNotBePresentInArray>(array, size, key, extractKey);
  218. }
  219. // Return the element that is either to the left, or the right, of where the element would have been found.
  220. template<typename ArrayElementType, typename KeyType, typename ArrayType, typename ExtractKey>
  221. inline ArrayElementType* approximateBinarySearch(ArrayType& array, size_t size, KeyType key, ExtractKey extractKey = ExtractKey())
  222. {
  223. return binarySearchImpl<ArrayElementType, KeyType, ArrayType, ExtractKey, ReturnAdjacentElementIfKeyIsNotPresent>(array, size, key, extractKey);
  224. }
  225. // Variants of the above that use const.
  226. template<typename ArrayElementType, typename KeyType, typename ArrayType, typename ExtractKey>
  227. inline ArrayElementType* binarySearch(const ArrayType& array, size_t size, KeyType key, ExtractKey extractKey = ExtractKey())
  228. {
  229. return binarySearchImpl<ArrayElementType, KeyType, ArrayType, ExtractKey, KeyMustBePresentInArray>(const_cast<ArrayType&>(array), size, key, extractKey);
  230. }
  231. template<typename ArrayElementType, typename KeyType, typename ArrayType, typename ExtractKey>
  232. inline ArrayElementType* tryBinarySearch(const ArrayType& array, size_t size, KeyType key, ExtractKey extractKey = ExtractKey())
  233. {
  234. return binarySearchImpl<ArrayElementType, KeyType, ArrayType, ExtractKey, KeyMightNotBePresentInArray>(const_cast<ArrayType&>(array), size, key, extractKey);
  235. }
  236. template<typename ArrayElementType, typename KeyType, typename ArrayType, typename ExtractKey>
  237. inline ArrayElementType* approximateBinarySearch(const ArrayType& array, size_t size, KeyType key, ExtractKey extractKey = ExtractKey())
  238. {
  239. return binarySearchImpl<ArrayElementType, KeyType, ArrayType, ExtractKey, ReturnAdjacentElementIfKeyIsNotPresent>(const_cast<ArrayType&>(array), size, key, extractKey);
  240. }
  241. } // namespace WTF
  242. #if OS(WINCE)
  243. // Windows CE CRT has does not implement bsearch().
  244. inline void* wtf_bsearch(const void* key, const void* base, size_t count, size_t size, int (*compare)(const void *, const void *))
  245. {
  246. const char* first = static_cast<const char*>(base);
  247. while (count) {
  248. size_t pos = (count - 1) >> 1;
  249. const char* item = first + pos * size;
  250. int compareResult = compare(item, key);
  251. if (!compareResult)
  252. return const_cast<char*>(item);
  253. if (compareResult < 0) {
  254. count -= (pos + 1);
  255. first += (pos + 1) * size;
  256. } else
  257. count = pos;
  258. }
  259. return 0;
  260. }
  261. #define bsearch(key, base, count, size, compare) wtf_bsearch(key, base, count, size, compare)
  262. #endif
  263. // This version of placement new omits a 0 check.
  264. enum NotNullTag { NotNull };
  265. inline void* operator new(size_t, NotNullTag, void* location)
  266. {
  267. ASSERT(location);
  268. return location;
  269. }
  270. using WTF::KB;
  271. using WTF::MB;
  272. using WTF::isPointerAligned;
  273. using WTF::is8ByteAligned;
  274. using WTF::binarySearch;
  275. using WTF::tryBinarySearch;
  276. using WTF::approximateBinarySearch;
  277. using WTF::bitwise_cast;
  278. using WTF::safeCast;
  279. #endif // WTF_StdLibExtras_h