unordered_base.h 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. // Profiling unordered containers implementation details -*- C++ -*-
  2. // Copyright (C) 2013-2018 Free Software Foundation, Inc.
  3. //
  4. // This file is part of the GNU ISO C++ Library. This library is free
  5. // software; you can redistribute it and/or modify it under the
  6. // terms of the GNU General Public License as published by the
  7. // Free Software Foundation; either version 3, or (at your option)
  8. // any later version.
  9. //
  10. // This library is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. // GNU General Public License for more details.
  14. // Under Section 7 of GPL version 3, you are granted additional
  15. // permissions described in the GCC Runtime Library Exception, version
  16. // 3.1, as published by the Free Software Foundation.
  17. // You should have received a copy of the GNU General Public License along
  18. // with this library; see the file COPYING3. If not see
  19. // <http://www.gnu.org/licenses/>.
  20. /** @file profile/unordered_base.h
  21. * This file is a GNU profile extension to the Standard C++ Library.
  22. */
  23. #ifndef _GLIBCXX_PROFILE_UNORDERED
  24. #define _GLIBCXX_PROFILE_UNORDERED 1
  25. namespace std _GLIBCXX_VISIBILITY(default)
  26. {
  27. namespace __profile
  28. {
  29. template<typename _UnorderedCont,
  30. typename _Value, bool _Cache_hash_code>
  31. struct _Bucket_index_helper;
  32. template<typename _UnorderedCont, typename _Value>
  33. struct _Bucket_index_helper<_UnorderedCont, _Value, true>
  34. {
  35. static std::size_t
  36. bucket(const _UnorderedCont& __uc,
  37. const __detail::_Hash_node<_Value, true>* __node)
  38. { return __node->_M_hash_code % __uc.bucket_count(); }
  39. };
  40. template<typename _UnorderedCont, typename _Value>
  41. struct _Bucket_index_helper<_UnorderedCont, _Value, false>
  42. {
  43. static std::size_t
  44. bucket(const _UnorderedCont& __uc,
  45. const __detail::_Hash_node<_Value, false>* __node)
  46. { return __uc.bucket(__node->_M_v()); }
  47. };
  48. template<typename _UnorderedCont, typename _Key, typename _Mapped>
  49. struct _Bucket_index_helper<_UnorderedCont,
  50. std::pair<const _Key, _Mapped>, false>
  51. {
  52. typedef std::pair<const _Key, _Mapped> _Value;
  53. static std::size_t
  54. bucket(const _UnorderedCont& __uc,
  55. const __detail::_Hash_node<_Value, false>* __node)
  56. { return __uc.bucket(__node->_M_v().first); }
  57. };
  58. template<typename _UnorderedCont, typename _Value, bool _Cache_hash_code>
  59. std::size_t
  60. __get_bucket_index(const _UnorderedCont& __uc,
  61. const __detail::_Hash_node<_Value, _Cache_hash_code>* __node)
  62. {
  63. using __bucket_index_helper
  64. = _Bucket_index_helper<_UnorderedCont, _Value, _Cache_hash_code>;
  65. return __bucket_index_helper::bucket(__uc, __node);
  66. }
  67. template<typename _UnorderedCont,
  68. typename _Value, bool _Cache_hash_code>
  69. struct _Equal_helper;
  70. template<typename _UnorderedCont, typename _Value>
  71. struct _Equal_helper<_UnorderedCont, _Value, true>
  72. {
  73. static std::size_t
  74. are_equal(const _UnorderedCont& __uc,
  75. const __detail::_Hash_node<_Value, true>* __lhs,
  76. const __detail::_Hash_node<_Value, true>* __rhs)
  77. {
  78. return __lhs->_M_hash_code == __rhs->_M_hash_code
  79. && __uc.key_eq()(__lhs->_M_v(), __rhs->_M_v());
  80. }
  81. };
  82. template<typename _UnorderedCont,
  83. typename _Value>
  84. struct _Equal_helper<_UnorderedCont, _Value, false>
  85. {
  86. static std::size_t
  87. are_equal(const _UnorderedCont& __uc,
  88. const __detail::_Hash_node<_Value, false>* __lhs,
  89. const __detail::_Hash_node<_Value, false>* __rhs)
  90. { return __uc.key_eq()(__lhs->_M_v(), __rhs->_M_v()); }
  91. };
  92. template<typename _UnorderedCont,
  93. typename _Key, typename _Mapped>
  94. struct _Equal_helper<_UnorderedCont, std::pair<const _Key, _Mapped>, true>
  95. {
  96. typedef std::pair<const _Key, _Mapped> _Value;
  97. static std::size_t
  98. are_equal(const _UnorderedCont& __uc,
  99. const __detail::_Hash_node<_Value, true>* __lhs,
  100. const __detail::_Hash_node<_Value, true>* __rhs)
  101. {
  102. return __lhs->_M_hash_code == __rhs->_M_hash_code
  103. && __uc.key_eq()(__lhs->_M_v().first, __rhs->_M_v().first);
  104. }
  105. };
  106. template<typename _UnorderedCont,
  107. typename _Key, typename _Mapped>
  108. struct _Equal_helper<_UnorderedCont, std::pair<const _Key, _Mapped>, false>
  109. {
  110. typedef std::pair<const _Key, _Mapped> _Value;
  111. static std::size_t
  112. are_equal(const _UnorderedCont& __uc,
  113. const __detail::_Hash_node<_Value, false>* __lhs,
  114. const __detail::_Hash_node<_Value, false>* __rhs)
  115. { return __uc.key_eq()(__lhs->_M_v().first, __rhs->_M_v().first); }
  116. };
  117. template<typename _UnorderedCont, typename _Value, bool _Cache_hash_code>
  118. bool
  119. __are_equal(const _UnorderedCont& __uc,
  120. const __detail::_Hash_node<_Value, _Cache_hash_code>* __lhs,
  121. const __detail::_Hash_node<_Value, _Cache_hash_code>* __rhs)
  122. {
  123. using __equal_helper
  124. = _Equal_helper<_UnorderedCont, _Value, _Cache_hash_code>;
  125. return __equal_helper::are_equal(__uc, __lhs, __rhs);
  126. }
  127. template<typename _UnorderedCont, bool _Unique_keys>
  128. class _Unordered_profile
  129. {
  130. _UnorderedCont&
  131. _M_conjure()
  132. { return *(static_cast<_UnorderedCont*>(this)); }
  133. using __unique_keys = std::integral_constant<bool, _Unique_keys>;
  134. protected:
  135. _Unordered_profile() noexcept
  136. { _M_profile_construct(); }
  137. _Unordered_profile(const _Unordered_profile&) noexcept
  138. : _Unordered_profile() { }
  139. _Unordered_profile(_Unordered_profile&& __other) noexcept
  140. : _Unordered_profile()
  141. { _M_swap(__other); }
  142. ~_Unordered_profile()
  143. { _M_profile_destruct(); }
  144. _Unordered_profile&
  145. operator=(const _Unordered_profile&) noexcept
  146. {
  147. // Assignment just reset profiling.
  148. _M_profile_destruct();
  149. _M_profile_construct();
  150. }
  151. _Unordered_profile&
  152. operator=(_Unordered_profile&& __other) noexcept
  153. {
  154. // Take profiling of the moved instance...
  155. _M_swap(__other);
  156. // ...and then reset other instance profiling.
  157. __other._M_profile_destruct();
  158. __other._M_profile_construct();
  159. }
  160. void
  161. _M_profile_construct() noexcept
  162. {
  163. auto& __uc = _M_conjure();
  164. _M_size_info = __profcxx_hashtable_size_construct(__uc.bucket_count());
  165. _M_hashfunc_info = __profcxx_hash_func_construct();
  166. }
  167. void
  168. _M_profile_destruct() noexcept
  169. {
  170. auto& __uc = _M_conjure();
  171. __profcxx_hashtable_size_destruct(_M_size_info,
  172. __uc.bucket_count(), __uc.size());
  173. _M_size_info = 0;
  174. if (!_M_hashfunc_info)
  175. return;
  176. _M_profile_destruct(__unique_keys());
  177. _M_hashfunc_info = 0;
  178. }
  179. void
  180. _M_swap(_Unordered_profile& __other) noexcept
  181. {
  182. std::swap(_M_size_info, __other._M_size_info);
  183. std::swap(_M_hashfunc_info, __other._M_hashfunc_info);
  184. }
  185. void
  186. _M_profile_resize(std::size_t __old_size)
  187. {
  188. auto __new_size = _M_conjure().bucket_count();
  189. if (__old_size != __new_size)
  190. __profcxx_hashtable_size_resize(_M_size_info, __old_size, __new_size);
  191. }
  192. __gnu_profile::__container_size_info* _M_size_info;
  193. __gnu_profile::__hashfunc_info* _M_hashfunc_info;
  194. private:
  195. void
  196. _M_profile_destruct(std::true_type);
  197. void
  198. _M_profile_destruct(std::false_type);
  199. };
  200. template<typename _UnorderedCont, bool _Unique_keys>
  201. void
  202. _Unordered_profile<_UnorderedCont, _Unique_keys>::
  203. _M_profile_destruct(std::true_type)
  204. {
  205. auto& __uc = _M_conjure();
  206. std::size_t __hops = 0, __lc = 0, __chain = 0;
  207. auto __it = __uc.begin();
  208. while (__it != __uc.end())
  209. {
  210. auto __bkt = __get_bucket_index(__uc, __it._M_cur);
  211. auto __lit = __uc.begin(__bkt);
  212. auto __lend = __uc.end(__bkt);
  213. for (++__it, ++__lit; __lit != __lend; ++__it, ++__lit)
  214. ++__chain;
  215. if (__chain)
  216. {
  217. ++__chain;
  218. __lc = __lc > __chain ? __lc : __chain;
  219. __hops += __chain * (__chain - 1) / 2;
  220. __chain = 0;
  221. }
  222. }
  223. __profcxx_hash_func_destruct(_M_hashfunc_info,
  224. __lc, __uc.size(), __hops);
  225. }
  226. template<typename _UnorderedCont, bool _Unique_keys>
  227. void
  228. _Unordered_profile<_UnorderedCont, _Unique_keys>::
  229. _M_profile_destruct(std::false_type)
  230. {
  231. auto& __uc = _M_conjure();
  232. std::size_t __hops = 0, __lc = 0, __chain = 0, __unique_size = 0;
  233. auto __it = __uc.begin();
  234. while (__it != __uc.end())
  235. {
  236. auto __bkt = __get_bucket_index(__uc, __it._M_cur);
  237. auto __lit = __uc.begin(__bkt);
  238. auto __lend = __uc.end(__bkt);
  239. auto __pit = __it;
  240. ++__unique_size;
  241. for (++__it, ++__lit; __lit != __lend; ++__it, ++__lit)
  242. {
  243. if (!__are_equal(__uc, __pit._M_cur, __it._M_cur))
  244. {
  245. ++__chain;
  246. ++__unique_size;
  247. __pit = __it;
  248. }
  249. }
  250. if (__chain)
  251. {
  252. ++__chain;
  253. __lc = __lc > __chain ? __lc : __chain;
  254. __hops += __chain * (__chain - 1) / 2;
  255. __chain = 0;
  256. }
  257. }
  258. __profcxx_hash_func_destruct(_M_hashfunc_info,
  259. __lc, __unique_size, __hops);
  260. }
  261. } // namespace __profile
  262. } // namespace std
  263. #endif