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