Home | History | Annotate | Download | only in profile
      1 // Profiling unordered_set/unordered_multiset implementation -*- C++ -*-
      2 
      3 // Copyright (C) 2009-2013 Free Software Foundation, Inc.
      4 //
      5 // This file is part of the GNU ISO C++ Library.  This library is free
      6 // software; you can redistribute it and/or modify it under the
      7 // terms of the GNU General Public License as published by the
      8 // Free Software Foundation; either version 3, or (at your option)
      9 // any later version.
     10 //
     11 // This library is distributed in the hope that it will be useful,
     12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14 // GNU General Public License for more details.
     15 
     16 // Under Section 7 of GPL version 3, you are granted additional
     17 // permissions described in the GCC Runtime Library Exception, version
     18 // 3.1, as published by the Free Software Foundation.
     19 
     20 // You should have received a copy of the GNU General Public License along
     21 // with this library; see the file COPYING3.  If not see
     22 // <http://www.gnu.org/licenses/>.
     23 
     24 /** @file profile/unordered_set
     25  *  This file is a GNU profile extension to the Standard C++ Library.
     26  */
     27 
     28 #ifndef _GLIBCXX_PROFILE_UNORDERED_SET
     29 #define _GLIBCXX_PROFILE_UNORDERED_SET 1
     30 
     31 #if __cplusplus < 201103L
     32 # include <bits/c++0x_warning.h>
     33 #else
     34 # include <unordered_set>
     35 
     36 #include <profile/base.h>
     37 
     38 #define _GLIBCXX_BASE unordered_set<_Key, _Hash, _Pred, _Alloc>
     39 #define _GLIBCXX_STD_BASE _GLIBCXX_STD_C::_GLIBCXX_BASE
     40 
     41 namespace std _GLIBCXX_VISIBILITY(default)
     42 {
     43 namespace __profile
     44 {
     45   /** @brief Unordered_set wrapper with performance instrumentation.  */
     46   template<typename _Key, 
     47 	   typename _Hash  = std::hash<_Key>,
     48 	   typename _Pred = std::equal_to<_Key>,
     49 	   typename _Alloc =  std::allocator<_Key> >
     50     class unordered_set
     51     : public _GLIBCXX_STD_BASE
     52     {
     53       typedef _GLIBCXX_STD_BASE _Base;
     54 
     55     public:
     56       typedef typename _Base::size_type       size_type;
     57       typedef typename _Base::hasher          hasher;
     58       typedef typename _Base::key_equal       key_equal;
     59       typedef typename _Base::allocator_type  allocator_type;
     60       typedef typename _Base::key_type        key_type;
     61       typedef typename _Base::value_type      value_type;
     62       typedef typename _Base::difference_type difference_type;
     63       typedef typename _Base::reference       reference;
     64       typedef typename _Base::const_reference const_reference;
     65 
     66       typedef typename _Base::iterator iterator;
     67       typedef typename _Base::const_iterator const_iterator;
     68 
     69       explicit
     70       unordered_set(size_type __n = 10,
     71 		    const hasher& __hf = hasher(),
     72 		    const key_equal& __eql = key_equal(),
     73 		    const allocator_type& __a = allocator_type())
     74       : _Base(__n, __hf, __eql, __a)
     75       {
     76         __profcxx_hashtable_construct(this, _Base::bucket_count());
     77         __profcxx_hashtable_construct2(this);
     78       }
     79 
     80       template<typename _InputIterator>
     81         unordered_set(_InputIterator __f, _InputIterator __l,
     82 		      size_type __n = 0,
     83 		      const hasher& __hf = hasher(),
     84 		      const key_equal& __eql = key_equal(),
     85 		      const allocator_type& __a = allocator_type())
     86       : _Base(__f, __l, __n, __hf, __eql, __a)
     87       {
     88         __profcxx_hashtable_construct(this, _Base::bucket_count());
     89         __profcxx_hashtable_construct2(this);
     90       }
     91 
     92       unordered_set(const unordered_set& __x)
     93       : _Base(__x) 
     94       { 
     95         __profcxx_hashtable_construct(this, _Base::bucket_count());
     96         __profcxx_hashtable_construct2(this);
     97       }
     98 
     99       unordered_set(const _Base& __x)
    100       : _Base(__x) 
    101       { 
    102         __profcxx_hashtable_construct(this, _Base::bucket_count());
    103         __profcxx_hashtable_construct2(this);
    104       }
    105 
    106       unordered_set(unordered_set&& __x)
    107       : _Base(std::move(__x)) 
    108       { 
    109         __profcxx_hashtable_construct(this, _Base::bucket_count());
    110         __profcxx_hashtable_construct2(this);
    111       }
    112 
    113       unordered_set(initializer_list<value_type> __l,
    114 		    size_type __n = 0,
    115 		    const hasher& __hf = hasher(),
    116 		    const key_equal& __eql = key_equal(),
    117 		    const allocator_type& __a = allocator_type())
    118       : _Base(__l, __n, __hf, __eql, __a) { }
    119 
    120       unordered_set&
    121       operator=(const unordered_set& __x)
    122       {
    123 	*static_cast<_Base*>(this) = __x;
    124 	return *this;
    125       }
    126 
    127       unordered_set&
    128       operator=(unordered_set&& __x)
    129       {
    130 	// NB: DR 1204.
    131 	// NB: DR 675.
    132 	this->clear();
    133 	this->swap(__x);
    134 	return *this;
    135       }
    136 
    137       unordered_set&
    138       operator=(initializer_list<value_type> __l)
    139       {
    140 	this->clear();
    141 	this->insert(__l);
    142 	return *this;
    143       }
    144 
    145       ~unordered_set() noexcept
    146       {
    147         __profcxx_hashtable_destruct(this, _Base::bucket_count(), 
    148                                      _Base::size());
    149         _M_profile_destruct();
    150       }
    151 
    152       void
    153       swap(unordered_set& __x)
    154       {
    155         _Base::swap(__x);
    156       }
    157 
    158       void
    159       clear() noexcept
    160       {
    161         __profcxx_hashtable_destruct(this, _Base::bucket_count(), 
    162                                      _Base::size());
    163         _M_profile_destruct();
    164         _Base::clear();
    165       }
    166 
    167       template<typename... _Args>
    168 	std::pair<iterator, bool>
    169 	emplace(_Args&&... __args)
    170 	{
    171 	  size_type __old_size = _Base::bucket_count();
    172 	  std::pair<iterator, bool> __res
    173 	    = _Base::emplace(std::forward<_Args>(__args)...);
    174 	  _M_profile_resize(__old_size);
    175 	  return __res;
    176 	}
    177 
    178       template<typename... _Args>
    179 	iterator
    180 	emplace_hint(const_iterator __it, _Args&&... __args)
    181 	{
    182 	  size_type __old_size = _Base::bucket_count();
    183 	  iterator __res
    184 	    = _Base::emplace_hint(__it, std::forward<_Args>(__args)...);
    185 	  _M_profile_resize(__old_size);
    186 	  return __res;
    187 	}
    188 
    189       void
    190       insert(std::initializer_list<value_type> __l)
    191       { 
    192         size_type __old_size = _Base::bucket_count();
    193         _Base::insert(__l); 
    194         _M_profile_resize(__old_size); 
    195       }
    196 
    197       std::pair<iterator, bool>
    198       insert(const value_type& __obj)
    199       {
    200         size_type __old_size = _Base::bucket_count();
    201         std::pair<iterator, bool> __res = _Base::insert(__obj);
    202         _M_profile_resize(__old_size); 
    203         return __res;
    204       }
    205 
    206       iterator
    207       insert(const_iterator __iter, const value_type& __v)
    208       { 
    209         size_type __old_size = _Base::bucket_count(); 
    210         iterator __res = _Base::insert(__iter, __v);
    211         _M_profile_resize(__old_size); 
    212         return __res;
    213       }
    214 
    215       std::pair<iterator, bool>
    216       insert(value_type&& __obj)
    217       {
    218         size_type __old_size = _Base::bucket_count();
    219         std::pair<iterator, bool> __res = _Base::insert(std::move(__obj));
    220         _M_profile_resize(__old_size); 
    221         return __res;
    222       }
    223 
    224       iterator
    225       insert(const_iterator __iter, value_type&& __v)
    226       { 
    227         size_type __old_size = _Base::bucket_count();
    228         iterator __res = _Base::insert(__iter, std::move(__v));
    229         _M_profile_resize(__old_size); 
    230         return __res;
    231       }
    232 
    233       template<typename _InputIter>
    234         void
    235         insert(_InputIter __first, _InputIter __last)
    236         {
    237 	  size_type __old_size = _Base::bucket_count(); 
    238 	  _Base::insert(__first, __last);
    239 	  _M_profile_resize(__old_size); 
    240 	}
    241 
    242       void
    243       insert(const value_type* __first, const value_type* __last)
    244       {
    245         size_type __old_size = _Base::bucket_count(); 
    246         _Base::insert(__first, __last);
    247         _M_profile_resize(__old_size); 
    248       }
    249      
    250       void rehash(size_type __n)
    251       {
    252         size_type __old_size = _Base::bucket_count();
    253         _Base::rehash(__n);
    254         _M_profile_resize(__old_size); 
    255       }
    256 
    257     private:
    258       void
    259       _M_profile_resize(size_type __old_size)
    260       {
    261 	size_type __new_size = _Base::bucket_count();
    262 	if (__old_size != __new_size)
    263 	  __profcxx_hashtable_resize(this, __old_size, __new_size);
    264       }
    265 
    266       void
    267       _M_profile_destruct()
    268       {
    269 	size_type __hops = 0, __lc = 0, __chain = 0;
    270 	iterator __it = this->begin();
    271 	while (__it != this->end())
    272 	  {
    273 	    size_type __bkt = this->bucket(*__it);
    274 	    auto __lit = this->begin(__bkt);
    275 	    auto __lend = this->end(__bkt);
    276 	    for (++__it, ++__lit; __lit != __lend; ++__it, ++__lit)
    277 	      ++__chain;
    278 	    if (__chain)
    279 	      {
    280 		++__chain;
    281 		__lc = __lc > __chain ? __lc : __chain;
    282 		__hops += __chain * (__chain - 1) / 2;
    283 		__chain = 0;
    284 	      }
    285 	  }
    286         __profcxx_hashtable_destruct2(this, __lc, _Base::size(), __hops);
    287       }
    288   };
    289 
    290   template<typename _Key, typename _Hash, typename _Pred, typename _Alloc>
    291     inline void
    292     swap(unordered_set<_Key, _Hash, _Pred, _Alloc>& __x,
    293 	 unordered_set<_Key, _Hash, _Pred, _Alloc>& __y)
    294     { __x.swap(__y); }
    295 
    296   template<typename _Key, typename _Hash, typename _Pred, typename _Alloc>
    297     inline bool
    298     operator==(const unordered_set<_Key, _Hash, _Pred, _Alloc>& __x,
    299 	       const unordered_set<_Key, _Hash, _Pred, _Alloc>& __y)
    300     { return static_cast<const _GLIBCXX_STD_BASE&>(__x) == __y; }
    301 
    302   template<typename _Key, typename _Hash, typename _Pred, typename _Alloc>
    303     inline bool
    304     operator!=(const unordered_set<_Key, _Hash, _Pred, _Alloc>& __x,
    305 	       const unordered_set<_Key, _Hash, _Pred, _Alloc>& __y)
    306     { return !(__x == __y); }
    307 
    308 #undef _GLIBCXX_BASE
    309 #undef _GLIBCXX_STD_BASE
    310 #define _GLIBCXX_STD_BASE _GLIBCXX_STD_C::_GLIBCXX_BASE
    311 #define _GLIBCXX_BASE unordered_multiset<_Value, _Hash, _Pred, _Alloc>
    312 
    313   /** @brief Unordered_multiset wrapper with performance instrumentation.  */
    314   template<typename _Value,
    315        typename _Hash  = std::hash<_Value>,
    316        typename _Pred = std::equal_to<_Value>,
    317        typename _Alloc =  std::allocator<_Value> >
    318     class unordered_multiset
    319     : public _GLIBCXX_STD_BASE
    320     {
    321       typedef _GLIBCXX_STD_BASE _Base;
    322 
    323     public:
    324       typedef typename _Base::size_type       size_type;
    325       typedef typename _Base::hasher          hasher;
    326       typedef typename _Base::key_equal       key_equal;
    327       typedef typename _Base::allocator_type  allocator_type;
    328       typedef typename _Base::key_type        key_type;
    329       typedef typename _Base::value_type      value_type;
    330       typedef typename _Base::difference_type difference_type;
    331       typedef typename _Base::reference       reference;
    332       typedef typename _Base::const_reference const_reference;
    333 
    334       typedef typename _Base::iterator iterator;
    335       typedef typename _Base::const_iterator const_iterator;
    336 
    337       explicit
    338       unordered_multiset(size_type __n = 10,
    339 			 const hasher& __hf = hasher(),
    340 			 const key_equal& __eql = key_equal(),
    341 			 const allocator_type& __a = allocator_type())
    342       : _Base(__n, __hf, __eql, __a)
    343       {
    344         __profcxx_hashtable_construct(this, _Base::bucket_count());
    345       }
    346 
    347       template<typename _InputIterator>
    348         unordered_multiset(_InputIterator __f, _InputIterator __l,
    349 			   size_type __n = 0,
    350 			   const hasher& __hf = hasher(),
    351 			   const key_equal& __eql = key_equal(),
    352 			   const allocator_type& __a = allocator_type())
    353       : _Base(__f, __l, __n, __hf, __eql, __a)
    354       {
    355         __profcxx_hashtable_construct(this, _Base::bucket_count());
    356       }
    357 
    358       unordered_multiset(const unordered_multiset& __x)
    359       : _Base(__x)
    360       {
    361         __profcxx_hashtable_construct(this, _Base::bucket_count());
    362       }
    363 
    364       unordered_multiset(const _Base& __x)
    365       : _Base(__x)
    366       {
    367         __profcxx_hashtable_construct(this, _Base::bucket_count());
    368       }
    369 
    370       unordered_multiset(unordered_multiset&& __x)
    371       : _Base(std::move(__x))
    372       {
    373         __profcxx_hashtable_construct(this, _Base::bucket_count());
    374       }
    375 
    376       unordered_multiset(initializer_list<value_type> __l,
    377 			 size_type __n = 0,
    378 			 const hasher& __hf = hasher(),
    379 			 const key_equal& __eql = key_equal(),
    380 			 const allocator_type& __a = allocator_type())
    381       : _Base(__l, __n, __hf, __eql, __a) { }
    382 
    383       unordered_multiset&
    384       operator=(const unordered_multiset& __x)
    385       {
    386 	*static_cast<_Base*>(this) = __x;
    387 	return *this;
    388       }
    389 
    390       unordered_multiset&
    391       operator=(unordered_multiset&& __x)
    392       {
    393 	// NB: DR 1204.
    394 	// NB: DR 675.
    395 	this->clear();
    396 	this->swap(__x);
    397 	return *this;
    398       }
    399 
    400       unordered_multiset&
    401       operator=(initializer_list<value_type> __l)
    402       {
    403 	this->clear();
    404 	this->insert(__l);
    405 	return *this;
    406       }
    407 
    408       ~unordered_multiset() noexcept
    409       {
    410         __profcxx_hashtable_destruct(this, _Base::bucket_count(), 
    411                                      _Base::size());
    412         _M_profile_destruct();
    413       }
    414 
    415       void
    416       swap(unordered_multiset& __x)
    417       {
    418         _Base::swap(__x);
    419       }
    420 
    421       void
    422       clear() noexcept
    423       {
    424         __profcxx_hashtable_destruct(this, _Base::bucket_count(), 
    425                                      _Base::size());
    426         _M_profile_destruct();
    427         _Base::clear();
    428       }
    429 
    430       template<typename... _Args>
    431 	iterator
    432 	emplace(_Args&&... __args)
    433 	{
    434 	  size_type __old_size = _Base::bucket_count();
    435 	  iterator __res = _Base::emplace(std::forward<_Args>(__args)...);
    436 	  _M_profile_resize(__old_size);
    437 	  return __res;
    438 	}
    439 
    440       template<typename... _Args>
    441 	iterator
    442 	emplace_hint(const_iterator __it, _Args&&... __args)
    443 	{
    444 	  size_type __old_size = _Base::bucket_count();
    445 	  iterator __res
    446 	    = _Base::emplace_hint(__it, std::forward<_Args>(__args)...);
    447 	  _M_profile_resize(__old_size);
    448 	  return __res;
    449 	}
    450 
    451       void
    452       insert(std::initializer_list<value_type> __l)
    453       { 
    454         size_type __old_size = _Base::bucket_count();
    455         _Base::insert(__l); 
    456         _M_profile_resize(__old_size); 
    457       }
    458 
    459       iterator
    460       insert(const value_type& __obj)
    461       {
    462         size_type __old_size = _Base::bucket_count();
    463         iterator __res = _Base::insert(__obj);
    464         _M_profile_resize(__old_size); 
    465         return __res;
    466       }
    467 
    468       iterator
    469       insert(const_iterator __iter, const value_type& __v)
    470       {
    471         size_type __old_size = _Base::bucket_count(); 
    472         iterator __res = _Base::insert(__iter, __v);
    473         _M_profile_resize(__old_size); 
    474         return __res;
    475       }
    476 
    477       iterator
    478       insert(value_type&& __obj)
    479       {
    480 	size_type __old_size = _Base::bucket_count();
    481         iterator __res = _Base::insert(std::move(__obj));
    482         _M_profile_resize(__old_size); 
    483         return __res;
    484       }
    485 
    486       iterator
    487       insert(const_iterator __iter, value_type&& __v)
    488       {
    489         size_type __old_size = _Base::bucket_count(); 
    490         iterator __res = _Base::insert(__iter, std::move(__v));
    491         _M_profile_resize(__old_size); 
    492         return __res;
    493       }
    494 
    495       template<typename _InputIter>
    496         void
    497         insert(_InputIter __first, _InputIter __last)
    498         {
    499 	  size_type __old_size = _Base::bucket_count(); 
    500 	  _Base::insert(__first, __last);
    501 	  _M_profile_resize(__old_size); 
    502 	}
    503 
    504       void
    505       insert(const value_type* __first, const value_type* __last)
    506       {
    507         size_type __old_size = _Base::bucket_count(); 
    508         _Base::insert(__first, __last);
    509         _M_profile_resize(__old_size); 
    510       }
    511      
    512       void rehash(size_type __n)
    513       {
    514         size_type __old_size = _Base::bucket_count();
    515         _Base::rehash(__n);
    516         _M_profile_resize(__old_size); 
    517       }
    518 
    519     private:
    520       void
    521       _M_profile_resize(size_type __old_size)
    522       {
    523 	size_type __new_size = _Base::bucket_count();
    524         if (__old_size != __new_size)
    525           __profcxx_hashtable_resize(this, __old_size, __new_size);
    526       }
    527 
    528       void
    529       _M_profile_destruct()
    530       {
    531 	size_type __hops = 0, __lc = 0, __chain = 0;
    532 	iterator __it = this->begin();
    533 	while (__it != this->end())
    534 	  {
    535 	    size_type __bkt = this->bucket(*__it);
    536 	    auto __lit = this->begin(__bkt);
    537 	    auto __lend = this->end(__bkt);
    538 	    for (++__it, ++__lit; __lit != __lend; ++__it, ++__lit)
    539 	      ++__chain;
    540 	    if (__chain)
    541 	      {
    542 		++__chain;
    543 		__lc = __lc > __chain ? __lc : __chain;
    544 		__hops += __chain * (__chain - 1) / 2;
    545 		__chain = 0;
    546 	      }
    547 	  }
    548         __profcxx_hashtable_destruct2(this, __lc, _Base::size(), __hops);
    549       }
    550    };
    551 
    552   template<typename _Value, typename _Hash, typename _Pred, typename _Alloc>
    553     inline void
    554     swap(unordered_multiset<_Value, _Hash, _Pred, _Alloc>& __x,
    555 	 unordered_multiset<_Value, _Hash, _Pred, _Alloc>& __y)
    556     { __x.swap(__y); }
    557 
    558   template<typename _Value, typename _Hash, typename _Pred, typename _Alloc>
    559     inline bool
    560     operator==(const unordered_multiset<_Value, _Hash, _Pred, _Alloc>& __x,
    561 	       const unordered_multiset<_Value, _Hash, _Pred, _Alloc>& __y)
    562     { return static_cast<const _GLIBCXX_STD_BASE&>(__x) == __y; }
    563 
    564   template<typename _Value, typename _Hash, typename _Pred, typename _Alloc>
    565     inline bool
    566     operator!=(const unordered_multiset<_Value, _Hash, _Pred, _Alloc>& __x,
    567 	       const unordered_multiset<_Value, _Hash, _Pred, _Alloc>& __y)
    568     { return !(__x == __y); }
    569 
    570 } // namespace __profile
    571 } // namespace std
    572 
    573 #undef _GLIBCXX_BASE
    574 #undef _GLIBCXX_STD_BASE
    575 
    576 #endif // C++11
    577 
    578 #endif
    579