You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

280 lines
9.1 KiB

  1. // ----------------------------------------------------------------------
  2. // Copyright (c) 2016, Steven Gregory Popovitch - greg7mdp@gmail.com
  3. // All rights reserved.
  4. //
  5. // Code derived derived from Boost libraries.
  6. // Boost software licence reproduced below.
  7. //
  8. // Redistribution and use in source and binary forms, with or without
  9. // modification, are permitted provided that the following conditions are
  10. // met:
  11. //
  12. // * Redistributions of source code must retain the above copyright
  13. // notice, this list of conditions and the following disclaimer.
  14. // * Redistributions in binary form must reproduce the above
  15. // copyright notice, this list of conditions and the following disclaimer
  16. // in the documentation and/or other materials provided with the
  17. // distribution.
  18. // * The name of Steven Gregory Popovitch may not be used to
  19. // endorse or promote products derived from this software without
  20. // specific prior written permission.
  21. //
  22. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  23. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  24. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  25. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  26. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  27. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  28. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  29. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  30. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  31. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  32. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  33. // ----------------------------------------------------------------------
  34. // ---------------------------------------------------------------------------
  35. // Boost Software License - Version 1.0 - August 17th, 2003
  36. //
  37. // Permission is hereby granted, free of charge, to any person or organization
  38. // obtaining a copy of the software and accompanying documentation covered by
  39. // this license (the "Software") to use, reproduce, display, distribute,
  40. // execute, and transmit the Software, and to prepare derivative works of the
  41. // Software, and to permit third-parties to whom the Software is furnished to
  42. // do so, all subject to the following:
  43. //
  44. // The copyright notices in the Software and this entire statement, including
  45. // the above license grant, this restriction and the following disclaimer,
  46. // must be included in all copies of the Software, in whole or in part, and
  47. // all derivative works of the Software, unless such copies or derivative
  48. // works are solely in the form of machine-executable object code generated by
  49. // a source language processor.
  50. //
  51. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  52. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  53. // FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
  54. // SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
  55. // FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
  56. // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  57. // DEALINGS IN THE SOFTWARE.
  58. // ---------------------------------------------------------------------------
  59. // ----------------------------------------------------------------------
  60. // H A S H F U N C T I O N S
  61. // ----------------------------
  62. //
  63. // Implements spp::spp_hash() and spp::hash_combine()
  64. //
  65. // The exact same code is duplicated in sparsepp.h.
  66. //
  67. // WARNING: Any change here has to be duplicated in sparsepp.h.
  68. // ----------------------------------------------------------------------
  69. #if !defined(spp_utils_h_guard_)
  70. #define spp_utils_h_guard_
  71. #if defined(_MSC_VER)
  72. #if (_MSC_VER >= 1600 ) // vs2010 (1900 is vs2015)
  73. #include <functional>
  74. #define SPP_HASH_CLASS std::hash
  75. #else
  76. #include <hash_map>
  77. #define SPP_HASH_CLASS stdext::hash_compare
  78. #endif
  79. #if (_MSC_FULL_VER < 190021730)
  80. #define SPP_NO_CXX11_NOEXCEPT
  81. #endif
  82. #elif defined(__GNUC__)
  83. #if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L)
  84. #include <functional>
  85. #define SPP_HASH_CLASS std::hash
  86. #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100) < 40600
  87. #define SPP_NO_CXX11_NOEXCEPT
  88. #endif
  89. #else
  90. #include <tr1/unordered_map>
  91. #define SPP_HASH_CLASS std::tr1::hash
  92. #define SPP_NO_CXX11_NOEXCEPT
  93. #endif
  94. #elif defined __clang__
  95. #include <functional>
  96. #define SPP_HASH_CLASS std::hash
  97. #if !__has_feature(cxx_noexcept)
  98. #define SPP_NO_CXX11_NOEXCEPT
  99. #endif
  100. #else
  101. #include <functional>
  102. #define SPP_HASH_CLASS std::hash
  103. #endif
  104. #ifdef SPP_NO_CXX11_NOEXCEPT
  105. #define SPP_NOEXCEPT
  106. #else
  107. #define SPP_NOEXCEPT noexcept
  108. #endif
  109. #define SPP_INLINE
  110. #ifndef SPP_NAMESPACE
  111. #define SPP_NAMESPACE spp
  112. #endif
  113. namespace SPP_NAMESPACE
  114. {
  115. template <class T>
  116. struct spp_hash
  117. {
  118. SPP_INLINE size_t operator()(const T &__v) const SPP_NOEXCEPT
  119. {
  120. SPP_HASH_CLASS<T> hasher;
  121. return hasher(__v);
  122. }
  123. };
  124. template <class T>
  125. struct spp_hash<T *>
  126. {
  127. static size_t spp_log2 (size_t val) SPP_NOEXCEPT
  128. {
  129. size_t res = 0;
  130. while (val > 1)
  131. {
  132. val >>= 1;
  133. res++;
  134. }
  135. return res;
  136. }
  137. SPP_INLINE size_t operator()(const T *__v) const SPP_NOEXCEPT
  138. {
  139. static const size_t shift = spp_log2(1 + sizeof(T));
  140. return static_cast<size_t>((*(reinterpret_cast<const uintptr_t *>(&__v))) >> shift);
  141. }
  142. };
  143. template <>
  144. struct spp_hash<bool> : public std::unary_function<bool, size_t>
  145. {
  146. SPP_INLINE size_t operator()(bool __v) const SPP_NOEXCEPT {return static_cast<size_t>(__v);}
  147. };
  148. template <>
  149. struct spp_hash<char> : public std::unary_function<char, size_t>
  150. {
  151. SPP_INLINE size_t operator()(char __v) const SPP_NOEXCEPT {return static_cast<size_t>(__v);}
  152. };
  153. template <>
  154. struct spp_hash<signed char> : public std::unary_function<signed char, size_t>
  155. {
  156. SPP_INLINE size_t operator()(signed char __v) const SPP_NOEXCEPT {return static_cast<size_t>(__v);}
  157. };
  158. template <>
  159. struct spp_hash<unsigned char> : public std::unary_function<unsigned char, size_t>
  160. {
  161. SPP_INLINE size_t operator()(unsigned char __v) const SPP_NOEXCEPT {return static_cast<size_t>(__v);}
  162. };
  163. template <>
  164. struct spp_hash<wchar_t> : public std::unary_function<wchar_t, size_t>
  165. {
  166. SPP_INLINE size_t operator()(wchar_t __v) const SPP_NOEXCEPT {return static_cast<size_t>(__v);}
  167. };
  168. template <>
  169. struct spp_hash<short> : public std::unary_function<short, size_t>
  170. {
  171. SPP_INLINE size_t operator()(short __v) const SPP_NOEXCEPT {return static_cast<size_t>(__v);}
  172. };
  173. template <>
  174. struct spp_hash<unsigned short> : public std::unary_function<unsigned short, size_t>
  175. {
  176. SPP_INLINE size_t operator()(unsigned short __v) const SPP_NOEXCEPT {return static_cast<size_t>(__v);}
  177. };
  178. template <>
  179. struct spp_hash<int> : public std::unary_function<int, size_t>
  180. {
  181. SPP_INLINE size_t operator()(int __v) const SPP_NOEXCEPT {return static_cast<size_t>(__v);}
  182. };
  183. template <>
  184. struct spp_hash<unsigned int> : public std::unary_function<unsigned int, size_t>
  185. {
  186. SPP_INLINE size_t operator()(unsigned int __v) const SPP_NOEXCEPT {return static_cast<size_t>(__v);}
  187. };
  188. template <>
  189. struct spp_hash<long> : public std::unary_function<long, size_t>
  190. {
  191. SPP_INLINE size_t operator()(long __v) const SPP_NOEXCEPT {return static_cast<size_t>(__v);}
  192. };
  193. template <>
  194. struct spp_hash<unsigned long> : public std::unary_function<unsigned long, size_t>
  195. {
  196. SPP_INLINE size_t operator()(unsigned long __v) const SPP_NOEXCEPT {return static_cast<size_t>(__v);}
  197. };
  198. template <>
  199. struct spp_hash<float> : public std::unary_function<float, size_t>
  200. {
  201. SPP_INLINE size_t operator()(float __v) const SPP_NOEXCEPT
  202. {
  203. // -0.0 and 0.0 should return same hash
  204. uint32_t *as_int = reinterpret_cast<uint32_t *>(&__v);
  205. return (__v == 0) ? static_cast<size_t>(0) : static_cast<size_t>(*as_int);
  206. }
  207. };
  208. #if 0
  209. // todo: we should not ignore half of the double => see libcxx/include/functional
  210. template <>
  211. struct spp_hash<double> : public std::unary_function<double, size_t>
  212. {
  213. SPP_INLINE size_t operator()(double __v) const SPP_NOEXCEPT
  214. {
  215. // -0.0 and 0.0 should return same hash
  216. return (__v == 0) ? (size_t)0 : (size_t)*((uint64_t *)&__v);
  217. }
  218. };
  219. #endif
  220. template <class T, int sz> struct Combiner
  221. {
  222. inline void operator()(T& seed, T value);
  223. };
  224. template <class T> struct Combiner<T, 4>
  225. {
  226. inline void operator()(T& seed, T value)
  227. {
  228. seed ^= value + 0x9e3779b9 + (seed << 6) + (seed >> 2);
  229. }
  230. };
  231. template <class T> struct Combiner<T, 8>
  232. {
  233. inline void operator()(T& seed, T value)
  234. {
  235. seed ^= value + T(0xc6a4a7935bd1e995) + (seed << 6) + (seed >> 2);
  236. }
  237. };
  238. template <class T>
  239. inline void hash_combine(std::size_t& seed, T const& v)
  240. {
  241. spp::spp_hash<T> hasher;
  242. Combiner<std::size_t, sizeof(std::size_t)> combiner;
  243. combiner(seed, hasher(v));
  244. }
  245. };
  246. #endif // spp_utils_h_guard_