hashtable.hpp 144 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531
  1. /////////////////////////////////////////////////////////////////////////////
  2. //
  3. // (C) Copyright Ion Gaztanaga 2006-2015
  4. //
  5. // Distributed under the Boost Software License, Version 1.0.
  6. // (See accompanying file LICENSE_1_0.txt or copy at
  7. // http://www.boost.org/LICENSE_1_0.txt)
  8. //
  9. // See http://www.boost.org/libs/intrusive for documentation.
  10. //
  11. /////////////////////////////////////////////////////////////////////////////
  12. #ifndef BOOST_INTRUSIVE_HASHTABLE_HPP
  13. #define BOOST_INTRUSIVE_HASHTABLE_HPP
  14. #include <boost/intrusive/detail/config_begin.hpp>
  15. #include <boost/intrusive/intrusive_fwd.hpp>
  16. //General intrusive utilities
  17. #include <boost/intrusive/detail/hashtable_node.hpp>
  18. #include <boost/intrusive/detail/transform_iterator.hpp>
  19. #include <boost/intrusive/link_mode.hpp>
  20. #include <boost/intrusive/detail/ebo_functor_holder.hpp>
  21. #include <boost/intrusive/detail/is_stateful_value_traits.hpp>
  22. #include <boost/intrusive/detail/node_to_value.hpp>
  23. #include <boost/intrusive/detail/exception_disposer.hpp>
  24. #include <boost/intrusive/detail/node_cloner_disposer.hpp>
  25. #include <boost/intrusive/detail/simple_disposers.hpp>
  26. #include <boost/intrusive/detail/size_holder.hpp>
  27. #include <boost/intrusive/detail/iterator.hpp>
  28. //Implementation utilities
  29. #include <boost/intrusive/unordered_set_hook.hpp>
  30. #include <boost/intrusive/slist.hpp>
  31. #include <boost/intrusive/pointer_traits.hpp>
  32. #include <boost/intrusive/detail/mpl.hpp>
  33. //boost
  34. #include <boost/functional/hash.hpp>
  35. #include <boost/intrusive/detail/assert.hpp>
  36. #include <boost/static_assert.hpp>
  37. #include <boost/move/utility_core.hpp>
  38. #include <boost/move/adl_move_swap.hpp>
  39. //std C++
  40. #include <boost/intrusive/detail/minimal_less_equal_header.hpp> //std::equal_to
  41. #include <boost/intrusive/detail/minimal_pair_header.hpp> //std::pair
  42. #include <algorithm> //std::lower_bound, std::upper_bound
  43. #include <cstddef> //std::size_t
  44. #if defined(BOOST_HAS_PRAGMA_ONCE)
  45. # pragma once
  46. #endif
  47. namespace boost {
  48. namespace intrusive {
  49. /// @cond
  50. template<class InputIt, class T>
  51. InputIt priv_algo_find(InputIt first, InputIt last, const T& value)
  52. {
  53. for (; first != last; ++first) {
  54. if (*first == value) {
  55. return first;
  56. }
  57. }
  58. return last;
  59. }
  60. template<class InputIt, class T>
  61. typename boost::intrusive::iterator_traits<InputIt>::difference_type
  62. priv_algo_count(InputIt first, InputIt last, const T& value)
  63. {
  64. typename boost::intrusive::iterator_traits<InputIt>::difference_type ret = 0;
  65. for (; first != last; ++first) {
  66. if (*first == value) {
  67. ret++;
  68. }
  69. }
  70. return ret;
  71. }
  72. template <class ForwardIterator1, class ForwardIterator2>
  73. bool priv_algo_is_permutation(ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2)
  74. {
  75. typedef typename
  76. boost::intrusive::iterator_traits<ForwardIterator2>::difference_type
  77. distance_type;
  78. //Efficiently compare identical prefixes: O(N) if sequences
  79. //have the same elements in the same order.
  80. for ( ; first1 != last1; ++first1, ++first2){
  81. if (! (*first1 == *first2))
  82. break;
  83. }
  84. if (first1 == last1){
  85. return true;
  86. }
  87. //Establish last2 assuming equal ranges by iterating over the
  88. //rest of the list.
  89. ForwardIterator2 last2 = first2;
  90. boost::intrusive::iterator_advance(last2, boost::intrusive::iterator_distance(first1, last1));
  91. for(ForwardIterator1 scan = first1; scan != last1; ++scan){
  92. if (scan != (priv_algo_find)(first1, scan, *scan)){
  93. continue; //We've seen this one before.
  94. }
  95. distance_type matches = (priv_algo_count)(first2, last2, *scan);
  96. if (0 == matches || (priv_algo_count)(scan, last1, *scan != matches)){
  97. return false;
  98. }
  99. }
  100. return true;
  101. }
  102. template<int Dummy = 0>
  103. struct prime_list_holder
  104. {
  105. static const std::size_t prime_list[];
  106. static const std::size_t prime_list_size;
  107. };
  108. //We only support LLP64(Win64) or LP64(most Unix) data models
  109. #ifdef _WIN64 //In 64 bit windows sizeof(size_t) == sizeof(unsigned long long)
  110. #define BOOST_INTRUSIVE_PRIME_C(NUMBER) NUMBER##ULL
  111. #define BOOST_INTRUSIVE_64_BIT_SIZE_T 1
  112. #else //In 32 bit windows and 32/64 bit unixes sizeof(size_t) == sizeof(unsigned long)
  113. #define BOOST_INTRUSIVE_PRIME_C(NUMBER) NUMBER##UL
  114. #define BOOST_INTRUSIVE_64_BIT_SIZE_T (((((ULONG_MAX>>16)>>16)>>16)>>15) != 0)
  115. #endif
  116. template<int Dummy>
  117. const std::size_t prime_list_holder<Dummy>::prime_list[] = {
  118. BOOST_INTRUSIVE_PRIME_C(3), BOOST_INTRUSIVE_PRIME_C(7),
  119. BOOST_INTRUSIVE_PRIME_C(11), BOOST_INTRUSIVE_PRIME_C(17),
  120. BOOST_INTRUSIVE_PRIME_C(29), BOOST_INTRUSIVE_PRIME_C(53),
  121. BOOST_INTRUSIVE_PRIME_C(97), BOOST_INTRUSIVE_PRIME_C(193),
  122. BOOST_INTRUSIVE_PRIME_C(389), BOOST_INTRUSIVE_PRIME_C(769),
  123. BOOST_INTRUSIVE_PRIME_C(1543), BOOST_INTRUSIVE_PRIME_C(3079),
  124. BOOST_INTRUSIVE_PRIME_C(6151), BOOST_INTRUSIVE_PRIME_C(12289),
  125. BOOST_INTRUSIVE_PRIME_C(24593), BOOST_INTRUSIVE_PRIME_C(49157),
  126. BOOST_INTRUSIVE_PRIME_C(98317), BOOST_INTRUSIVE_PRIME_C(196613),
  127. BOOST_INTRUSIVE_PRIME_C(393241), BOOST_INTRUSIVE_PRIME_C(786433),
  128. BOOST_INTRUSIVE_PRIME_C(1572869), BOOST_INTRUSIVE_PRIME_C(3145739),
  129. BOOST_INTRUSIVE_PRIME_C(6291469), BOOST_INTRUSIVE_PRIME_C(12582917),
  130. BOOST_INTRUSIVE_PRIME_C(25165843), BOOST_INTRUSIVE_PRIME_C(50331653),
  131. BOOST_INTRUSIVE_PRIME_C(100663319), BOOST_INTRUSIVE_PRIME_C(201326611),
  132. BOOST_INTRUSIVE_PRIME_C(402653189), BOOST_INTRUSIVE_PRIME_C(805306457),
  133. BOOST_INTRUSIVE_PRIME_C(1610612741), BOOST_INTRUSIVE_PRIME_C(3221225473),
  134. #if BOOST_INTRUSIVE_64_BIT_SIZE_T
  135. //Taken from Boost.MultiIndex code, thanks to Joaquin M Lopez Munoz.
  136. BOOST_INTRUSIVE_PRIME_C(6442450939), BOOST_INTRUSIVE_PRIME_C(12884901893),
  137. BOOST_INTRUSIVE_PRIME_C(25769803751), BOOST_INTRUSIVE_PRIME_C(51539607551),
  138. BOOST_INTRUSIVE_PRIME_C(103079215111), BOOST_INTRUSIVE_PRIME_C(206158430209),
  139. BOOST_INTRUSIVE_PRIME_C(412316860441), BOOST_INTRUSIVE_PRIME_C(824633720831),
  140. BOOST_INTRUSIVE_PRIME_C(1649267441651), BOOST_INTRUSIVE_PRIME_C(3298534883309),
  141. BOOST_INTRUSIVE_PRIME_C(6597069766657), BOOST_INTRUSIVE_PRIME_C(13194139533299),
  142. BOOST_INTRUSIVE_PRIME_C(26388279066623), BOOST_INTRUSIVE_PRIME_C(52776558133303),
  143. BOOST_INTRUSIVE_PRIME_C(105553116266489), BOOST_INTRUSIVE_PRIME_C(211106232532969),
  144. BOOST_INTRUSIVE_PRIME_C(422212465066001), BOOST_INTRUSIVE_PRIME_C(844424930131963),
  145. BOOST_INTRUSIVE_PRIME_C(1688849860263953), BOOST_INTRUSIVE_PRIME_C(3377699720527861),
  146. BOOST_INTRUSIVE_PRIME_C(6755399441055731), BOOST_INTRUSIVE_PRIME_C(13510798882111483),
  147. BOOST_INTRUSIVE_PRIME_C(27021597764222939), BOOST_INTRUSIVE_PRIME_C(54043195528445957),
  148. BOOST_INTRUSIVE_PRIME_C(108086391056891903), BOOST_INTRUSIVE_PRIME_C(216172782113783843),
  149. BOOST_INTRUSIVE_PRIME_C(432345564227567621), BOOST_INTRUSIVE_PRIME_C(864691128455135207),
  150. BOOST_INTRUSIVE_PRIME_C(1729382256910270481), BOOST_INTRUSIVE_PRIME_C(3458764513820540933),
  151. BOOST_INTRUSIVE_PRIME_C(6917529027641081903), BOOST_INTRUSIVE_PRIME_C(13835058055282163729),
  152. BOOST_INTRUSIVE_PRIME_C(18446744073709551557)
  153. #else
  154. BOOST_INTRUSIVE_PRIME_C(4294967291)
  155. #endif
  156. };
  157. #undef BOOST_INTRUSIVE_PRIME_C
  158. #undef BOOST_INTRUSIVE_64_BIT_SIZE_T
  159. template<int Dummy>
  160. const std::size_t prime_list_holder<Dummy>::prime_list_size
  161. = sizeof(prime_list)/sizeof(std::size_t);
  162. struct hash_bool_flags
  163. {
  164. static const std::size_t unique_keys_pos = 1u;
  165. static const std::size_t constant_time_size_pos = 2u;
  166. static const std::size_t power_2_buckets_pos = 4u;
  167. static const std::size_t cache_begin_pos = 8u;
  168. static const std::size_t compare_hash_pos = 16u;
  169. static const std::size_t incremental_pos = 32u;
  170. };
  171. namespace detail {
  172. template<class SupposedValueTraits>
  173. struct get_slist_impl_from_supposed_value_traits
  174. {
  175. typedef SupposedValueTraits value_traits;
  176. typedef typename detail::get_node_traits
  177. <value_traits>::type node_traits;
  178. typedef typename get_slist_impl
  179. <typename reduced_slist_node_traits
  180. <node_traits>::type
  181. >::type type;
  182. };
  183. template<class SupposedValueTraits>
  184. struct unordered_bucket_impl
  185. {
  186. typedef typename
  187. get_slist_impl_from_supposed_value_traits
  188. <SupposedValueTraits>::type slist_impl;
  189. typedef detail::bucket_impl<slist_impl> implementation_defined;
  190. typedef implementation_defined type;
  191. };
  192. template<class SupposedValueTraits>
  193. struct unordered_bucket_ptr_impl
  194. {
  195. typedef typename detail::get_node_traits
  196. <SupposedValueTraits>::type::node_ptr node_ptr;
  197. typedef typename unordered_bucket_impl
  198. <SupposedValueTraits>::type bucket_type;
  199. typedef typename pointer_traits
  200. <node_ptr>::template rebind_pointer
  201. < bucket_type >::type implementation_defined;
  202. typedef implementation_defined type;
  203. };
  204. template <class T>
  205. struct store_hash_is_true
  206. {
  207. template<bool Add>
  208. struct two_or_three {yes_type _[2 + Add];};
  209. template <class U> static yes_type test(...);
  210. template <class U> static two_or_three<U::store_hash> test (int);
  211. static const bool value = sizeof(test<T>(0)) > sizeof(yes_type)*2;
  212. };
  213. template <class T>
  214. struct optimize_multikey_is_true
  215. {
  216. template<bool Add>
  217. struct two_or_three {yes_type _[2 + Add];};
  218. template <class U> static yes_type test(...);
  219. template <class U> static two_or_three<U::optimize_multikey> test (int);
  220. static const bool value = sizeof(test<T>(0)) > sizeof(yes_type)*2;
  221. };
  222. struct insert_commit_data_impl
  223. {
  224. std::size_t hash;
  225. };
  226. template<class Node, class SlistNodePtr>
  227. inline typename pointer_traits<SlistNodePtr>::template rebind_pointer<Node>::type
  228. dcast_bucket_ptr(const SlistNodePtr &p)
  229. {
  230. typedef typename pointer_traits<SlistNodePtr>::template rebind_pointer<Node>::type node_ptr;
  231. return pointer_traits<node_ptr>::pointer_to(static_cast<Node&>(*p));
  232. }
  233. template<class NodeTraits>
  234. struct group_functions
  235. {
  236. // A group is reverse-linked
  237. //
  238. // A is "first in group"
  239. // C is "last in group"
  240. // __________________
  241. // | _____ _____ |
  242. // | | | | | | <- Group links
  243. // ^ V ^ V ^ V
  244. // _ _ _ _
  245. // A|_| B|_| C|_| D|_|
  246. //
  247. // ^ | ^ | ^ | ^ V <- Bucket links
  248. // _ _____| |_____| |______| |____| |
  249. // |B| |
  250. // ^________________________________|
  251. //
  252. typedef NodeTraits node_traits;
  253. typedef unordered_group_adapter<node_traits> group_traits;
  254. typedef typename node_traits::node_ptr node_ptr;
  255. typedef typename node_traits::node node;
  256. typedef typename reduced_slist_node_traits
  257. <node_traits>::type reduced_node_traits;
  258. typedef typename reduced_node_traits::node_ptr slist_node_ptr;
  259. typedef typename reduced_node_traits::node slist_node;
  260. typedef circular_slist_algorithms<group_traits> group_algorithms;
  261. typedef circular_slist_algorithms<node_traits> node_algorithms;
  262. static slist_node_ptr get_bucket_before_begin
  263. (const slist_node_ptr &bucket_beg, const slist_node_ptr &bucket_end, const node_ptr &p)
  264. {
  265. //First find the last node of p's group.
  266. //This requires checking the first node of the next group or
  267. //the bucket node.
  268. node_ptr prev_node = p;
  269. node_ptr nxt(node_traits::get_next(p));
  270. while(!(bucket_beg <= nxt && nxt <= bucket_end) &&
  271. (group_traits::get_next(nxt) == prev_node)){
  272. prev_node = nxt;
  273. nxt = node_traits::get_next(nxt);
  274. }
  275. //If we've reached the bucket node just return it.
  276. if(bucket_beg <= nxt && nxt <= bucket_end){
  277. return nxt;
  278. }
  279. //Otherwise, iterate using group links until the bucket node
  280. node_ptr first_node_of_group = nxt;
  281. node_ptr last_node_group = group_traits::get_next(first_node_of_group);
  282. slist_node_ptr possible_end = node_traits::get_next(last_node_group);
  283. while(!(bucket_beg <= possible_end && possible_end <= bucket_end)){
  284. first_node_of_group = detail::dcast_bucket_ptr<node>(possible_end);
  285. last_node_group = group_traits::get_next(first_node_of_group);
  286. possible_end = node_traits::get_next(last_node_group);
  287. }
  288. return possible_end;
  289. }
  290. static node_ptr get_prev_to_first_in_group(const slist_node_ptr &bucket_node, const node_ptr &first_in_group)
  291. {
  292. node_ptr nb = detail::dcast_bucket_ptr<node>(bucket_node);
  293. node_ptr n;
  294. while((n = node_traits::get_next(nb)) != first_in_group){
  295. nb = group_traits::get_next(n); //go to last in group
  296. }
  297. return nb;
  298. }
  299. static void erase_from_group(const slist_node_ptr &end_ptr, const node_ptr &to_erase_ptr, detail::true_)
  300. {
  301. node_ptr const nxt_ptr(node_traits::get_next(to_erase_ptr));
  302. //Check if the next node is in the group (not end node) and reverse linked to
  303. //'to_erase_ptr'. Erase if that's the case.
  304. if(nxt_ptr != end_ptr && to_erase_ptr == group_traits::get_next(nxt_ptr)){
  305. group_algorithms::unlink_after(nxt_ptr);
  306. }
  307. }
  308. static void erase_from_group(const slist_node_ptr&, const node_ptr&, detail::false_)
  309. {}
  310. static node_ptr get_last_in_group(const node_ptr &first_in_group, detail::true_)
  311. { return group_traits::get_next(first_in_group); }
  312. static node_ptr get_last_in_group(node_ptr n, detail::false_)
  313. { return n; }
  314. static node_ptr get_first_in_group(node_ptr n, detail::true_)
  315. {
  316. node_ptr ng;
  317. while(n == node_traits::get_next((ng = group_traits::get_next(n)))){
  318. n = ng;
  319. }
  320. return n;
  321. }
  322. static node_ptr next_group_if_first_in_group(node_ptr ptr)
  323. {
  324. return node_traits::get_next(group_traits::get_next(ptr));
  325. }
  326. static node_ptr get_first_in_group(const node_ptr &n, detail::false_)
  327. { return n; }
  328. static void insert_in_group(const node_ptr &first_in_group, const node_ptr &n, true_)
  329. { group_algorithms::link_after(first_in_group, n); }
  330. static void insert_in_group(const node_ptr&, const node_ptr&, false_)
  331. {}
  332. static node_ptr split_group(node_ptr const new_first_in_group)
  333. {
  334. node_ptr const first((get_first_in_group)(new_first_in_group, detail::true_()));
  335. if(first != new_first_in_group){
  336. node_ptr const last = group_traits::get_next(first);
  337. group_traits::set_next(first, group_traits::get_next(new_first_in_group));
  338. group_traits::set_next(new_first_in_group, last);
  339. }
  340. return first;
  341. }
  342. };
  343. template<class BucketType, class SplitTraits>
  344. class incremental_rehash_rollback
  345. {
  346. private:
  347. typedef BucketType bucket_type;
  348. typedef SplitTraits split_traits;
  349. incremental_rehash_rollback();
  350. incremental_rehash_rollback & operator=(const incremental_rehash_rollback &);
  351. incremental_rehash_rollback (const incremental_rehash_rollback &);
  352. public:
  353. incremental_rehash_rollback
  354. (bucket_type &source_bucket, bucket_type &destiny_bucket, split_traits &split_traits)
  355. : source_bucket_(source_bucket), destiny_bucket_(destiny_bucket)
  356. , split_traits_(split_traits), released_(false)
  357. {}
  358. void release()
  359. { released_ = true; }
  360. ~incremental_rehash_rollback()
  361. {
  362. if(!released_){
  363. //If an exception is thrown, just put all moved nodes back in the old bucket
  364. //and move back the split mark.
  365. destiny_bucket_.splice_after(destiny_bucket_.before_begin(), source_bucket_);
  366. split_traits_.decrement();
  367. }
  368. }
  369. private:
  370. bucket_type &source_bucket_;
  371. bucket_type &destiny_bucket_;
  372. split_traits &split_traits_;
  373. bool released_;
  374. };
  375. template<class NodeTraits>
  376. struct node_functions
  377. {
  378. static void store_hash(typename NodeTraits::node_ptr p, std::size_t h, true_)
  379. { return NodeTraits::set_hash(p, h); }
  380. static void store_hash(typename NodeTraits::node_ptr, std::size_t, false_)
  381. {}
  382. };
  383. inline std::size_t hash_to_bucket(std::size_t hash_value, std::size_t bucket_cnt, detail::false_)
  384. { return hash_value % bucket_cnt; }
  385. inline std::size_t hash_to_bucket(std::size_t hash_value, std::size_t bucket_cnt, detail::true_)
  386. { return hash_value & (bucket_cnt - 1); }
  387. template<bool Power2Buckets, bool Incremental>
  388. inline std::size_t hash_to_bucket_split(std::size_t hash_value, std::size_t bucket_cnt, std::size_t split)
  389. {
  390. std::size_t bucket_number = detail::hash_to_bucket(hash_value, bucket_cnt, detail::bool_<Power2Buckets>());
  391. if(Incremental)
  392. bucket_number -= static_cast<std::size_t>(bucket_number >= split)*(bucket_cnt/2);
  393. return bucket_number;
  394. }
  395. } //namespace detail {
  396. //!This metafunction will obtain the type of a bucket
  397. //!from the value_traits or hook option to be used with
  398. //!a hash container.
  399. template<class ValueTraitsOrHookOption>
  400. struct unordered_bucket
  401. : public detail::unordered_bucket_impl
  402. <typename ValueTraitsOrHookOption::
  403. template pack<empty>::proto_value_traits
  404. >
  405. {};
  406. //!This metafunction will obtain the type of a bucket pointer
  407. //!from the value_traits or hook option to be used with
  408. //!a hash container.
  409. template<class ValueTraitsOrHookOption>
  410. struct unordered_bucket_ptr
  411. : public detail::unordered_bucket_ptr_impl
  412. <typename ValueTraitsOrHookOption::
  413. template pack<empty>::proto_value_traits
  414. >
  415. {};
  416. //!This metafunction will obtain the type of the default bucket traits
  417. //!(when the user does not specify the bucket_traits<> option) from the
  418. //!value_traits or hook option to be used with
  419. //!a hash container.
  420. template<class ValueTraitsOrHookOption>
  421. struct unordered_default_bucket_traits
  422. {
  423. typedef typename ValueTraitsOrHookOption::
  424. template pack<empty>::proto_value_traits supposed_value_traits;
  425. typedef typename detail::
  426. get_slist_impl_from_supposed_value_traits
  427. <supposed_value_traits>::type slist_impl;
  428. typedef detail::bucket_traits_impl
  429. <slist_impl> implementation_defined;
  430. typedef implementation_defined type;
  431. };
  432. struct default_bucket_traits;
  433. //hashtable default hook traits
  434. struct default_hashtable_hook_applier
  435. { template <class T> struct apply{ typedef typename T::default_hashtable_hook type; }; };
  436. template<>
  437. struct is_default_hook_tag<default_hashtable_hook_applier>
  438. { static const bool value = true; };
  439. struct hashtable_defaults
  440. {
  441. typedef default_hashtable_hook_applier proto_value_traits;
  442. typedef std::size_t size_type;
  443. typedef void key_of_value;
  444. typedef void equal;
  445. typedef void hash;
  446. typedef default_bucket_traits bucket_traits;
  447. static const bool constant_time_size = true;
  448. static const bool power_2_buckets = false;
  449. static const bool cache_begin = false;
  450. static const bool compare_hash = false;
  451. static const bool incremental = false;
  452. };
  453. template<class ValueTraits, bool IsConst>
  454. struct downcast_node_to_value_t
  455. : public detail::node_to_value<ValueTraits, IsConst>
  456. {
  457. typedef detail::node_to_value<ValueTraits, IsConst> base_t;
  458. typedef typename base_t::result_type result_type;
  459. typedef ValueTraits value_traits;
  460. typedef typename detail::get_slist_impl
  461. <typename detail::reduced_slist_node_traits
  462. <typename value_traits::node_traits>::type
  463. >::type slist_impl;
  464. typedef typename detail::add_const_if_c
  465. <typename slist_impl::node, IsConst>::type & first_argument_type;
  466. typedef typename detail::add_const_if_c
  467. < typename ValueTraits::node_traits::node
  468. , IsConst>::type & intermediate_argument_type;
  469. typedef typename pointer_traits
  470. <typename ValueTraits::pointer>::
  471. template rebind_pointer
  472. <const ValueTraits>::type const_value_traits_ptr;
  473. downcast_node_to_value_t(const const_value_traits_ptr &ptr)
  474. : base_t(ptr)
  475. {}
  476. result_type operator()(first_argument_type arg) const
  477. { return this->base_t::operator()(static_cast<intermediate_argument_type>(arg)); }
  478. };
  479. template<class F, class SlistNodePtr, class NodePtr>
  480. struct node_cast_adaptor
  481. //Use public inheritance to avoid MSVC bugs with closures
  482. : public detail::ebo_functor_holder<F>
  483. {
  484. typedef detail::ebo_functor_holder<F> base_t;
  485. typedef typename pointer_traits<SlistNodePtr>::element_type slist_node;
  486. typedef typename pointer_traits<NodePtr>::element_type node;
  487. template<class ConvertibleToF, class RealValuTraits>
  488. node_cast_adaptor(const ConvertibleToF &c2f, const RealValuTraits *traits)
  489. : base_t(base_t(c2f, traits))
  490. {}
  491. typename base_t::node_ptr operator()(const slist_node &to_clone)
  492. { return base_t::operator()(static_cast<const node &>(to_clone)); }
  493. void operator()(SlistNodePtr to_clone)
  494. {
  495. base_t::operator()(pointer_traits<NodePtr>::pointer_to(static_cast<node &>(*to_clone)));
  496. }
  497. };
  498. //bucket_plus_vtraits stores ValueTraits + BucketTraits
  499. //this data is needed by iterators to obtain the
  500. //value from the iterator and detect the bucket
  501. template<class ValueTraits, class BucketTraits>
  502. struct bucket_plus_vtraits
  503. {
  504. typedef BucketTraits bucket_traits;
  505. typedef ValueTraits value_traits;
  506. static const bool safemode_or_autounlink = is_safe_autounlink<value_traits::link_mode>::value;
  507. typedef typename
  508. detail::get_slist_impl_from_supposed_value_traits
  509. <value_traits>::type slist_impl;
  510. typedef typename value_traits::node_traits node_traits;
  511. typedef unordered_group_adapter<node_traits> group_traits;
  512. typedef typename slist_impl::iterator siterator;
  513. typedef typename slist_impl::size_type size_type;
  514. typedef detail::bucket_impl<slist_impl> bucket_type;
  515. typedef detail::group_functions<node_traits> group_functions_t;
  516. typedef typename slist_impl::node_algorithms node_algorithms;
  517. typedef typename slist_impl::node_ptr slist_node_ptr;
  518. typedef typename node_traits::node_ptr node_ptr;
  519. typedef typename node_traits::node node;
  520. typedef typename value_traits::value_type value_type;
  521. typedef typename value_traits::pointer pointer;
  522. typedef typename value_traits::const_pointer const_pointer;
  523. typedef typename pointer_traits<pointer>::reference reference;
  524. typedef typename pointer_traits
  525. <const_pointer>::reference const_reference;
  526. typedef circular_slist_algorithms<group_traits> group_algorithms;
  527. typedef typename pointer_traits
  528. <typename value_traits::pointer>::
  529. template rebind_pointer
  530. <const value_traits>::type const_value_traits_ptr;
  531. typedef typename pointer_traits
  532. <typename value_traits::pointer>::
  533. template rebind_pointer
  534. <const bucket_plus_vtraits>::type const_bucket_value_traits_ptr;
  535. typedef typename detail::unordered_bucket_ptr_impl
  536. <value_traits>::type bucket_ptr;
  537. template<class BucketTraitsType>
  538. bucket_plus_vtraits(const ValueTraits &val_traits, BOOST_FWD_REF(BucketTraitsType) b_traits)
  539. : data(val_traits, ::boost::forward<BucketTraitsType>(b_traits))
  540. {}
  541. bucket_plus_vtraits & operator =(const bucket_plus_vtraits &x)
  542. { data.bucket_traits_ = x.data.bucket_traits_; return *this; }
  543. const_value_traits_ptr priv_value_traits_ptr() const
  544. { return pointer_traits<const_value_traits_ptr>::pointer_to(this->priv_value_traits()); }
  545. //bucket_value_traits
  546. //
  547. const bucket_plus_vtraits &get_bucket_value_traits() const
  548. { return *this; }
  549. bucket_plus_vtraits &get_bucket_value_traits()
  550. { return *this; }
  551. const_bucket_value_traits_ptr bucket_value_traits_ptr() const
  552. { return pointer_traits<const_bucket_value_traits_ptr>::pointer_to(this->get_bucket_value_traits()); }
  553. //value traits
  554. //
  555. const value_traits &priv_value_traits() const
  556. { return this->data; }
  557. value_traits &priv_value_traits()
  558. { return this->data; }
  559. //bucket_traits
  560. //
  561. const bucket_traits &priv_bucket_traits() const
  562. { return this->data.bucket_traits_; }
  563. bucket_traits &priv_bucket_traits()
  564. { return this->data.bucket_traits_; }
  565. //bucket operations
  566. bucket_ptr priv_bucket_pointer() const
  567. { return this->priv_bucket_traits().bucket_begin(); }
  568. typename slist_impl::size_type priv_bucket_count() const
  569. { return this->priv_bucket_traits().bucket_count(); }
  570. bucket_ptr priv_invalid_bucket() const
  571. {
  572. const bucket_traits &rbt = this->priv_bucket_traits();
  573. return rbt.bucket_begin() + rbt.bucket_count();
  574. }
  575. siterator priv_invalid_local_it() const
  576. { return this->priv_bucket_traits().bucket_begin()->before_begin(); }
  577. template<class NodeDisposer>
  578. static size_type priv_erase_from_single_bucket(bucket_type &b, siterator sbefore_first, siterator slast, NodeDisposer node_disposer, detail::true_) //optimize multikey
  579. {
  580. size_type n = 0;
  581. siterator const sfirst(++siterator(sbefore_first));
  582. if(sfirst != slast){
  583. node_ptr const nf = detail::dcast_bucket_ptr<node>(sfirst.pointed_node());
  584. node_ptr const nl = detail::dcast_bucket_ptr<node>(slast.pointed_node());
  585. node_ptr const ne = detail::dcast_bucket_ptr<node>(b.end().pointed_node());
  586. if(group_functions_t::next_group_if_first_in_group(nf) != nf) {
  587. // The node is at the beginning of a group.
  588. if(nl != ne){
  589. group_functions_t::split_group(nl);
  590. }
  591. }
  592. else {
  593. node_ptr const group1 = group_functions_t::split_group(nf);
  594. if(nl != ne) {
  595. node_ptr const group2 = group_functions_t::split_group(ne);
  596. if(nf == group2) { //Both first and last in the same group
  597. //so join group1 and group2
  598. node_ptr const end1 = group_traits::get_next(group1);
  599. node_ptr const end2 = group_traits::get_next(group2);
  600. group_traits::set_next(group1, end2);
  601. group_traits::set_next(group2, end1);
  602. }
  603. }
  604. }
  605. siterator it(++siterator(sbefore_first));
  606. while(it != slast){
  607. node_disposer((it++).pointed_node());
  608. ++n;
  609. }
  610. b.erase_after(sbefore_first, slast);
  611. }
  612. return n;
  613. }
  614. template<class NodeDisposer>
  615. static size_type priv_erase_from_single_bucket(bucket_type &b, siterator sbefore_first, siterator slast, NodeDisposer node_disposer, detail::false_) //optimize multikey
  616. {
  617. size_type n = 0;
  618. siterator it(++siterator(sbefore_first));
  619. while(it != slast){
  620. node_disposer((it++).pointed_node());
  621. ++n;
  622. }
  623. b.erase_after(sbefore_first, slast);
  624. return n;
  625. }
  626. template<class NodeDisposer>
  627. static void priv_erase_node(bucket_type &b, siterator i, NodeDisposer node_disposer, detail::true_) //optimize multikey
  628. {
  629. node_ptr const ne(detail::dcast_bucket_ptr<node>(b.end().pointed_node()));
  630. node_ptr n(detail::dcast_bucket_ptr<node>(i.pointed_node()));
  631. node_ptr pos = node_traits::get_next(group_traits::get_next(n));
  632. node_ptr bn;
  633. node_ptr nn(node_traits::get_next(n));
  634. if(pos != n) {
  635. //Node is the first of the group
  636. bn = group_functions_t::get_prev_to_first_in_group(ne, n);
  637. //Unlink the rest of the group if it's not the last node of its group
  638. if(nn != ne && group_traits::get_next(nn) == n){
  639. group_algorithms::unlink_after(nn);
  640. }
  641. }
  642. else if(nn != ne && group_traits::get_next(nn) == n){
  643. //Node is not the end of the group
  644. bn = group_traits::get_next(n);
  645. group_algorithms::unlink_after(nn);
  646. }
  647. else{
  648. //Node is the end of the group
  649. bn = group_traits::get_next(n);
  650. node_ptr const x(group_algorithms::get_previous_node(n));
  651. group_algorithms::unlink_after(x);
  652. }
  653. b.erase_after_and_dispose(bucket_type::s_iterator_to(*bn), node_disposer);
  654. }
  655. template<class NodeDisposer>
  656. static void priv_erase_node(bucket_type &b, siterator i, NodeDisposer node_disposer, detail::false_) //optimize multikey
  657. { b.erase_after_and_dispose(b.previous(i), node_disposer); }
  658. template<class NodeDisposer, bool OptimizeMultikey>
  659. size_type priv_erase_node_range( siterator const &before_first_it, size_type const first_bucket
  660. , siterator const &last_it, size_type const last_bucket
  661. , NodeDisposer node_disposer, detail::bool_<OptimizeMultikey> optimize_multikey_tag)
  662. {
  663. size_type num_erased(0);
  664. siterator last_step_before_it;
  665. if(first_bucket != last_bucket){
  666. bucket_type *b = (&this->priv_bucket_pointer()[0]);
  667. num_erased += this->priv_erase_from_single_bucket
  668. (b[first_bucket], before_first_it, b[first_bucket].end(), node_disposer, optimize_multikey_tag);
  669. for(size_type i = 0, n = (last_bucket - first_bucket - 1); i != n; ++i){
  670. num_erased += this->priv_erase_whole_bucket(b[first_bucket+i+1], node_disposer);
  671. }
  672. last_step_before_it = b[last_bucket].before_begin();
  673. }
  674. else{
  675. last_step_before_it = before_first_it;
  676. }
  677. num_erased += this->priv_erase_from_single_bucket
  678. (this->priv_bucket_pointer()[last_bucket], last_step_before_it, last_it, node_disposer, optimize_multikey_tag);
  679. return num_erased;
  680. }
  681. static siterator priv_get_last(bucket_type &b, detail::true_) //optimize multikey
  682. {
  683. //First find the last node of p's group.
  684. //This requires checking the first node of the next group or
  685. //the bucket node.
  686. slist_node_ptr end_ptr(b.end().pointed_node());
  687. node_ptr possible_end(node_traits::get_next( detail::dcast_bucket_ptr<node>(end_ptr)));
  688. node_ptr last_node_group(possible_end);
  689. while(end_ptr != possible_end){
  690. last_node_group = group_traits::get_next(detail::dcast_bucket_ptr<node>(possible_end));
  691. possible_end = node_traits::get_next(last_node_group);
  692. }
  693. return bucket_type::s_iterator_to(*last_node_group);
  694. }
  695. template<class NodeDisposer>
  696. size_type priv_erase_whole_bucket(bucket_type &b, NodeDisposer node_disposer)
  697. {
  698. size_type num_erased = 0;
  699. siterator b_begin(b.before_begin());
  700. siterator nxt(b_begin);
  701. ++nxt;
  702. siterator const end_sit(b.end());
  703. while(nxt != end_sit){
  704. //No need to init group links as we'll delete all bucket nodes
  705. nxt = bucket_type::s_erase_after_and_dispose(b_begin, node_disposer);
  706. ++num_erased;
  707. }
  708. return num_erased;
  709. }
  710. static siterator priv_get_last(bucket_type &b, detail::false_) //NOT optimize multikey
  711. { return b.previous(b.end()); }
  712. static siterator priv_get_previous(bucket_type &b, siterator i, detail::true_) //optimize multikey
  713. {
  714. node_ptr const elem(detail::dcast_bucket_ptr<node>(i.pointed_node()));
  715. node_ptr const prev_in_group(group_traits::get_next(elem));
  716. bool const first_in_group = node_traits::get_next(prev_in_group) != elem;
  717. typename bucket_type::node &n = first_in_group
  718. ? *group_functions_t::get_prev_to_first_in_group(b.end().pointed_node(), elem)
  719. : *group_traits::get_next(elem)
  720. ;
  721. return bucket_type::s_iterator_to(n);
  722. }
  723. static siterator priv_get_previous(bucket_type &b, siterator i, detail::false_) //NOT optimize multikey
  724. { return b.previous(i); }
  725. std::size_t priv_get_bucket_num_no_hash_store(siterator it, detail::true_) //optimize multikey
  726. {
  727. const bucket_ptr f(this->priv_bucket_pointer()), l(f + this->priv_bucket_count() - 1);
  728. slist_node_ptr bb = group_functions_t::get_bucket_before_begin
  729. ( f->end().pointed_node()
  730. , l->end().pointed_node()
  731. , detail::dcast_bucket_ptr<node>(it.pointed_node()));
  732. //Now get the bucket_impl from the iterator
  733. const bucket_type &b = static_cast<const bucket_type&>
  734. (bucket_type::slist_type::container_from_end_iterator(bucket_type::s_iterator_to(*bb)));
  735. //Now just calculate the index b has in the bucket array
  736. return static_cast<size_type>(&b - &*f);
  737. }
  738. std::size_t priv_get_bucket_num_no_hash_store(siterator it, detail::false_) //NO optimize multikey
  739. {
  740. bucket_ptr f(this->priv_bucket_pointer()), l(f + this->priv_bucket_count() - 1);
  741. slist_node_ptr first_ptr(f->cend().pointed_node())
  742. , last_ptr(l->cend().pointed_node());
  743. //The end node is embedded in the singly linked list:
  744. //iterate until we reach it.
  745. while(!(first_ptr <= it.pointed_node() && it.pointed_node() <= last_ptr)){
  746. ++it;
  747. }
  748. //Now get the bucket_impl from the iterator
  749. const bucket_type &b = static_cast<const bucket_type&>
  750. (bucket_type::container_from_end_iterator(it));
  751. //Now just calculate the index b has in the bucket array
  752. return static_cast<std::size_t>(&b - &*f);
  753. }
  754. static std::size_t priv_stored_hash(slist_node_ptr n, detail::true_) //store_hash
  755. { return node_traits::get_hash(detail::dcast_bucket_ptr<node>(n)); }
  756. static std::size_t priv_stored_hash(slist_node_ptr, detail::false_) //NO store_hash
  757. { return std::size_t(-1); }
  758. node &priv_value_to_node(reference v)
  759. { return *this->priv_value_traits().to_node_ptr(v); }
  760. const node &priv_value_to_node(const_reference v) const
  761. { return *this->priv_value_traits().to_node_ptr(v); }
  762. reference priv_value_from_slist_node(slist_node_ptr n)
  763. { return *this->priv_value_traits().to_value_ptr(detail::dcast_bucket_ptr<node>(n)); }
  764. const_reference priv_value_from_slist_node(slist_node_ptr n) const
  765. { return *this->priv_value_traits().to_value_ptr(detail::dcast_bucket_ptr<node>(n)); }
  766. void priv_clear_buckets(const bucket_ptr buckets_ptr, const size_type bucket_cnt)
  767. {
  768. bucket_ptr buckets_it = buckets_ptr;
  769. for(size_type bucket_i = 0; bucket_i != bucket_cnt; ++buckets_it, ++bucket_i){
  770. if(safemode_or_autounlink){
  771. buckets_it->clear_and_dispose(detail::init_disposer<node_algorithms>());
  772. }
  773. else{
  774. buckets_it->clear();
  775. }
  776. }
  777. }
  778. std::size_t priv_stored_or_compute_hash(const value_type &v, detail::true_) const //For store_hash == true
  779. { return node_traits::get_hash(this->priv_value_traits().to_node_ptr(v)); }
  780. typedef hashtable_iterator<bucket_plus_vtraits, false> iterator;
  781. typedef hashtable_iterator<bucket_plus_vtraits, true> const_iterator;
  782. iterator end()
  783. { return iterator(this->priv_invalid_local_it(), 0); }
  784. const_iterator end() const
  785. { return this->cend(); }
  786. const_iterator cend() const
  787. { return const_iterator(this->priv_invalid_local_it(), 0); }
  788. static size_type suggested_upper_bucket_count(size_type n)
  789. {
  790. const std::size_t *primes = &prime_list_holder<0>::prime_list[0];
  791. const std::size_t *primes_end = primes + prime_list_holder<0>::prime_list_size;
  792. std::size_t const* bound = std::lower_bound(primes, primes_end, n);
  793. bound -= (bound == primes_end);
  794. return size_type(*bound);
  795. }
  796. static size_type suggested_lower_bucket_count(size_type n)
  797. {
  798. const std::size_t *primes = &prime_list_holder<0>::prime_list[0];
  799. const std::size_t *primes_end = primes + prime_list_holder<0>::prime_list_size;
  800. size_type const* bound = std::upper_bound(primes, primes_end, n);
  801. bound -= (bound != primes);
  802. return size_type(*bound);
  803. }
  804. //Public functions:
  805. struct data_type : public ValueTraits
  806. {
  807. template<class BucketTraitsType>
  808. data_type(const ValueTraits &val_traits, BOOST_FWD_REF(BucketTraitsType) b_traits)
  809. : ValueTraits(val_traits), bucket_traits_(::boost::forward<BucketTraitsType>(b_traits))
  810. {}
  811. bucket_traits bucket_traits_;
  812. } data;
  813. };
  814. template<class Hash, class>
  815. struct get_hash
  816. {
  817. typedef Hash type;
  818. };
  819. template<class T>
  820. struct get_hash<void, T>
  821. {
  822. typedef ::boost::hash<T> type;
  823. };
  824. template<class EqualTo, class>
  825. struct get_equal_to
  826. {
  827. typedef EqualTo type;
  828. };
  829. template<class T>
  830. struct get_equal_to<void, T>
  831. {
  832. typedef std::equal_to<T> type;
  833. };
  834. template<class KeyOfValue, class T>
  835. struct get_hash_key_of_value
  836. {
  837. typedef KeyOfValue type;
  838. };
  839. template<class T>
  840. struct get_hash_key_of_value<void, T>
  841. {
  842. typedef ::boost::intrusive::detail::identity<T> type;
  843. };
  844. template<class T, class VoidOrKeyOfValue>
  845. struct hash_key_types_base
  846. {
  847. typedef typename get_hash_key_of_value
  848. < VoidOrKeyOfValue, T>::type key_of_value;
  849. typedef typename key_of_value::type key_type;
  850. };
  851. template<class T, class VoidOrKeyOfValue, class VoidOrKeyHash>
  852. struct hash_key_hash
  853. : get_hash
  854. < VoidOrKeyHash
  855. , typename hash_key_types_base<T, VoidOrKeyOfValue>::key_type
  856. >
  857. {};
  858. template<class T, class VoidOrKeyOfValue, class VoidOrKeyEqual>
  859. struct hash_key_equal
  860. : get_equal_to
  861. < VoidOrKeyEqual
  862. , typename hash_key_types_base<T, VoidOrKeyOfValue>::key_type
  863. >
  864. {};
  865. //bucket_hash_t
  866. //Stores bucket_plus_vtraits plust the hash function
  867. template<class ValueTraits, class VoidOrKeyOfValue, class VoidOrKeyHash, class BucketTraits>
  868. struct bucket_hash_t
  869. //Use public inheritance to avoid MSVC bugs with closures
  870. : public detail::ebo_functor_holder
  871. <typename hash_key_hash < typename bucket_plus_vtraits<ValueTraits,BucketTraits>::value_traits::value_type
  872. , VoidOrKeyOfValue
  873. , VoidOrKeyHash
  874. >::type
  875. >
  876. , bucket_plus_vtraits<ValueTraits, BucketTraits> //4
  877. {
  878. typedef typename bucket_plus_vtraits<ValueTraits,BucketTraits>::value_traits value_traits;
  879. typedef typename value_traits::value_type value_type;
  880. typedef typename value_traits::node_traits node_traits;
  881. typedef hash_key_hash
  882. < value_type, VoidOrKeyOfValue, VoidOrKeyHash> hash_key_hash_t;
  883. typedef typename hash_key_hash_t::type hasher;
  884. typedef typename hash_key_types_base<value_type, VoidOrKeyOfValue>::key_of_value key_of_value;
  885. typedef BucketTraits bucket_traits;
  886. typedef bucket_plus_vtraits<ValueTraits, BucketTraits> bucket_plus_vtraits_t;
  887. typedef detail::ebo_functor_holder<hasher> base_t;
  888. template<class BucketTraitsType>
  889. bucket_hash_t(const ValueTraits &val_traits, BOOST_FWD_REF(BucketTraitsType) b_traits, const hasher & h)
  890. : detail::ebo_functor_holder<hasher>(h), bucket_plus_vtraits_t(val_traits, ::boost::forward<BucketTraitsType>(b_traits))
  891. {}
  892. const hasher &priv_hasher() const
  893. { return this->base_t::get(); }
  894. hasher &priv_hasher()
  895. { return this->base_t::get(); }
  896. using bucket_plus_vtraits_t::priv_stored_or_compute_hash; //For store_hash == true
  897. std::size_t priv_stored_or_compute_hash(const value_type &v, detail::false_) const //For store_hash == false
  898. { return this->priv_hasher()(key_of_value()(v)); }
  899. };
  900. template<class ValueTraits, class BucketTraits, class VoidOrKeyOfValue, class VoidOrKeyEqual>
  901. struct hashtable_equal_holder
  902. {
  903. typedef detail::ebo_functor_holder
  904. < typename hash_key_equal < typename bucket_plus_vtraits<ValueTraits, BucketTraits>::value_traits::value_type
  905. , VoidOrKeyOfValue
  906. , VoidOrKeyEqual
  907. >::type
  908. > type;
  909. };
  910. //bucket_hash_equal_t
  911. //Stores bucket_hash_t and the equality function when the first
  912. //non-empty bucket shall not be cached.
  913. template<class ValueTraits, class VoidOrKeyOfValue, class VoidOrKeyHash, class VoidOrKeyEqual, class BucketTraits, bool>
  914. struct bucket_hash_equal_t
  915. //Use public inheritance to avoid MSVC bugs with closures
  916. : public bucket_hash_t<ValueTraits, VoidOrKeyOfValue, VoidOrKeyHash, BucketTraits> //3
  917. , public hashtable_equal_holder<ValueTraits, BucketTraits, VoidOrKeyOfValue, VoidOrKeyEqual>::type //equal
  918. {
  919. typedef typename hashtable_equal_holder
  920. <ValueTraits, BucketTraits, VoidOrKeyOfValue, VoidOrKeyEqual>::type equal_holder_t;
  921. typedef bucket_hash_t<ValueTraits, VoidOrKeyOfValue, VoidOrKeyHash, BucketTraits> bucket_hash_type;
  922. typedef bucket_plus_vtraits<ValueTraits,BucketTraits> bucket_plus_vtraits_t;
  923. typedef ValueTraits value_traits;
  924. typedef typename equal_holder_t::functor_type key_equal;
  925. typedef typename bucket_hash_type::hasher hasher;
  926. typedef BucketTraits bucket_traits;
  927. typedef typename bucket_plus_vtraits_t::slist_impl slist_impl;
  928. typedef typename slist_impl::size_type size_type;
  929. typedef typename slist_impl::iterator siterator;
  930. typedef detail::bucket_impl<slist_impl> bucket_type;
  931. typedef typename detail::unordered_bucket_ptr_impl<value_traits>::type bucket_ptr;
  932. template<class BucketTraitsType>
  933. bucket_hash_equal_t(const ValueTraits &val_traits, BOOST_FWD_REF(BucketTraitsType) b_traits, const hasher & h, const key_equal &e)
  934. : bucket_hash_type(val_traits, ::boost::forward<BucketTraitsType>(b_traits), h)
  935. , equal_holder_t(e)
  936. {}
  937. bucket_ptr priv_get_cache()
  938. { return this->bucket_hash_type::priv_bucket_pointer(); }
  939. void priv_set_cache(const bucket_ptr &)
  940. {}
  941. size_type priv_get_cache_bucket_num()
  942. { return 0u; }
  943. void priv_initialize_cache()
  944. {}
  945. void priv_swap_cache(bucket_hash_equal_t &)
  946. {}
  947. siterator priv_begin() const
  948. {
  949. size_type n = 0;
  950. size_type bucket_cnt = this->bucket_hash_type::priv_bucket_count();
  951. for (n = 0; n < bucket_cnt; ++n){
  952. bucket_type &b = this->bucket_hash_type::priv_bucket_pointer()[n];
  953. if(!b.empty()){
  954. return b.begin();
  955. }
  956. }
  957. return this->bucket_hash_type::priv_invalid_local_it();
  958. }
  959. void priv_insertion_update_cache(size_type)
  960. {}
  961. void priv_erasure_update_cache_range(size_type, size_type)
  962. {}
  963. void priv_erasure_update_cache()
  964. {}
  965. const key_equal &priv_equal() const
  966. { return this->equal_holder_t::get(); }
  967. key_equal &priv_equal()
  968. { return this->equal_holder_t::get(); }
  969. };
  970. //bucket_hash_equal_t
  971. //Stores bucket_hash_t and the equality function when the first
  972. //non-empty bucket shall be cached.
  973. template<class ValueTraits, class VoidOrKeyOfValue, class VoidOrKeyHash, class VoidOrKeyEqual, class BucketTraits> //cache_begin == true version
  974. struct bucket_hash_equal_t<ValueTraits, VoidOrKeyOfValue, VoidOrKeyHash, VoidOrKeyEqual, BucketTraits, true>
  975. //Use public inheritance to avoid MSVC bugs with closures
  976. : bucket_hash_t<ValueTraits, VoidOrKeyOfValue, VoidOrKeyHash, BucketTraits> //2
  977. , hashtable_equal_holder<ValueTraits, BucketTraits, VoidOrKeyOfValue, VoidOrKeyEqual>::type
  978. {
  979. typedef typename hashtable_equal_holder
  980. <ValueTraits, BucketTraits, VoidOrKeyOfValue, VoidOrKeyEqual>::type equal_holder_t;
  981. typedef bucket_plus_vtraits<ValueTraits,BucketTraits> bucket_plus_vtraits_t;
  982. typedef ValueTraits value_traits;
  983. typedef typename equal_holder_t::functor_type key_equal;
  984. typedef bucket_hash_t<ValueTraits, VoidOrKeyOfValue, VoidOrKeyHash, BucketTraits> bucket_hash_type;
  985. typedef typename bucket_hash_type::hasher hasher;
  986. typedef BucketTraits bucket_traits;
  987. typedef typename bucket_plus_vtraits_t::slist_impl::size_type size_type;
  988. typedef typename bucket_plus_vtraits_t::slist_impl::iterator siterator;
  989. template<class BucketTraitsType>
  990. bucket_hash_equal_t(const ValueTraits &val_traits, BOOST_FWD_REF(BucketTraitsType) b_traits, const hasher & h, const key_equal &e)
  991. : bucket_hash_type(val_traits, ::boost::forward<BucketTraitsType>(b_traits), h)
  992. , equal_holder_t(e)
  993. {}
  994. typedef typename detail::unordered_bucket_ptr_impl
  995. <typename bucket_hash_type::value_traits>::type bucket_ptr;
  996. bucket_ptr &priv_get_cache()
  997. { return cached_begin_; }
  998. const bucket_ptr &priv_get_cache() const
  999. { return cached_begin_; }
  1000. void priv_set_cache(const bucket_ptr &p)
  1001. { cached_begin_ = p; }
  1002. std::size_t priv_get_cache_bucket_num()
  1003. { return this->cached_begin_ - this->bucket_hash_type::priv_bucket_pointer(); }
  1004. void priv_initialize_cache()
  1005. { this->cached_begin_ = this->bucket_hash_type::priv_invalid_bucket(); }
  1006. void priv_swap_cache(bucket_hash_equal_t &other)
  1007. {
  1008. ::boost::adl_move_swap(this->cached_begin_, other.cached_begin_);
  1009. }
  1010. siterator priv_begin() const
  1011. {
  1012. if(this->cached_begin_ == this->bucket_hash_type::priv_invalid_bucket()){
  1013. return this->bucket_hash_type::priv_invalid_local_it();
  1014. }
  1015. else{
  1016. return this->cached_begin_->begin();
  1017. }
  1018. }
  1019. void priv_insertion_update_cache(size_type insertion_bucket)
  1020. {
  1021. bucket_ptr p = this->bucket_hash_type::priv_bucket_pointer() + insertion_bucket;
  1022. if(p < this->cached_begin_){
  1023. this->cached_begin_ = p;
  1024. }
  1025. }
  1026. const key_equal &priv_equal() const
  1027. { return this->equal_holder_t::get(); }
  1028. key_equal &priv_equal()
  1029. { return this->equal_holder_t::get(); }
  1030. void priv_erasure_update_cache_range(size_type first_bucket_num, size_type last_bucket_num)
  1031. {
  1032. //If the last bucket is the end, the cache must be updated
  1033. //to the last position if all
  1034. if(this->priv_get_cache_bucket_num() == first_bucket_num &&
  1035. this->bucket_hash_type::priv_bucket_pointer()[first_bucket_num].empty() ){
  1036. this->priv_set_cache(this->bucket_hash_type::priv_bucket_pointer() + last_bucket_num);
  1037. this->priv_erasure_update_cache();
  1038. }
  1039. }
  1040. void priv_erasure_update_cache()
  1041. {
  1042. if(this->cached_begin_ != this->bucket_hash_type::priv_invalid_bucket()){
  1043. size_type current_n = this->priv_get_cache() - this->bucket_hash_type::priv_bucket_pointer();
  1044. for( const size_type num_buckets = this->bucket_hash_type::priv_bucket_count()
  1045. ; current_n < num_buckets
  1046. ; ++current_n, ++this->priv_get_cache()){
  1047. if(!this->priv_get_cache()->empty()){
  1048. return;
  1049. }
  1050. }
  1051. this->priv_initialize_cache();
  1052. }
  1053. }
  1054. bucket_ptr cached_begin_;
  1055. };
  1056. //This wrapper around size_traits is used
  1057. //to maintain minimal container size with compilers like MSVC
  1058. //that have problems with EBO and multiple empty base classes
  1059. template<class DeriveFrom, class SizeType, bool>
  1060. struct hashtable_size_traits_wrapper
  1061. : public DeriveFrom
  1062. {
  1063. template<class Base, class Arg0, class Arg1, class Arg2>
  1064. hashtable_size_traits_wrapper( BOOST_FWD_REF(Base) base, BOOST_FWD_REF(Arg0) arg0
  1065. , BOOST_FWD_REF(Arg1) arg1, BOOST_FWD_REF(Arg2) arg2)
  1066. : DeriveFrom(::boost::forward<Base>(base)
  1067. , ::boost::forward<Arg0>(arg0)
  1068. , ::boost::forward<Arg1>(arg1)
  1069. , ::boost::forward<Arg2>(arg2))
  1070. {}
  1071. typedef detail::size_holder < true, SizeType> size_traits;//size_traits
  1072. size_traits size_traits_;
  1073. const size_traits &priv_size_traits() const
  1074. { return size_traits_; }
  1075. size_traits &priv_size_traits()
  1076. { return size_traits_; }
  1077. };
  1078. template<class DeriveFrom, class SizeType>
  1079. struct hashtable_size_traits_wrapper<DeriveFrom, SizeType, false>
  1080. : public DeriveFrom
  1081. {
  1082. template<class Base, class Arg0, class Arg1, class Arg2>
  1083. hashtable_size_traits_wrapper( BOOST_FWD_REF(Base) base, BOOST_FWD_REF(Arg0) arg0
  1084. , BOOST_FWD_REF(Arg1) arg1, BOOST_FWD_REF(Arg2) arg2)
  1085. : DeriveFrom(::boost::forward<Base>(base)
  1086. , ::boost::forward<Arg0>(arg0)
  1087. , ::boost::forward<Arg1>(arg1)
  1088. , ::boost::forward<Arg2>(arg2))
  1089. {}
  1090. typedef detail::size_holder< false, SizeType> size_traits;
  1091. const size_traits &priv_size_traits() const
  1092. { return size_traits_; }
  1093. size_traits &priv_size_traits()
  1094. { return size_traits_; }
  1095. static size_traits size_traits_;
  1096. };
  1097. template<class DeriveFrom, class SizeType>
  1098. detail::size_holder< false, SizeType > hashtable_size_traits_wrapper<DeriveFrom, SizeType, false>::size_traits_;
  1099. //hashdata_internal
  1100. //Stores bucket_hash_equal_t and split_traits
  1101. template<class ValueTraits, class VoidOrKeyOfValue, class VoidOrKeyHash, class VoidOrKeyEqual, class BucketTraits, class SizeType, std::size_t BoolFlags>
  1102. struct hashdata_internal
  1103. : public hashtable_size_traits_wrapper
  1104. < bucket_hash_equal_t
  1105. < ValueTraits, VoidOrKeyOfValue, VoidOrKeyHash, VoidOrKeyEqual
  1106. , BucketTraits
  1107. , 0 != (BoolFlags & hash_bool_flags::cache_begin_pos)
  1108. > //2
  1109. , SizeType
  1110. , (BoolFlags & hash_bool_flags::incremental_pos) != 0
  1111. >
  1112. {
  1113. typedef hashtable_size_traits_wrapper
  1114. < bucket_hash_equal_t
  1115. < ValueTraits, VoidOrKeyOfValue, VoidOrKeyHash, VoidOrKeyEqual
  1116. , BucketTraits
  1117. , 0 != (BoolFlags & hash_bool_flags::cache_begin_pos)
  1118. > //2
  1119. , SizeType
  1120. , (BoolFlags & hash_bool_flags::incremental_pos) != 0
  1121. > internal_type;
  1122. typedef typename internal_type::key_equal key_equal;
  1123. typedef typename internal_type::hasher hasher;
  1124. typedef bucket_plus_vtraits<ValueTraits,BucketTraits> bucket_plus_vtraits_t;
  1125. typedef typename bucket_plus_vtraits_t::size_type size_type;
  1126. typedef typename internal_type::size_traits split_traits;
  1127. typedef typename bucket_plus_vtraits_t::bucket_ptr bucket_ptr;
  1128. typedef typename bucket_plus_vtraits_t::const_value_traits_ptr const_value_traits_ptr;
  1129. typedef typename bucket_plus_vtraits_t::siterator siterator;
  1130. typedef typename bucket_plus_vtraits_t::bucket_traits bucket_traits;
  1131. typedef typename bucket_plus_vtraits_t::value_traits value_traits;
  1132. typedef typename bucket_plus_vtraits_t::bucket_type bucket_type;
  1133. typedef typename value_traits::value_type value_type;
  1134. typedef typename value_traits::pointer pointer;
  1135. typedef typename value_traits::const_pointer const_pointer;
  1136. typedef typename pointer_traits<pointer>::reference reference;
  1137. typedef typename pointer_traits
  1138. <const_pointer>::reference const_reference;
  1139. typedef typename value_traits::node_traits node_traits;
  1140. typedef typename node_traits::node node;
  1141. typedef typename node_traits::node_ptr node_ptr;
  1142. typedef typename node_traits::const_node_ptr const_node_ptr;
  1143. typedef detail::node_functions<node_traits> node_functions_t;
  1144. typedef typename detail::get_slist_impl
  1145. <typename detail::reduced_slist_node_traits
  1146. <typename value_traits::node_traits>::type
  1147. >::type slist_impl;
  1148. typedef typename slist_impl::node_algorithms node_algorithms;
  1149. typedef typename slist_impl::node_ptr slist_node_ptr;
  1150. typedef hash_key_types_base
  1151. < typename ValueTraits::value_type
  1152. , VoidOrKeyOfValue
  1153. > hash_types_base;
  1154. typedef typename hash_types_base::key_of_value key_of_value;
  1155. static const bool store_hash = detail::store_hash_is_true<node_traits>::value;
  1156. static const bool safemode_or_autounlink = is_safe_autounlink<value_traits::link_mode>::value;
  1157. static const bool stateful_value_traits = detail::is_stateful_value_traits<value_traits>::value;
  1158. typedef detail::bool_<store_hash> store_hash_t;
  1159. typedef detail::transform_iterator
  1160. < typename slist_impl::iterator
  1161. , downcast_node_to_value_t
  1162. < value_traits
  1163. , false> > local_iterator;
  1164. typedef detail::transform_iterator
  1165. < typename slist_impl::iterator
  1166. , downcast_node_to_value_t
  1167. < value_traits
  1168. , true> > const_local_iterator;
  1169. //
  1170. template<class BucketTraitsType>
  1171. hashdata_internal( const ValueTraits &val_traits, BOOST_FWD_REF(BucketTraitsType) b_traits
  1172. , const hasher & h, const key_equal &e)
  1173. : internal_type(val_traits, ::boost::forward<BucketTraitsType>(b_traits), h, e)
  1174. {}
  1175. split_traits &priv_split_traits()
  1176. { return this->priv_size_traits(); }
  1177. const split_traits &priv_split_traits() const
  1178. { return this->priv_size_traits(); }
  1179. ~hashdata_internal()
  1180. { this->priv_clear_buckets(); }
  1181. void priv_clear_buckets()
  1182. {
  1183. this->internal_type::priv_clear_buckets
  1184. ( this->priv_get_cache()
  1185. , this->internal_type::priv_bucket_count()
  1186. - (this->priv_get_cache()
  1187. - this->internal_type::priv_bucket_pointer()));
  1188. }
  1189. void priv_clear_buckets_and_cache()
  1190. {
  1191. this->priv_clear_buckets();
  1192. this->priv_initialize_cache();
  1193. }
  1194. void priv_initialize_buckets_and_cache()
  1195. {
  1196. this->internal_type::priv_clear_buckets
  1197. ( this->internal_type::priv_bucket_pointer()
  1198. , this->internal_type::priv_bucket_count());
  1199. this->priv_initialize_cache();
  1200. }
  1201. typedef hashtable_iterator<bucket_plus_vtraits_t, false> iterator;
  1202. typedef hashtable_iterator<bucket_plus_vtraits_t, true> const_iterator;
  1203. static std::size_t priv_stored_hash(slist_node_ptr n, detail::true_ true_value)
  1204. { return bucket_plus_vtraits<ValueTraits, BucketTraits>::priv_stored_hash(n, true_value); }
  1205. static std::size_t priv_stored_hash(slist_node_ptr n, detail::false_ false_value)
  1206. { return bucket_plus_vtraits<ValueTraits, BucketTraits>::priv_stored_hash(n, false_value); }
  1207. //public functions
  1208. SizeType split_count() const
  1209. {
  1210. return this->priv_split_traits().get_size();
  1211. }
  1212. iterator iterator_to(reference value)
  1213. {
  1214. return iterator(bucket_type::s_iterator_to
  1215. (this->priv_value_to_node(value)), &this->get_bucket_value_traits());
  1216. }
  1217. const_iterator iterator_to(const_reference value) const
  1218. {
  1219. siterator const sit = bucket_type::s_iterator_to
  1220. ( *pointer_traits<node_ptr>::const_cast_from
  1221. (pointer_traits<const_node_ptr>::pointer_to(this->priv_value_to_node(value)))
  1222. );
  1223. return const_iterator(sit, &this->get_bucket_value_traits());
  1224. }
  1225. static local_iterator s_local_iterator_to(reference value)
  1226. {
  1227. BOOST_STATIC_ASSERT((!stateful_value_traits));
  1228. siterator sit = bucket_type::s_iterator_to(*value_traits::to_node_ptr(value));
  1229. return local_iterator(sit, const_value_traits_ptr());
  1230. }
  1231. static const_local_iterator s_local_iterator_to(const_reference value)
  1232. {
  1233. BOOST_STATIC_ASSERT((!stateful_value_traits));
  1234. siterator const sit = bucket_type::s_iterator_to
  1235. ( *pointer_traits<node_ptr>::const_cast_from
  1236. (value_traits::to_node_ptr(value))
  1237. );
  1238. return const_local_iterator(sit, const_value_traits_ptr());
  1239. }
  1240. local_iterator local_iterator_to(reference value)
  1241. {
  1242. siterator sit = bucket_type::s_iterator_to(this->priv_value_to_node(value));
  1243. return local_iterator(sit, this->priv_value_traits_ptr());
  1244. }
  1245. const_local_iterator local_iterator_to(const_reference value) const
  1246. {
  1247. siterator sit = bucket_type::s_iterator_to
  1248. ( *pointer_traits<node_ptr>::const_cast_from
  1249. (pointer_traits<const_node_ptr>::pointer_to(this->priv_value_to_node(value)))
  1250. );
  1251. return const_local_iterator(sit, this->priv_value_traits_ptr());
  1252. }
  1253. size_type bucket_count() const
  1254. { return this->priv_bucket_count(); }
  1255. size_type bucket_size(size_type n) const
  1256. { return this->priv_bucket_pointer()[n].size(); }
  1257. bucket_ptr bucket_pointer() const
  1258. { return this->priv_bucket_pointer(); }
  1259. local_iterator begin(size_type n)
  1260. { return local_iterator(this->priv_bucket_pointer()[n].begin(), this->priv_value_traits_ptr()); }
  1261. const_local_iterator begin(size_type n) const
  1262. { return this->cbegin(n); }
  1263. const_local_iterator cbegin(size_type n) const
  1264. {
  1265. return const_local_iterator
  1266. ( pointer_traits<bucket_ptr>::const_cast_from(this->priv_bucket_pointer())[n].begin()
  1267. , this->priv_value_traits_ptr());
  1268. }
  1269. using internal_type::end;
  1270. using internal_type::cend;
  1271. local_iterator end(size_type n)
  1272. { return local_iterator(this->priv_bucket_pointer()[n].end(), this->priv_value_traits_ptr()); }
  1273. const_local_iterator end(size_type n) const
  1274. { return this->cend(n); }
  1275. const_local_iterator cend(size_type n) const
  1276. {
  1277. return const_local_iterator
  1278. ( pointer_traits<bucket_ptr>::const_cast_from(this->priv_bucket_pointer())[n].end()
  1279. , this->priv_value_traits_ptr());
  1280. }
  1281. //Public functions for hashtable_impl
  1282. iterator begin()
  1283. { return iterator(this->priv_begin(), &this->get_bucket_value_traits()); }
  1284. const_iterator begin() const
  1285. { return this->cbegin(); }
  1286. const_iterator cbegin() const
  1287. { return const_iterator(this->priv_begin(), &this->get_bucket_value_traits()); }
  1288. hasher hash_function() const
  1289. { return this->priv_hasher(); }
  1290. key_equal key_eq() const
  1291. { return this->priv_equal(); }
  1292. };
  1293. /// @endcond
  1294. //! The class template hashtable is an intrusive hash table container, that
  1295. //! is used to construct intrusive unordered_set and unordered_multiset containers. The
  1296. //! no-throw guarantee holds only, if the VoidOrKeyEqual object and Hasher don't throw.
  1297. //!
  1298. //! hashtable is a semi-intrusive container: each object to be stored in the
  1299. //! container must contain a proper hook, but the container also needs
  1300. //! additional auxiliary memory to work: hashtable needs a pointer to an array
  1301. //! of type `bucket_type` to be passed in the constructor. This bucket array must
  1302. //! have at least the same lifetime as the container. This makes the use of
  1303. //! hashtable more complicated than purely intrusive containers.
  1304. //! `bucket_type` is default-constructible, copyable and assignable
  1305. //!
  1306. //! The template parameter \c T is the type to be managed by the container.
  1307. //! The user can specify additional options and if no options are provided
  1308. //! default options are used.
  1309. //!
  1310. //! The container supports the following options:
  1311. //! \c base_hook<>/member_hook<>/value_traits<>,
  1312. //! \c constant_time_size<>, \c size_type<>, \c hash<> and \c equal<>
  1313. //! \c bucket_traits<>, power_2_buckets<>, cache_begin<> and incremental<>.
  1314. //!
  1315. //! hashtable only provides forward iterators but it provides 4 iterator types:
  1316. //! iterator and const_iterator to navigate through the whole container and
  1317. //! local_iterator and const_local_iterator to navigate through the values
  1318. //! stored in a single bucket. Local iterators are faster and smaller.
  1319. //!
  1320. //! It's not recommended to use non constant-time size hashtables because several
  1321. //! key functions, like "empty()", become non-constant time functions. Non
  1322. //! constant_time size hashtables are mainly provided to support auto-unlink hooks.
  1323. //!
  1324. //! hashtables, does not make automatic rehashings nor
  1325. //! offers functions related to a load factor. Rehashing can be explicitly requested
  1326. //! and the user must provide a new bucket array that will be used from that moment.
  1327. //!
  1328. //! Since no automatic rehashing is done, iterators are never invalidated when
  1329. //! inserting or erasing elements. Iterators are only invalidated when rehashing.
  1330. #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
  1331. template<class T, class ...Options>
  1332. #else
  1333. template<class ValueTraits, class VoidOrKeyOfValue, class VoidOrKeyHash, class VoidOrKeyEqual, class BucketTraits, class SizeType, std::size_t BoolFlags>
  1334. #endif
  1335. class hashtable_impl
  1336. : private hashtable_size_traits_wrapper
  1337. < hashdata_internal
  1338. < ValueTraits
  1339. , VoidOrKeyOfValue, VoidOrKeyHash, VoidOrKeyEqual
  1340. , BucketTraits, SizeType
  1341. , BoolFlags & (hash_bool_flags::incremental_pos | hash_bool_flags::cache_begin_pos) //1
  1342. >
  1343. , SizeType
  1344. , (BoolFlags & hash_bool_flags::constant_time_size_pos) != 0
  1345. >
  1346. {
  1347. typedef hashtable_size_traits_wrapper
  1348. < hashdata_internal
  1349. < ValueTraits
  1350. , VoidOrKeyOfValue, VoidOrKeyHash, VoidOrKeyEqual
  1351. , BucketTraits, SizeType
  1352. , BoolFlags & (hash_bool_flags::incremental_pos | hash_bool_flags::cache_begin_pos) //1
  1353. >
  1354. , SizeType
  1355. , (BoolFlags & hash_bool_flags::constant_time_size_pos) != 0
  1356. > internal_type;
  1357. typedef typename internal_type::size_traits size_traits;
  1358. typedef hash_key_types_base
  1359. < typename ValueTraits::value_type
  1360. , VoidOrKeyOfValue
  1361. > hash_types_base;
  1362. public:
  1363. typedef ValueTraits value_traits;
  1364. /// @cond
  1365. typedef BucketTraits bucket_traits;
  1366. typedef typename internal_type::slist_impl slist_impl;
  1367. typedef bucket_plus_vtraits<ValueTraits, BucketTraits> bucket_plus_vtraits_t;
  1368. typedef typename bucket_plus_vtraits_t::const_value_traits_ptr const_value_traits_ptr;
  1369. using internal_type::begin;
  1370. using internal_type::cbegin;
  1371. using internal_type::end;
  1372. using internal_type::cend;
  1373. using internal_type::hash_function;
  1374. using internal_type::key_eq;
  1375. using internal_type::bucket_size;
  1376. using internal_type::bucket_count;
  1377. using internal_type::local_iterator_to;
  1378. using internal_type::s_local_iterator_to;
  1379. using internal_type::iterator_to;
  1380. using internal_type::bucket_pointer;
  1381. using internal_type::suggested_upper_bucket_count;
  1382. using internal_type::suggested_lower_bucket_count;
  1383. using internal_type::split_count;
  1384. /// @endcond
  1385. typedef typename value_traits::pointer pointer;
  1386. typedef typename value_traits::const_pointer const_pointer;
  1387. typedef typename value_traits::value_type value_type;
  1388. typedef typename hash_types_base::key_type key_type;
  1389. typedef typename hash_types_base::key_of_value key_of_value;
  1390. typedef typename pointer_traits<pointer>::reference reference;
  1391. typedef typename pointer_traits<const_pointer>::reference const_reference;
  1392. typedef typename pointer_traits<pointer>::difference_type difference_type;
  1393. typedef SizeType size_type;
  1394. typedef typename internal_type::key_equal key_equal;
  1395. typedef typename internal_type::hasher hasher;
  1396. typedef detail::bucket_impl<slist_impl> bucket_type;
  1397. typedef typename internal_type::bucket_ptr bucket_ptr;
  1398. typedef typename slist_impl::iterator siterator;
  1399. typedef typename slist_impl::const_iterator const_siterator;
  1400. typedef typename internal_type::iterator iterator;
  1401. typedef typename internal_type::const_iterator const_iterator;
  1402. typedef typename internal_type::local_iterator local_iterator;
  1403. typedef typename internal_type::const_local_iterator const_local_iterator;
  1404. typedef typename value_traits::node_traits node_traits;
  1405. typedef typename node_traits::node node;
  1406. typedef typename pointer_traits
  1407. <pointer>::template rebind_pointer
  1408. < node >::type node_ptr;
  1409. typedef typename pointer_traits
  1410. <pointer>::template rebind_pointer
  1411. < const node >::type const_node_ptr;
  1412. typedef typename pointer_traits
  1413. <node_ptr>::reference node_reference;
  1414. typedef typename pointer_traits
  1415. <const_node_ptr>::reference const_node_reference;
  1416. typedef typename slist_impl::node_algorithms node_algorithms;
  1417. static const bool stateful_value_traits = internal_type::stateful_value_traits;
  1418. static const bool store_hash = internal_type::store_hash;
  1419. static const bool unique_keys = 0 != (BoolFlags & hash_bool_flags::unique_keys_pos);
  1420. static const bool constant_time_size = 0 != (BoolFlags & hash_bool_flags::constant_time_size_pos);
  1421. static const bool cache_begin = 0 != (BoolFlags & hash_bool_flags::cache_begin_pos);
  1422. static const bool compare_hash = 0 != (BoolFlags & hash_bool_flags::compare_hash_pos);
  1423. static const bool incremental = 0 != (BoolFlags & hash_bool_flags::incremental_pos);
  1424. static const bool power_2_buckets = incremental || (0 != (BoolFlags & hash_bool_flags::power_2_buckets_pos));
  1425. static const bool optimize_multikey
  1426. = detail::optimize_multikey_is_true<node_traits>::value && !unique_keys;
  1427. /// @cond
  1428. static const bool is_multikey = !unique_keys;
  1429. private:
  1430. //Configuration error: compare_hash<> can't be specified without store_hash<>
  1431. //See documentation for more explanations
  1432. BOOST_STATIC_ASSERT((!compare_hash || store_hash));
  1433. typedef typename slist_impl::node_ptr slist_node_ptr;
  1434. typedef typename pointer_traits
  1435. <slist_node_ptr>::template rebind_pointer
  1436. < void >::type void_pointer;
  1437. //We'll define group traits, but these won't be instantiated if
  1438. //optimize_multikey is not true
  1439. typedef unordered_group_adapter<node_traits> group_traits;
  1440. typedef circular_slist_algorithms<group_traits> group_algorithms;
  1441. typedef typename internal_type::store_hash_t store_hash_t;
  1442. typedef detail::bool_<optimize_multikey> optimize_multikey_t;
  1443. typedef detail::bool_<cache_begin> cache_begin_t;
  1444. typedef detail::bool_<power_2_buckets> power_2_buckets_t;
  1445. typedef typename internal_type::split_traits split_traits;
  1446. typedef detail::group_functions<node_traits> group_functions_t;
  1447. typedef detail::node_functions<node_traits> node_functions_t;
  1448. private:
  1449. //noncopyable, movable
  1450. BOOST_MOVABLE_BUT_NOT_COPYABLE(hashtable_impl)
  1451. static const bool safemode_or_autounlink = internal_type::safemode_or_autounlink;
  1452. //Constant-time size is incompatible with auto-unlink hooks!
  1453. BOOST_STATIC_ASSERT(!(constant_time_size && ((int)value_traits::link_mode == (int)auto_unlink)));
  1454. //Cache begin is incompatible with auto-unlink hooks!
  1455. BOOST_STATIC_ASSERT(!(cache_begin && ((int)value_traits::link_mode == (int)auto_unlink)));
  1456. template<class Disposer>
  1457. struct typeof_node_disposer
  1458. {
  1459. typedef node_cast_adaptor
  1460. < detail::node_disposer< Disposer, value_traits, CircularSListAlgorithms>
  1461. , slist_node_ptr, node_ptr > type;
  1462. };
  1463. template<class Disposer>
  1464. typename typeof_node_disposer<Disposer>::type
  1465. make_node_disposer(const Disposer &disposer) const
  1466. {
  1467. typedef typename typeof_node_disposer<Disposer>::type return_t;
  1468. return return_t(disposer, &this->priv_value_traits());
  1469. }
  1470. /// @endcond
  1471. public:
  1472. typedef detail::insert_commit_data_impl insert_commit_data;
  1473. public:
  1474. //! <b>Requires</b>: buckets must not be being used by any other resource.
  1475. //!
  1476. //! <b>Effects</b>: Constructs an empty unordered_set, storing a reference
  1477. //! to the bucket array and copies of the key_hasher and equal_func functors.
  1478. //!
  1479. //! <b>Complexity</b>: Constant.
  1480. //!
  1481. //! <b>Throws</b>: If value_traits::node_traits::node
  1482. //! constructor throws (this does not happen with predefined Boost.Intrusive hooks)
  1483. //! or the copy constructor or invocation of hash_func or equal_func throws.
  1484. //!
  1485. //! <b>Notes</b>: buckets array must be disposed only after
  1486. //! *this is disposed.
  1487. explicit hashtable_impl ( const bucket_traits &b_traits
  1488. , const hasher & hash_func = hasher()
  1489. , const key_equal &equal_func = key_equal()
  1490. , const value_traits &v_traits = value_traits())
  1491. : internal_type(v_traits, b_traits, hash_func, equal_func)
  1492. {
  1493. this->priv_initialize_buckets_and_cache();
  1494. this->priv_size_traits().set_size(size_type(0));
  1495. size_type bucket_sz = this->priv_bucket_count();
  1496. BOOST_INTRUSIVE_INVARIANT_ASSERT(bucket_sz != 0);
  1497. //Check power of two bucket array if the option is activated
  1498. BOOST_INTRUSIVE_INVARIANT_ASSERT
  1499. (!power_2_buckets || (0 == (bucket_sz & (bucket_sz-1))));
  1500. this->priv_split_traits().set_size(bucket_sz>>1);
  1501. }
  1502. //! <b>Requires</b>: buckets must not be being used by any other resource
  1503. //! and dereferencing iterator must yield an lvalue of type value_type.
  1504. //!
  1505. //! <b>Effects</b>: Constructs an empty container and inserts elements from
  1506. //! [b, e).
  1507. //!
  1508. //! <b>Complexity</b>: If N is distance(b, e): Average case is O(N)
  1509. //! (with a good hash function and with buckets_len >= N),worst case O(N^2).
  1510. //!
  1511. //! <b>Throws</b>: If value_traits::node_traits::node
  1512. //! constructor throws (this does not happen with predefined Boost.Intrusive hooks)
  1513. //! or the copy constructor or invocation of hasher or key_equal throws.
  1514. //!
  1515. //! <b>Notes</b>: buckets array must be disposed only after
  1516. //! *this is disposed.
  1517. template<class Iterator>
  1518. hashtable_impl ( bool unique, Iterator b, Iterator e
  1519. , const bucket_traits &b_traits
  1520. , const hasher & hash_func = hasher()
  1521. , const key_equal &equal_func = key_equal()
  1522. , const value_traits &v_traits = value_traits())
  1523. : internal_type(v_traits, b_traits, hash_func, equal_func)
  1524. {
  1525. this->priv_initialize_buckets_and_cache();
  1526. this->priv_size_traits().set_size(size_type(0));
  1527. size_type bucket_sz = this->priv_bucket_count();
  1528. BOOST_INTRUSIVE_INVARIANT_ASSERT(bucket_sz != 0);
  1529. //Check power of two bucket array if the option is activated
  1530. BOOST_INTRUSIVE_INVARIANT_ASSERT
  1531. (!power_2_buckets || (0 == (bucket_sz & (bucket_sz-1))));
  1532. this->priv_split_traits().set_size(bucket_sz>>1);
  1533. //Now insert
  1534. if(unique)
  1535. this->insert_unique(b, e);
  1536. else
  1537. this->insert_equal(b, e);
  1538. }
  1539. //! <b>Effects</b>: to-do
  1540. //!
  1541. hashtable_impl(BOOST_RV_REF(hashtable_impl) x)
  1542. : internal_type( ::boost::move(x.priv_value_traits())
  1543. , ::boost::move(x.priv_bucket_traits())
  1544. , ::boost::move(x.priv_hasher())
  1545. , ::boost::move(x.priv_equal())
  1546. )
  1547. {
  1548. this->priv_swap_cache(x);
  1549. x.priv_initialize_cache();
  1550. if(constant_time_size){
  1551. this->priv_size_traits().set_size(size_type(0));
  1552. this->priv_size_traits().set_size(x.priv_size_traits().get_size());
  1553. x.priv_size_traits().set_size(size_type(0));
  1554. }
  1555. if(incremental){
  1556. this->priv_split_traits().set_size(x.priv_split_traits().get_size());
  1557. x.priv_split_traits().set_size(size_type(0));
  1558. }
  1559. }
  1560. //! <b>Effects</b>: to-do
  1561. //!
  1562. hashtable_impl& operator=(BOOST_RV_REF(hashtable_impl) x)
  1563. { this->swap(x); return *this; }
  1564. #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
  1565. //! <b>Effects</b>: Detaches all elements from this. The objects in the unordered_set
  1566. //! are not deleted (i.e. no destructors are called).
  1567. //!
  1568. //! <b>Complexity</b>: Linear to the number of elements in the unordered_set, if
  1569. //! it's a safe-mode or auto-unlink value. Otherwise constant.
  1570. //!
  1571. //! <b>Throws</b>: Nothing.
  1572. ~hashtable_impl();
  1573. //! <b>Effects</b>: Returns an iterator pointing to the beginning of the unordered_set.
  1574. //!
  1575. //! <b>Complexity</b>: Amortized constant time.
  1576. //! Worst case (empty unordered_set): O(this->bucket_count())
  1577. //!
  1578. //! <b>Throws</b>: Nothing.
  1579. iterator begin();
  1580. //! <b>Effects</b>: Returns a const_iterator pointing to the beginning
  1581. //! of the unordered_set.
  1582. //!
  1583. //! <b>Complexity</b>: Amortized constant time.
  1584. //! Worst case (empty unordered_set): O(this->bucket_count())
  1585. //!
  1586. //! <b>Throws</b>: Nothing.
  1587. const_iterator begin() const;
  1588. //! <b>Effects</b>: Returns a const_iterator pointing to the beginning
  1589. //! of the unordered_set.
  1590. //!
  1591. //! <b>Complexity</b>: Amortized constant time.
  1592. //! Worst case (empty unordered_set): O(this->bucket_count())
  1593. //!
  1594. //! <b>Throws</b>: Nothing.
  1595. const_iterator cbegin() const;
  1596. //! <b>Effects</b>: Returns an iterator pointing to the end of the unordered_set.
  1597. //!
  1598. //! <b>Complexity</b>: Constant.
  1599. //!
  1600. //! <b>Throws</b>: Nothing.
  1601. iterator end();
  1602. //! <b>Effects</b>: Returns a const_iterator pointing to the end of the unordered_set.
  1603. //!
  1604. //! <b>Complexity</b>: Constant.
  1605. //!
  1606. //! <b>Throws</b>: Nothing.
  1607. const_iterator end() const;
  1608. //! <b>Effects</b>: Returns a const_iterator pointing to the end of the unordered_set.
  1609. //!
  1610. //! <b>Complexity</b>: Constant.
  1611. //!
  1612. //! <b>Throws</b>: Nothing.
  1613. const_iterator cend() const;
  1614. //! <b>Effects</b>: Returns the hasher object used by the unordered_set.
  1615. //!
  1616. //! <b>Complexity</b>: Constant.
  1617. //!
  1618. //! <b>Throws</b>: If hasher copy-constructor throws.
  1619. hasher hash_function() const;
  1620. //! <b>Effects</b>: Returns the key_equal object used by the unordered_set.
  1621. //!
  1622. //! <b>Complexity</b>: Constant.
  1623. //!
  1624. //! <b>Throws</b>: If key_equal copy-constructor throws.
  1625. key_equal key_eq() const;
  1626. #endif
  1627. //! <b>Effects</b>: Returns true if the container is empty.
  1628. //!
  1629. //! <b>Complexity</b>: if constant-time size and cache_begin options are disabled,
  1630. //! average constant time (worst case, with empty() == true: O(this->bucket_count()).
  1631. //! Otherwise constant.
  1632. //!
  1633. //! <b>Throws</b>: Nothing.
  1634. bool empty() const
  1635. {
  1636. if(constant_time_size){
  1637. return !this->size();
  1638. }
  1639. else if(cache_begin){
  1640. return this->begin() == this->end();
  1641. }
  1642. else{
  1643. size_type bucket_cnt = this->priv_bucket_count();
  1644. const bucket_type *b = boost::intrusive::detail::to_raw_pointer(this->priv_bucket_pointer());
  1645. for (size_type n = 0; n < bucket_cnt; ++n, ++b){
  1646. if(!b->empty()){
  1647. return false;
  1648. }
  1649. }
  1650. return true;
  1651. }
  1652. }
  1653. //! <b>Effects</b>: Returns the number of elements stored in the unordered_set.
  1654. //!
  1655. //! <b>Complexity</b>: Linear to elements contained in *this if
  1656. //! constant_time_size is false. Constant-time otherwise.
  1657. //!
  1658. //! <b>Throws</b>: Nothing.
  1659. size_type size() const
  1660. {
  1661. if(constant_time_size)
  1662. return this->priv_size_traits().get_size();
  1663. else{
  1664. size_type len = 0;
  1665. size_type bucket_cnt = this->priv_bucket_count();
  1666. const bucket_type *b = boost::intrusive::detail::to_raw_pointer(this->priv_bucket_pointer());
  1667. for (size_type n = 0; n < bucket_cnt; ++n, ++b){
  1668. len += b->size();
  1669. }
  1670. return len;
  1671. }
  1672. }
  1673. //! <b>Requires</b>: the hasher and the equality function unqualified swap
  1674. //! call should not throw.
  1675. //!
  1676. //! <b>Effects</b>: Swaps the contents of two unordered_sets.
  1677. //! Swaps also the contained bucket array and equality and hasher functors.
  1678. //!
  1679. //! <b>Complexity</b>: Constant.
  1680. //!
  1681. //! <b>Throws</b>: If the swap() call for the comparison or hash functors
  1682. //! found using ADL throw. Basic guarantee.
  1683. void swap(hashtable_impl& other)
  1684. {
  1685. //These can throw
  1686. ::boost::adl_move_swap(this->priv_equal(), other.priv_equal());
  1687. ::boost::adl_move_swap(this->priv_hasher(), other.priv_hasher());
  1688. //These can't throw
  1689. ::boost::adl_move_swap(this->priv_bucket_traits(), other.priv_bucket_traits());
  1690. ::boost::adl_move_swap(this->priv_value_traits(), other.priv_value_traits());
  1691. this->priv_swap_cache(other);
  1692. ::boost::adl_move_swap(this->priv_size_traits(), other.priv_size_traits());
  1693. ::boost::adl_move_swap(this->priv_split_traits(), other.priv_split_traits());
  1694. }
  1695. //! <b>Requires</b>: Disposer::operator()(pointer) shouldn't throw
  1696. //! Cloner should yield to nodes that compare equal and produce the same
  1697. //! hash than the original node.
  1698. //!
  1699. //! <b>Effects</b>: Erases all the elements from *this
  1700. //! calling Disposer::operator()(pointer), clones all the
  1701. //! elements from src calling Cloner::operator()(const_reference )
  1702. //! and inserts them on *this. The hash function and the equality
  1703. //! predicate are copied from the source.
  1704. //!
  1705. //! If store_hash option is true, this method does not use the hash function.
  1706. //!
  1707. //! If any operation throws, all cloned elements are unlinked and disposed
  1708. //! calling Disposer::operator()(pointer).
  1709. //!
  1710. //! <b>Complexity</b>: Linear to erased plus inserted elements.
  1711. //!
  1712. //! <b>Throws</b>: If cloner or hasher throw or hash or equality predicate copying
  1713. //! throws. Basic guarantee.
  1714. template <class Cloner, class Disposer>
  1715. void clone_from(const hashtable_impl &src, Cloner cloner, Disposer disposer)
  1716. { this->priv_clone_from(src, cloner, disposer); }
  1717. //! <b>Requires</b>: Disposer::operator()(pointer) shouldn't throw
  1718. //! Cloner should yield to nodes that compare equal and produce the same
  1719. //! hash than the original node.
  1720. //!
  1721. //! <b>Effects</b>: Erases all the elements from *this
  1722. //! calling Disposer::operator()(pointer), clones all the
  1723. //! elements from src calling Cloner::operator()(reference)
  1724. //! and inserts them on *this. The hash function and the equality
  1725. //! predicate are copied from the source.
  1726. //!
  1727. //! If store_hash option is true, this method does not use the hash function.
  1728. //!
  1729. //! If any operation throws, all cloned elements are unlinked and disposed
  1730. //! calling Disposer::operator()(pointer).
  1731. //!
  1732. //! <b>Complexity</b>: Linear to erased plus inserted elements.
  1733. //!
  1734. //! <b>Throws</b>: If cloner or hasher throw or hash or equality predicate copying
  1735. //! throws. Basic guarantee.
  1736. template <class Cloner, class Disposer>
  1737. void clone_from(BOOST_RV_REF(hashtable_impl) src, Cloner cloner, Disposer disposer)
  1738. { this->priv_clone_from(static_cast<hashtable_impl&>(src), cloner, disposer); }
  1739. //! <b>Requires</b>: value must be an lvalue
  1740. //!
  1741. //! <b>Effects</b>: Inserts the value into the unordered_set.
  1742. //!
  1743. //! <b>Returns</b>: An iterator to the inserted value.
  1744. //!
  1745. //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).
  1746. //!
  1747. //! <b>Throws</b>: If the internal hasher or the equality functor throws. Strong guarantee.
  1748. //!
  1749. //! <b>Note</b>: Does not affect the validity of iterators and references.
  1750. //! No copy-constructors are called.
  1751. iterator insert_equal(reference value)
  1752. {
  1753. size_type bucket_num;
  1754. std::size_t hash_value;
  1755. siterator prev;
  1756. siterator const it = this->priv_find
  1757. (key_of_value()(value), this->priv_hasher(), this->priv_equal(), bucket_num, hash_value, prev);
  1758. bool const next_is_in_group = optimize_multikey && it != this->priv_invalid_local_it();
  1759. return this->priv_insert_equal_after_find(value, bucket_num, hash_value, prev, next_is_in_group);
  1760. }
  1761. //! <b>Requires</b>: Dereferencing iterator must yield an lvalue
  1762. //! of type value_type.
  1763. //!
  1764. //! <b>Effects</b>: Equivalent to this->insert_equal(t) for each element in [b, e).
  1765. //!
  1766. //! <b>Complexity</b>: Average case O(N), where N is distance(b, e).
  1767. //! Worst case O(N*this->size()).
  1768. //!
  1769. //! <b>Throws</b>: If the internal hasher or the equality functor throws. Basic guarantee.
  1770. //!
  1771. //! <b>Note</b>: Does not affect the validity of iterators and references.
  1772. //! No copy-constructors are called.
  1773. template<class Iterator>
  1774. void insert_equal(Iterator b, Iterator e)
  1775. {
  1776. for (; b != e; ++b)
  1777. this->insert_equal(*b);
  1778. }
  1779. //! <b>Requires</b>: value must be an lvalue
  1780. //!
  1781. //! <b>Effects</b>: Tries to inserts value into the unordered_set.
  1782. //!
  1783. //! <b>Returns</b>: If the value
  1784. //! is not already present inserts it and returns a pair containing the
  1785. //! iterator to the new value and true. If there is an equivalent value
  1786. //! returns a pair containing an iterator to the already present value
  1787. //! and false.
  1788. //!
  1789. //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).
  1790. //!
  1791. //! <b>Throws</b>: If the internal hasher or the equality functor throws. Strong guarantee.
  1792. //!
  1793. //! <b>Note</b>: Does not affect the validity of iterators and references.
  1794. //! No copy-constructors are called.
  1795. std::pair<iterator, bool> insert_unique(reference value)
  1796. {
  1797. insert_commit_data commit_data;
  1798. std::pair<iterator, bool> ret = this->insert_unique_check(key_of_value()(value), commit_data);
  1799. if(ret.second){
  1800. ret.first = this->insert_unique_commit(value, commit_data);
  1801. }
  1802. return ret;
  1803. }
  1804. //! <b>Requires</b>: Dereferencing iterator must yield an lvalue
  1805. //! of type value_type.
  1806. //!
  1807. //! <b>Effects</b>: Equivalent to this->insert_unique(t) for each element in [b, e).
  1808. //!
  1809. //! <b>Complexity</b>: Average case O(N), where N is distance(b, e).
  1810. //! Worst case O(N*this->size()).
  1811. //!
  1812. //! <b>Throws</b>: If the internal hasher or the equality functor throws. Basic guarantee.
  1813. //!
  1814. //! <b>Note</b>: Does not affect the validity of iterators and references.
  1815. //! No copy-constructors are called.
  1816. template<class Iterator>
  1817. void insert_unique(Iterator b, Iterator e)
  1818. {
  1819. for (; b != e; ++b)
  1820. this->insert_unique(*b);
  1821. }
  1822. //! <b>Requires</b>: "hash_func" must be a hash function that induces
  1823. //! the same hash values as the stored hasher. The difference is that
  1824. //! "hash_func" hashes the given key instead of the value_type.
  1825. //!
  1826. //! "equal_func" must be a equality function that induces
  1827. //! the same equality as key_equal. The difference is that
  1828. //! "equal_func" compares an arbitrary key with the contained values.
  1829. //!
  1830. //! <b>Effects</b>: Checks if a value can be inserted in the unordered_set, using
  1831. //! a user provided key instead of the value itself.
  1832. //!
  1833. //! <b>Returns</b>: If there is an equivalent value
  1834. //! returns a pair containing an iterator to the already present value
  1835. //! and false. If the value can be inserted returns true in the returned
  1836. //! pair boolean and fills "commit_data" that is meant to be used with
  1837. //! the "insert_commit" function.
  1838. //!
  1839. //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).
  1840. //!
  1841. //! <b>Throws</b>: If hash_func or equal_func throw. Strong guarantee.
  1842. //!
  1843. //! <b>Notes</b>: This function is used to improve performance when constructing
  1844. //! a value_type is expensive: if there is an equivalent value
  1845. //! the constructed object must be discarded. Many times, the part of the
  1846. //! node that is used to impose the hash or the equality is much cheaper to
  1847. //! construct than the value_type and this function offers the possibility to
  1848. //! use that the part to check if the insertion will be successful.
  1849. //!
  1850. //! If the check is successful, the user can construct the value_type and use
  1851. //! "insert_commit" to insert the object in constant-time.
  1852. //!
  1853. //! "commit_data" remains valid for a subsequent "insert_commit" only if no more
  1854. //! objects are inserted or erased from the unordered_set.
  1855. //!
  1856. //! After a successful rehashing insert_commit_data remains valid.
  1857. template<class KeyType, class KeyHasher, class KeyEqual>
  1858. std::pair<iterator, bool> insert_unique_check
  1859. ( const KeyType &key
  1860. , KeyHasher hash_func
  1861. , KeyEqual equal_func
  1862. , insert_commit_data &commit_data)
  1863. {
  1864. size_type bucket_num;
  1865. siterator prev;
  1866. siterator const pos = this->priv_find(key, hash_func, equal_func, bucket_num, commit_data.hash, prev);
  1867. return std::pair<iterator, bool>
  1868. ( iterator(pos, &this->get_bucket_value_traits())
  1869. , pos == this->priv_invalid_local_it());
  1870. }
  1871. //! <b>Effects</b>: Checks if a value can be inserted in the unordered_set, using
  1872. //! a user provided key instead of the value itself.
  1873. //!
  1874. //! <b>Returns</b>: If there is an equivalent value
  1875. //! returns a pair containing an iterator to the already present value
  1876. //! and false. If the value can be inserted returns true in the returned
  1877. //! pair boolean and fills "commit_data" that is meant to be used with
  1878. //! the "insert_commit" function.
  1879. //!
  1880. //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).
  1881. //!
  1882. //! <b>Throws</b>: If hasher or key_compare throw. Strong guarantee.
  1883. //!
  1884. //! <b>Notes</b>: This function is used to improve performance when constructing
  1885. //! a value_type is expensive: if there is an equivalent value
  1886. //! the constructed object must be discarded. Many times, the part of the
  1887. //! node that is used to impose the hash or the equality is much cheaper to
  1888. //! construct than the value_type and this function offers the possibility to
  1889. //! use that the part to check if the insertion will be successful.
  1890. //!
  1891. //! If the check is successful, the user can construct the value_type and use
  1892. //! "insert_commit" to insert the object in constant-time.
  1893. //!
  1894. //! "commit_data" remains valid for a subsequent "insert_commit" only if no more
  1895. //! objects are inserted or erased from the unordered_set.
  1896. //!
  1897. //! After a successful rehashing insert_commit_data remains valid.
  1898. std::pair<iterator, bool> insert_unique_check
  1899. ( const key_type &key, insert_commit_data &commit_data)
  1900. { return this->insert_unique_check(key, this->priv_hasher(), this->priv_equal(), commit_data); }
  1901. //! <b>Requires</b>: value must be an lvalue of type value_type. commit_data
  1902. //! must have been obtained from a previous call to "insert_check".
  1903. //! No objects should have been inserted or erased from the unordered_set between
  1904. //! the "insert_check" that filled "commit_data" and the call to "insert_commit".
  1905. //!
  1906. //! <b>Effects</b>: Inserts the value in the unordered_set using the information obtained
  1907. //! from the "commit_data" that a previous "insert_check" filled.
  1908. //!
  1909. //! <b>Returns</b>: An iterator to the newly inserted object.
  1910. //!
  1911. //! <b>Complexity</b>: Constant time.
  1912. //!
  1913. //! <b>Throws</b>: Nothing.
  1914. //!
  1915. //! <b>Notes</b>: This function has only sense if a "insert_check" has been
  1916. //! previously executed to fill "commit_data". No value should be inserted or
  1917. //! erased between the "insert_check" and "insert_commit" calls.
  1918. //!
  1919. //! After a successful rehashing insert_commit_data remains valid.
  1920. iterator insert_unique_commit(reference value, const insert_commit_data &commit_data)
  1921. {
  1922. size_type bucket_num = this->priv_hash_to_bucket(commit_data.hash);
  1923. bucket_type &b = this->priv_bucket_pointer()[bucket_num];
  1924. this->priv_size_traits().increment();
  1925. node_ptr const n = pointer_traits<node_ptr>::pointer_to(this->priv_value_to_node(value));
  1926. BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(!safemode_or_autounlink || node_algorithms::unique(n));
  1927. node_functions_t::store_hash(n, commit_data.hash, store_hash_t());
  1928. this->priv_insertion_update_cache(bucket_num);
  1929. group_functions_t::insert_in_group(n, n, optimize_multikey_t());
  1930. return iterator(b.insert_after(b.before_begin(), *n), &this->get_bucket_value_traits());
  1931. }
  1932. //! <b>Effects</b>: Erases the element pointed to by i.
  1933. //!
  1934. //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).
  1935. //!
  1936. //! <b>Throws</b>: Nothing.
  1937. //!
  1938. //! <b>Note</b>: Invalidates the iterators (but not the references)
  1939. //! to the erased element. No destructors are called.
  1940. void erase(const_iterator i)
  1941. { this->erase_and_dispose(i, detail::null_disposer()); }
  1942. //! <b>Effects</b>: Erases the range pointed to by b end e.
  1943. //!
  1944. //! <b>Complexity</b>: Average case O(distance(b, e)),
  1945. //! worst case O(this->size()).
  1946. //!
  1947. //! <b>Throws</b>: Nothing.
  1948. //!
  1949. //! <b>Note</b>: Invalidates the iterators (but not the references)
  1950. //! to the erased elements. No destructors are called.
  1951. void erase(const_iterator b, const_iterator e)
  1952. { this->erase_and_dispose(b, e, detail::null_disposer()); }
  1953. //! <b>Effects</b>: Erases all the elements with the given value.
  1954. //!
  1955. //! <b>Returns</b>: The number of erased elements.
  1956. //!
  1957. //! <b>Complexity</b>: Average case O(this->count(value)).
  1958. //! Worst case O(this->size()).
  1959. //!
  1960. //! <b>Throws</b>: If the internal hasher or the equality functor throws.
  1961. //! Basic guarantee.
  1962. //!
  1963. //! <b>Note</b>: Invalidates the iterators (but not the references)
  1964. //! to the erased elements. No destructors are called.
  1965. size_type erase(const key_type &key)
  1966. { return this->erase(key, this->priv_hasher(), this->priv_equal()); }
  1967. //! <b>Requires</b>: "hash_func" must be a hash function that induces
  1968. //! the same hash values as the stored hasher. The difference is that
  1969. //! "hash_func" hashes the given key instead of the value_type.
  1970. //!
  1971. //! "equal_func" must be a equality function that induces
  1972. //! the same equality as key_equal. The difference is that
  1973. //! "equal_func" compares an arbitrary key with the contained values.
  1974. //!
  1975. //! <b>Effects</b>: Erases all the elements that have the same hash and
  1976. //! compare equal with the given key.
  1977. //!
  1978. //! <b>Returns</b>: The number of erased elements.
  1979. //!
  1980. //! <b>Complexity</b>: Average case O(this->count(value)).
  1981. //! Worst case O(this->size()).
  1982. //!
  1983. //! <b>Throws</b>: If hash_func or equal_func throw. Basic guarantee.
  1984. //!
  1985. //! <b>Note</b>: Invalidates the iterators (but not the references)
  1986. //! to the erased elements. No destructors are called.
  1987. template<class KeyType, class KeyHasher, class KeyEqual>
  1988. size_type erase(const KeyType& key, KeyHasher hash_func, KeyEqual equal_func)
  1989. { return this->erase_and_dispose(key, hash_func, equal_func, detail::null_disposer()); }
  1990. //! <b>Requires</b>: Disposer::operator()(pointer) shouldn't throw.
  1991. //!
  1992. //! <b>Effects</b>: Erases the element pointed to by i.
  1993. //! Disposer::operator()(pointer) is called for the removed element.
  1994. //!
  1995. //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).
  1996. //!
  1997. //! <b>Throws</b>: Nothing.
  1998. //!
  1999. //! <b>Note</b>: Invalidates the iterators
  2000. //! to the erased elements.
  2001. template<class Disposer>
  2002. BOOST_INTRUSIVE_DOC1ST(void
  2003. , typename detail::disable_if_convertible<Disposer BOOST_INTRUSIVE_I const_iterator>::type)
  2004. erase_and_dispose(const_iterator i, Disposer disposer)
  2005. {
  2006. //Get the bucket number and local iterator for both iterators
  2007. siterator const first_local_it(i.slist_it());
  2008. size_type const first_bucket_num = this->priv_get_bucket_num(first_local_it);
  2009. this->priv_erase_node(this->priv_bucket_pointer()[first_bucket_num], first_local_it, make_node_disposer(disposer), optimize_multikey_t());
  2010. this->priv_size_traits().decrement();
  2011. this->priv_erasure_update_cache_range(first_bucket_num, first_bucket_num);
  2012. }
  2013. //! <b>Requires</b>: Disposer::operator()(pointer) shouldn't throw.
  2014. //!
  2015. //! <b>Effects</b>: Erases the range pointed to by b end e.
  2016. //! Disposer::operator()(pointer) is called for the removed elements.
  2017. //!
  2018. //! <b>Complexity</b>: Average case O(distance(b, e)),
  2019. //! worst case O(this->size()).
  2020. //!
  2021. //! <b>Throws</b>: Nothing.
  2022. //!
  2023. //! <b>Note</b>: Invalidates the iterators
  2024. //! to the erased elements.
  2025. template<class Disposer>
  2026. void erase_and_dispose(const_iterator b, const_iterator e, Disposer disposer)
  2027. {
  2028. if(b != e){
  2029. //Get the bucket number and local iterator for both iterators
  2030. siterator first_local_it(b.slist_it());
  2031. size_type first_bucket_num = this->priv_get_bucket_num(first_local_it);
  2032. const bucket_ptr buck_ptr = this->priv_bucket_pointer();
  2033. siterator before_first_local_it
  2034. = this->priv_get_previous(buck_ptr[first_bucket_num], first_local_it);
  2035. size_type last_bucket_num;
  2036. siterator last_local_it;
  2037. //For the end iterator, we will assign the end iterator
  2038. //of the last bucket
  2039. if(e == this->end()){
  2040. last_bucket_num = this->bucket_count() - 1;
  2041. last_local_it = buck_ptr[last_bucket_num].end();
  2042. }
  2043. else{
  2044. last_local_it = e.slist_it();
  2045. last_bucket_num = this->priv_get_bucket_num(last_local_it);
  2046. }
  2047. size_type const num_erased = this->priv_erase_node_range
  2048. ( before_first_local_it, first_bucket_num, last_local_it, last_bucket_num
  2049. , make_node_disposer(disposer), optimize_multikey_t());
  2050. this->priv_size_traits().set_size(this->priv_size_traits().get_size()-num_erased);
  2051. this->priv_erasure_update_cache_range(first_bucket_num, last_bucket_num);
  2052. }
  2053. }
  2054. //! <b>Requires</b>: Disposer::operator()(pointer) shouldn't throw.
  2055. //!
  2056. //! <b>Effects</b>: Erases all the elements with the given value.
  2057. //! Disposer::operator()(pointer) is called for the removed elements.
  2058. //!
  2059. //! <b>Returns</b>: The number of erased elements.
  2060. //!
  2061. //! <b>Complexity</b>: Average case O(this->count(value)).
  2062. //! Worst case O(this->size()).
  2063. //!
  2064. //! <b>Throws</b>: If the internal hasher or the equality functor throws.
  2065. //! Basic guarantee.
  2066. //!
  2067. //! <b>Note</b>: Invalidates the iterators (but not the references)
  2068. //! to the erased elements. No destructors are called.
  2069. template<class Disposer>
  2070. size_type erase_and_dispose(const key_type &key, Disposer disposer)
  2071. { return this->erase_and_dispose(key, this->priv_hasher(), this->priv_equal(), disposer); }
  2072. //! <b>Requires</b>: Disposer::operator()(pointer) shouldn't throw.
  2073. //!
  2074. //! <b>Effects</b>: Erases all the elements with the given key.
  2075. //! according to the comparison functor "equal_func".
  2076. //! Disposer::operator()(pointer) is called for the removed elements.
  2077. //!
  2078. //! <b>Returns</b>: The number of erased elements.
  2079. //!
  2080. //! <b>Complexity</b>: Average case O(this->count(value)).
  2081. //! Worst case O(this->size()).
  2082. //!
  2083. //! <b>Throws</b>: If hash_func or equal_func throw. Basic guarantee.
  2084. //!
  2085. //! <b>Note</b>: Invalidates the iterators
  2086. //! to the erased elements.
  2087. template<class KeyType, class KeyHasher, class KeyEqual, class Disposer>
  2088. size_type erase_and_dispose(const KeyType& key, KeyHasher hash_func
  2089. ,KeyEqual equal_func, Disposer disposer)
  2090. {
  2091. size_type bucket_num;
  2092. std::size_t h;
  2093. siterator prev;
  2094. siterator it = this->priv_find(key, hash_func, equal_func, bucket_num, h, prev);
  2095. bool const success = it != this->priv_invalid_local_it();
  2096. size_type cnt(0);
  2097. if(success){
  2098. if(optimize_multikey){
  2099. cnt = this->priv_erase_from_single_bucket
  2100. (this->priv_bucket_pointer()[bucket_num], prev, ++(priv_last_in_group)(it), make_node_disposer(disposer), optimize_multikey_t());
  2101. }
  2102. else{
  2103. bucket_type &b = this->priv_bucket_pointer()[bucket_num];
  2104. siterator const end_sit = b.end();
  2105. do{
  2106. ++cnt;
  2107. ++it;
  2108. }while(it != end_sit &&
  2109. this->priv_is_value_equal_to_key
  2110. (this->priv_value_from_slist_node(it.pointed_node()), h, key, equal_func));
  2111. bucket_type::s_erase_after_and_dispose(prev, it, make_node_disposer(disposer));
  2112. }
  2113. this->priv_size_traits().set_size(this->priv_size_traits().get_size()-cnt);
  2114. this->priv_erasure_update_cache();
  2115. }
  2116. return cnt;
  2117. }
  2118. //! <b>Effects</b>: Erases all of the elements.
  2119. //!
  2120. //! <b>Complexity</b>: Linear to the number of elements on the container.
  2121. //! if it's a safe-mode or auto-unlink value_type. Constant time otherwise.
  2122. //!
  2123. //! <b>Throws</b>: Nothing.
  2124. //!
  2125. //! <b>Note</b>: Invalidates the iterators (but not the references)
  2126. //! to the erased elements. No destructors are called.
  2127. void clear()
  2128. {
  2129. this->priv_clear_buckets_and_cache();
  2130. this->priv_size_traits().set_size(size_type(0));
  2131. }
  2132. //! <b>Requires</b>: Disposer::operator()(pointer) shouldn't throw.
  2133. //!
  2134. //! <b>Effects</b>: Erases all of the elements.
  2135. //!
  2136. //! <b>Complexity</b>: Linear to the number of elements on the container.
  2137. //! Disposer::operator()(pointer) is called for the removed elements.
  2138. //!
  2139. //! <b>Throws</b>: Nothing.
  2140. //!
  2141. //! <b>Note</b>: Invalidates the iterators (but not the references)
  2142. //! to the erased elements. No destructors are called.
  2143. template<class Disposer>
  2144. void clear_and_dispose(Disposer disposer)
  2145. {
  2146. if(!constant_time_size || !this->empty()){
  2147. size_type num_buckets = this->bucket_count();
  2148. bucket_ptr b = this->priv_bucket_pointer();
  2149. typename typeof_node_disposer<Disposer>::type d(disposer, &this->priv_value_traits());
  2150. for(; num_buckets--; ++b){
  2151. b->clear_and_dispose(d);
  2152. }
  2153. this->priv_size_traits().set_size(size_type(0));
  2154. }
  2155. this->priv_initialize_cache();
  2156. }
  2157. //! <b>Effects</b>: Returns the number of contained elements with the given value
  2158. //!
  2159. //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).
  2160. //!
  2161. //! <b>Throws</b>: If the internal hasher or the equality functor throws.
  2162. size_type count(const key_type &key) const
  2163. { return this->count(key, this->priv_hasher(), this->priv_equal()); }
  2164. //! <b>Requires</b>: "hash_func" must be a hash function that induces
  2165. //! the same hash values as the stored hasher. The difference is that
  2166. //! "hash_func" hashes the given key instead of the value_type.
  2167. //!
  2168. //! "equal_func" must be a equality function that induces
  2169. //! the same equality as key_equal. The difference is that
  2170. //! "equal_func" compares an arbitrary key with the contained values.
  2171. //!
  2172. //! <b>Effects</b>: Returns the number of contained elements with the given key
  2173. //!
  2174. //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).
  2175. //!
  2176. //! <b>Throws</b>: If hash_func or equal throw.
  2177. template<class KeyType, class KeyHasher, class KeyEqual>
  2178. size_type count(const KeyType &key, KeyHasher hash_func, KeyEqual equal_func) const
  2179. {
  2180. size_type cnt;
  2181. size_type n_bucket;
  2182. this->priv_local_equal_range(key, hash_func, equal_func, n_bucket, cnt);
  2183. return cnt;
  2184. }
  2185. //! <b>Effects</b>: Finds an iterator to the first element is equal to
  2186. //! "value" or end() if that element does not exist.
  2187. //!
  2188. //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).
  2189. //!
  2190. //! <b>Throws</b>: If the internal hasher or the equality functor throws.
  2191. iterator find(const key_type &key)
  2192. { return this->find(key, this->priv_hasher(), this->priv_equal()); }
  2193. //! <b>Requires</b>: "hash_func" must be a hash function that induces
  2194. //! the same hash values as the stored hasher. The difference is that
  2195. //! "hash_func" hashes the given key instead of the value_type.
  2196. //!
  2197. //! "equal_func" must be a equality function that induces
  2198. //! the same equality as key_equal. The difference is that
  2199. //! "equal_func" compares an arbitrary key with the contained values.
  2200. //!
  2201. //! <b>Effects</b>: Finds an iterator to the first element whose key is
  2202. //! "key" according to the given hash and equality functor or end() if
  2203. //! that element does not exist.
  2204. //!
  2205. //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).
  2206. //!
  2207. //! <b>Throws</b>: If hash_func or equal_func throw.
  2208. //!
  2209. //! <b>Note</b>: This function is used when constructing a value_type
  2210. //! is expensive and the value_type can be compared with a cheaper
  2211. //! key type. Usually this key is part of the value_type.
  2212. template<class KeyType, class KeyHasher, class KeyEqual>
  2213. iterator find(const KeyType &key, KeyHasher hash_func, KeyEqual equal_func)
  2214. {
  2215. size_type bucket_n;
  2216. std::size_t hash;
  2217. siterator prev;
  2218. return iterator( this->priv_find(key, hash_func, equal_func, bucket_n, hash, prev)
  2219. , &this->get_bucket_value_traits());
  2220. }
  2221. //! <b>Effects</b>: Finds a const_iterator to the first element whose key is
  2222. //! "key" or end() if that element does not exist.
  2223. //!
  2224. //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).
  2225. //!
  2226. //! <b>Throws</b>: If the internal hasher or the equality functor throws.
  2227. const_iterator find(const key_type &key) const
  2228. { return this->find(key, this->priv_hasher(), this->priv_equal()); }
  2229. //! <b>Requires</b>: "hash_func" must be a hash function that induces
  2230. //! the same hash values as the stored hasher. The difference is that
  2231. //! "hash_func" hashes the given key instead of the value_type.
  2232. //!
  2233. //! "equal_func" must be a equality function that induces
  2234. //! the same equality as key_equal. The difference is that
  2235. //! "equal_func" compares an arbitrary key with the contained values.
  2236. //!
  2237. //! <b>Effects</b>: Finds an iterator to the first element whose key is
  2238. //! "key" according to the given hasher and equality functor or end() if
  2239. //! that element does not exist.
  2240. //!
  2241. //! <b>Complexity</b>: Average case O(1), worst case O(this->size()).
  2242. //!
  2243. //! <b>Throws</b>: If hash_func or equal_func throw.
  2244. //!
  2245. //! <b>Note</b>: This function is used when constructing a value_type
  2246. //! is expensive and the value_type can be compared with a cheaper
  2247. //! key type. Usually this key is part of the value_type.
  2248. template<class KeyType, class KeyHasher, class KeyEqual>
  2249. const_iterator find
  2250. (const KeyType &key, KeyHasher hash_func, KeyEqual equal_func) const
  2251. {
  2252. size_type bucket_n;
  2253. std::size_t hash_value;
  2254. siterator prev;
  2255. return const_iterator( this->priv_find(key, hash_func, equal_func, bucket_n, hash_value, prev)
  2256. , &this->get_bucket_value_traits());
  2257. }
  2258. //! <b>Effects</b>: Returns a range containing all elements with values equivalent
  2259. //! to value. Returns std::make_pair(this->end(), this->end()) if no such
  2260. //! elements exist.
  2261. //!
  2262. //! <b>Complexity</b>: Average case O(this->count(value)). Worst case O(this->size()).
  2263. //!
  2264. //! <b>Throws</b>: If the internal hasher or the equality functor throws.
  2265. std::pair<iterator,iterator> equal_range(const key_type &key)
  2266. { return this->equal_range(key, this->priv_hasher(), this->priv_equal()); }
  2267. //! <b>Requires</b>: "hash_func" must be a hash function that induces
  2268. //! the same hash values as the stored hasher. The difference is that
  2269. //! "hash_func" hashes the given key instead of the value_type.
  2270. //!
  2271. //! "equal_func" must be a equality function that induces
  2272. //! the same equality as key_equal. The difference is that
  2273. //! "equal_func" compares an arbitrary key with the contained values.
  2274. //!
  2275. //! <b>Effects</b>: Returns a range containing all elements with equivalent
  2276. //! keys. Returns std::make_pair(this->end(), this->end()) if no such
  2277. //! elements exist.
  2278. //!
  2279. //! <b>Complexity</b>: Average case O(this->count(key, hash_func, equal_func)).
  2280. //! Worst case O(this->size()).
  2281. //!
  2282. //! <b>Throws</b>: If hash_func or the equal_func throw.
  2283. //!
  2284. //! <b>Note</b>: This function is used when constructing a value_type
  2285. //! is expensive and the value_type can be compared with a cheaper
  2286. //! key type. Usually this key is part of the value_type.
  2287. template<class KeyType, class KeyHasher, class KeyEqual>
  2288. std::pair<iterator,iterator> equal_range
  2289. (const KeyType &key, KeyHasher hash_func, KeyEqual equal_func)
  2290. {
  2291. std::pair<siterator, siterator> ret =
  2292. this->priv_equal_range(key, hash_func, equal_func);
  2293. return std::pair<iterator, iterator>
  2294. ( iterator(ret.first, &this->get_bucket_value_traits())
  2295. , iterator(ret.second, &this->get_bucket_value_traits()));
  2296. }
  2297. //! <b>Effects</b>: Returns a range containing all elements with values equivalent
  2298. //! to value. Returns std::make_pair(this->end(), this->end()) if no such
  2299. //! elements exist.
  2300. //!
  2301. //! <b>Complexity</b>: Average case O(this->count(value)). Worst case O(this->size()).
  2302. //!
  2303. //! <b>Throws</b>: If the internal hasher or the equality functor throws.
  2304. std::pair<const_iterator, const_iterator>
  2305. equal_range(const key_type &key) const
  2306. { return this->equal_range(key, this->priv_hasher(), this->priv_equal()); }
  2307. //! <b>Requires</b>: "hash_func" must be a hash function that induces
  2308. //! the same hash values as the stored hasher. The difference is that
  2309. //! "hash_func" hashes the given key instead of the value_type.
  2310. //!
  2311. //! "equal_func" must be a equality function that induces
  2312. //! the same equality as key_equal. The difference is that
  2313. //! "equal_func" compares an arbitrary key with the contained values.
  2314. //!
  2315. //! <b>Effects</b>: Returns a range containing all elements with equivalent
  2316. //! keys. Returns std::make_pair(this->end(), this->end()) if no such
  2317. //! elements exist.
  2318. //!
  2319. //! <b>Complexity</b>: Average case O(this->count(key, hash_func, equal_func)).
  2320. //! Worst case O(this->size()).
  2321. //!
  2322. //! <b>Throws</b>: If the hasher or equal_func throw.
  2323. //!
  2324. //! <b>Note</b>: This function is used when constructing a value_type
  2325. //! is expensive and the value_type can be compared with a cheaper
  2326. //! key type. Usually this key is part of the value_type.
  2327. template<class KeyType, class KeyHasher, class KeyEqual>
  2328. std::pair<const_iterator,const_iterator> equal_range
  2329. (const KeyType &key, KeyHasher hash_func, KeyEqual equal_func) const
  2330. {
  2331. std::pair<siterator, siterator> ret =
  2332. this->priv_equal_range(key, hash_func, equal_func);
  2333. return std::pair<const_iterator, const_iterator>
  2334. ( const_iterator(ret.first, &this->get_bucket_value_traits())
  2335. , const_iterator(ret.second, &this->get_bucket_value_traits()));
  2336. }
  2337. #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
  2338. //! <b>Requires</b>: value must be an lvalue and shall be in a unordered_set of
  2339. //! appropriate type. Otherwise the behavior is undefined.
  2340. //!
  2341. //! <b>Effects</b>: Returns: a valid iterator belonging to the unordered_set
  2342. //! that points to the value
  2343. //!
  2344. //! <b>Complexity</b>: Constant.
  2345. //!
  2346. //! <b>Throws</b>: If the internal hash function throws.
  2347. iterator iterator_to(reference value);
  2348. //! <b>Requires</b>: value must be an lvalue and shall be in a unordered_set of
  2349. //! appropriate type. Otherwise the behavior is undefined.
  2350. //!
  2351. //! <b>Effects</b>: Returns: a valid const_iterator belonging to the
  2352. //! unordered_set that points to the value
  2353. //!
  2354. //! <b>Complexity</b>: Constant.
  2355. //!
  2356. //! <b>Throws</b>: If the internal hash function throws.
  2357. const_iterator iterator_to(const_reference value) const;
  2358. //! <b>Requires</b>: value must be an lvalue and shall be in a unordered_set of
  2359. //! appropriate type. Otherwise the behavior is undefined.
  2360. //!
  2361. //! <b>Effects</b>: Returns: a valid local_iterator belonging to the unordered_set
  2362. //! that points to the value
  2363. //!
  2364. //! <b>Complexity</b>: Constant.
  2365. //!
  2366. //! <b>Throws</b>: Nothing.
  2367. //!
  2368. //! <b>Note</b>: This static function is available only if the <i>value traits</i>
  2369. //! is stateless.
  2370. static local_iterator s_local_iterator_to(reference value);
  2371. //! <b>Requires</b>: value must be an lvalue and shall be in a unordered_set of
  2372. //! appropriate type. Otherwise the behavior is undefined.
  2373. //!
  2374. //! <b>Effects</b>: Returns: a valid const_local_iterator belonging to
  2375. //! the unordered_set that points to the value
  2376. //!
  2377. //! <b>Complexity</b>: Constant.
  2378. //!
  2379. //! <b>Throws</b>: Nothing.
  2380. //!
  2381. //! <b>Note</b>: This static function is available only if the <i>value traits</i>
  2382. //! is stateless.
  2383. static const_local_iterator s_local_iterator_to(const_reference value);
  2384. //! <b>Requires</b>: value must be an lvalue and shall be in a unordered_set of
  2385. //! appropriate type. Otherwise the behavior is undefined.
  2386. //!
  2387. //! <b>Effects</b>: Returns: a valid local_iterator belonging to the unordered_set
  2388. //! that points to the value
  2389. //!
  2390. //! <b>Complexity</b>: Constant.
  2391. //!
  2392. //! <b>Throws</b>: Nothing.
  2393. local_iterator local_iterator_to(reference value);
  2394. //! <b>Requires</b>: value must be an lvalue and shall be in a unordered_set of
  2395. //! appropriate type. Otherwise the behavior is undefined.
  2396. //!
  2397. //! <b>Effects</b>: Returns: a valid const_local_iterator belonging to
  2398. //! the unordered_set that points to the value
  2399. //!
  2400. //! <b>Complexity</b>: Constant.
  2401. //!
  2402. //! <b>Throws</b>: Nothing.
  2403. const_local_iterator local_iterator_to(const_reference value) const;
  2404. //! <b>Effects</b>: Returns the number of buckets passed in the constructor
  2405. //! or the last rehash function.
  2406. //!
  2407. //! <b>Complexity</b>: Constant.
  2408. //!
  2409. //! <b>Throws</b>: Nothing.
  2410. size_type bucket_count() const;
  2411. //! <b>Requires</b>: n is in the range [0, this->bucket_count()).
  2412. //!
  2413. //! <b>Effects</b>: Returns the number of elements in the nth bucket.
  2414. //!
  2415. //! <b>Complexity</b>: Constant.
  2416. //!
  2417. //! <b>Throws</b>: Nothing.
  2418. size_type bucket_size(size_type n) const;
  2419. #endif //#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
  2420. //! <b>Effects</b>: Returns the index of the bucket in which elements
  2421. //! with keys equivalent to k would be found, if any such element existed.
  2422. //!
  2423. //! <b>Complexity</b>: Constant.
  2424. //!
  2425. //! <b>Throws</b>: If the hash functor throws.
  2426. //!
  2427. //! <b>Note</b>: the return value is in the range [0, this->bucket_count()).
  2428. size_type bucket(const key_type& k) const
  2429. { return this->bucket(k, this->priv_hasher()); }
  2430. //! <b>Requires</b>: "hash_func" must be a hash function that induces
  2431. //! the same hash values as the stored hasher. The difference is that
  2432. //! "hash_func" hashes the given key instead of the value_type.
  2433. //!
  2434. //! <b>Effects</b>: Returns the index of the bucket in which elements
  2435. //! with keys equivalent to k would be found, if any such element existed.
  2436. //!
  2437. //! <b>Complexity</b>: Constant.
  2438. //!
  2439. //! <b>Throws</b>: If hash_func throws.
  2440. //!
  2441. //! <b>Note</b>: the return value is in the range [0, this->bucket_count()).
  2442. template<class KeyType, class KeyHasher>
  2443. size_type bucket(const KeyType& k, KeyHasher hash_func) const
  2444. { return this->priv_hash_to_bucket(hash_func(k)); }
  2445. #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
  2446. //! <b>Effects</b>: Returns the bucket array pointer passed in the constructor
  2447. //! or the last rehash function.
  2448. //!
  2449. //! <b>Complexity</b>: Constant.
  2450. //!
  2451. //! <b>Throws</b>: Nothing.
  2452. bucket_ptr bucket_pointer() const;
  2453. //! <b>Requires</b>: n is in the range [0, this->bucket_count()).
  2454. //!
  2455. //! <b>Effects</b>: Returns a local_iterator pointing to the beginning
  2456. //! of the sequence stored in the bucket n.
  2457. //!
  2458. //! <b>Complexity</b>: Constant.
  2459. //!
  2460. //! <b>Throws</b>: Nothing.
  2461. //!
  2462. //! <b>Note</b>: [this->begin(n), this->end(n)) is a valid range
  2463. //! containing all of the elements in the nth bucket.
  2464. local_iterator begin(size_type n);
  2465. //! <b>Requires</b>: n is in the range [0, this->bucket_count()).
  2466. //!
  2467. //! <b>Effects</b>: Returns a const_local_iterator pointing to the beginning
  2468. //! of the sequence stored in the bucket n.
  2469. //!
  2470. //! <b>Complexity</b>: Constant.
  2471. //!
  2472. //! <b>Throws</b>: Nothing.
  2473. //!
  2474. //! <b>Note</b>: [this->begin(n), this->end(n)) is a valid range
  2475. //! containing all of the elements in the nth bucket.
  2476. const_local_iterator begin(size_type n) const;
  2477. //! <b>Requires</b>: n is in the range [0, this->bucket_count()).
  2478. //!
  2479. //! <b>Effects</b>: Returns a const_local_iterator pointing to the beginning
  2480. //! of the sequence stored in the bucket n.
  2481. //!
  2482. //! <b>Complexity</b>: Constant.
  2483. //!
  2484. //! <b>Throws</b>: Nothing.
  2485. //!
  2486. //! <b>Note</b>: [this->begin(n), this->end(n)) is a valid range
  2487. //! containing all of the elements in the nth bucket.
  2488. const_local_iterator cbegin(size_type n) const;
  2489. //! <b>Requires</b>: n is in the range [0, this->bucket_count()).
  2490. //!
  2491. //! <b>Effects</b>: Returns a local_iterator pointing to the end
  2492. //! of the sequence stored in the bucket n.
  2493. //!
  2494. //! <b>Complexity</b>: Constant.
  2495. //!
  2496. //! <b>Throws</b>: Nothing.
  2497. //!
  2498. //! <b>Note</b>: [this->begin(n), this->end(n)) is a valid range
  2499. //! containing all of the elements in the nth bucket.
  2500. local_iterator end(size_type n);
  2501. //! <b>Requires</b>: n is in the range [0, this->bucket_count()).
  2502. //!
  2503. //! <b>Effects</b>: Returns a const_local_iterator pointing to the end
  2504. //! of the sequence stored in the bucket n.
  2505. //!
  2506. //! <b>Complexity</b>: Constant.
  2507. //!
  2508. //! <b>Throws</b>: Nothing.
  2509. //!
  2510. //! <b>Note</b>: [this->begin(n), this->end(n)) is a valid range
  2511. //! containing all of the elements in the nth bucket.
  2512. const_local_iterator end(size_type n) const;
  2513. //! <b>Requires</b>: n is in the range [0, this->bucket_count()).
  2514. //!
  2515. //! <b>Effects</b>: Returns a const_local_iterator pointing to the end
  2516. //! of the sequence stored in the bucket n.
  2517. //!
  2518. //! <b>Complexity</b>: Constant.
  2519. //!
  2520. //! <b>Throws</b>: Nothing.
  2521. //!
  2522. //! <b>Note</b>: [this->begin(n), this->end(n)) is a valid range
  2523. //! containing all of the elements in the nth bucket.
  2524. const_local_iterator cend(size_type n) const;
  2525. #endif //#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
  2526. //! <b>Requires</b>: new_bucket_traits can hold a pointer to a new bucket array
  2527. //! or the same as the old bucket array with a different length. new_size is the length of the
  2528. //! the array pointed by new_buckets. If new_bucket_traits.bucket_begin() == this->bucket_pointer()
  2529. //! new_bucket_traits.bucket_count() can be bigger or smaller than this->bucket_count().
  2530. //! 'new_bucket_traits' copy constructor should not throw.
  2531. //!
  2532. //! <b>Effects</b>: Updates the internal reference with the new bucket, erases
  2533. //! the values from the old bucket and inserts then in the new one.
  2534. //! Bucket traits hold by *this is assigned from new_bucket_traits.
  2535. //! If the container is configured as incremental<>, the split bucket is set
  2536. //! to the new bucket_count().
  2537. //!
  2538. //! If store_hash option is true, this method does not use the hash function.
  2539. //!
  2540. //! <b>Complexity</b>: Average case linear in this->size(), worst case quadratic.
  2541. //!
  2542. //! <b>Throws</b>: If the hasher functor throws. Basic guarantee.
  2543. void rehash(const bucket_traits &new_bucket_traits)
  2544. {
  2545. const bucket_ptr new_buckets = new_bucket_traits.bucket_begin();
  2546. size_type new_bucket_count = new_bucket_traits.bucket_count();
  2547. const bucket_ptr old_buckets = this->priv_bucket_pointer();
  2548. size_type old_bucket_count = this->priv_bucket_count();
  2549. //Check power of two bucket array if the option is activated
  2550. BOOST_INTRUSIVE_INVARIANT_ASSERT
  2551. (!power_2_buckets || (0 == (new_bucket_count & (new_bucket_count-1u))));
  2552. size_type n = this->priv_get_cache_bucket_num();
  2553. const bool same_buffer = old_buckets == new_buckets;
  2554. //If the new bucket length is a common factor
  2555. //of the old one we can avoid hash calculations.
  2556. const bool fast_shrink = (!incremental) && (old_bucket_count >= new_bucket_count) &&
  2557. (power_2_buckets || (old_bucket_count % new_bucket_count) == 0);
  2558. //If we are shrinking the same bucket array and it's
  2559. //is a fast shrink, just rehash the last nodes
  2560. size_type new_first_bucket_num = new_bucket_count;
  2561. if(same_buffer && fast_shrink && (n < new_bucket_count)){
  2562. new_first_bucket_num = n;
  2563. n = new_bucket_count;
  2564. }
  2565. //Anti-exception stuff: they destroy the elements if something goes wrong.
  2566. //If the source and destination buckets are the same, the second rollback function
  2567. //is harmless, because all elements have been already unlinked and destroyed
  2568. typedef detail::init_disposer<node_algorithms> NodeDisposer;
  2569. typedef detail::exception_array_disposer<bucket_type, NodeDisposer, size_type> ArrayDisposer;
  2570. NodeDisposer node_disp;
  2571. ArrayDisposer rollback1(new_buckets[0], node_disp, new_bucket_count);
  2572. ArrayDisposer rollback2(old_buckets[0], node_disp, old_bucket_count);
  2573. //Put size in a safe value for rollback exception
  2574. size_type const size_backup = this->priv_size_traits().get_size();
  2575. this->priv_size_traits().set_size(0);
  2576. //Put cache to safe position
  2577. this->priv_initialize_cache();
  2578. this->priv_insertion_update_cache(size_type(0u));
  2579. //Iterate through nodes
  2580. for(; n < old_bucket_count; ++n){
  2581. bucket_type &old_bucket = old_buckets[n];
  2582. if(!fast_shrink){
  2583. for( siterator before_i(old_bucket.before_begin()), i(old_bucket.begin()), end_sit(old_bucket.end())
  2584. ; i != end_sit
  2585. ; i = before_i, ++i){
  2586. const value_type &v = this->priv_value_from_slist_node(i.pointed_node());
  2587. const std::size_t hash_value = this->priv_stored_or_compute_hash(v, store_hash_t());
  2588. const size_type new_n = detail::hash_to_bucket_split<power_2_buckets, incremental>
  2589. (hash_value, new_bucket_count, new_bucket_count);
  2590. if(cache_begin && new_n < new_first_bucket_num)
  2591. new_first_bucket_num = new_n;
  2592. siterator const last = (priv_last_in_group)(i);
  2593. if(same_buffer && new_n == n){
  2594. before_i = last;
  2595. }
  2596. else{
  2597. bucket_type &new_b = new_buckets[new_n];
  2598. new_b.splice_after(new_b.before_begin(), old_bucket, before_i, last);
  2599. }
  2600. }
  2601. }
  2602. else{
  2603. const size_type new_n = detail::hash_to_bucket_split<power_2_buckets, incremental>(n, new_bucket_count, new_bucket_count);
  2604. if(cache_begin && new_n < new_first_bucket_num)
  2605. new_first_bucket_num = new_n;
  2606. bucket_type &new_b = new_buckets[new_n];
  2607. new_b.splice_after( new_b.before_begin()
  2608. , old_bucket
  2609. , old_bucket.before_begin()
  2610. , bucket_plus_vtraits_t::priv_get_last(old_bucket, optimize_multikey_t()));
  2611. }
  2612. }
  2613. this->priv_size_traits().set_size(size_backup);
  2614. this->priv_split_traits().set_size(new_bucket_count);
  2615. this->priv_bucket_traits() = new_bucket_traits;
  2616. this->priv_initialize_cache();
  2617. this->priv_insertion_update_cache(new_first_bucket_num);
  2618. rollback1.release();
  2619. rollback2.release();
  2620. }
  2621. //! <b>Requires</b>:
  2622. //!
  2623. //! <b>Effects</b>:
  2624. //!
  2625. //! <b>Complexity</b>:
  2626. //!
  2627. //! <b>Throws</b>:
  2628. //!
  2629. //! <b>Note</b>: this method is only available if incremental<true> option is activated.
  2630. bool incremental_rehash(bool grow = true)
  2631. {
  2632. //This function is only available for containers with incremental hashing
  2633. BOOST_STATIC_ASSERT(( incremental && power_2_buckets ));
  2634. const size_type split_idx = this->priv_split_traits().get_size();
  2635. const size_type bucket_cnt = this->priv_bucket_count();
  2636. const bucket_ptr buck_ptr = this->priv_bucket_pointer();
  2637. bool ret = false;
  2638. if(grow){
  2639. //Test if the split variable can be changed
  2640. if((ret = split_idx < bucket_cnt)){
  2641. const size_type bucket_to_rehash = split_idx - bucket_cnt/2;
  2642. bucket_type &old_bucket = buck_ptr[bucket_to_rehash];
  2643. this->priv_split_traits().increment();
  2644. //Anti-exception stuff: if an exception is thrown while
  2645. //moving elements from old_bucket to the target bucket, all moved
  2646. //elements are moved back to the original one.
  2647. detail::incremental_rehash_rollback<bucket_type, split_traits> rollback
  2648. ( buck_ptr[split_idx], old_bucket, this->priv_split_traits());
  2649. for( siterator before_i(old_bucket.before_begin()), i(old_bucket.begin()), end_sit(old_bucket.end())
  2650. ; i != end_sit; i = before_i, ++i){
  2651. const value_type &v = this->priv_value_from_slist_node(i.pointed_node());
  2652. const std::size_t hash_value = this->priv_stored_or_compute_hash(v, store_hash_t());
  2653. const size_type new_n = this->priv_hash_to_bucket(hash_value);
  2654. siterator const last = (priv_last_in_group)(i);
  2655. if(new_n == bucket_to_rehash){
  2656. before_i = last;
  2657. }
  2658. else{
  2659. bucket_type &new_b = buck_ptr[new_n];
  2660. new_b.splice_after(new_b.before_begin(), old_bucket, before_i, last);
  2661. }
  2662. }
  2663. rollback.release();
  2664. this->priv_erasure_update_cache();
  2665. }
  2666. }
  2667. else if((ret = split_idx > bucket_cnt/2)){ //!grow
  2668. const size_type target_bucket_num = split_idx - 1 - bucket_cnt/2;
  2669. bucket_type &target_bucket = buck_ptr[target_bucket_num];
  2670. bucket_type &source_bucket = buck_ptr[split_idx-1];
  2671. target_bucket.splice_after(target_bucket.cbefore_begin(), source_bucket);
  2672. this->priv_split_traits().decrement();
  2673. this->priv_insertion_update_cache(target_bucket_num);
  2674. }
  2675. return ret;
  2676. }
  2677. //! <b>Effects</b>: If new_bucket_traits.bucket_count() is not
  2678. //! this->bucket_count()/2 or this->bucket_count()*2, or
  2679. //! this->split_bucket() != new_bucket_traits.bucket_count() returns false
  2680. //! and does nothing.
  2681. //!
  2682. //! Otherwise, copy assigns new_bucket_traits to the internal bucket_traits
  2683. //! and transfers all the objects from old buckets to the new ones.
  2684. //!
  2685. //! <b>Complexity</b>: Linear to size().
  2686. //!
  2687. //! <b>Throws</b>: Nothing
  2688. //!
  2689. //! <b>Note</b>: this method is only available if incremental<true> option is activated.
  2690. bool incremental_rehash(const bucket_traits &new_bucket_traits)
  2691. {
  2692. //This function is only available for containers with incremental hashing
  2693. BOOST_STATIC_ASSERT(( incremental && power_2_buckets ));
  2694. size_type const new_bucket_traits_size = new_bucket_traits.bucket_count();
  2695. size_type const cur_bucket_traits = this->priv_bucket_count();
  2696. const size_type split_idx = this->split_count();
  2697. //Test new bucket size is consistent with internal bucket size and split count
  2698. if(new_bucket_traits_size/2 == cur_bucket_traits){
  2699. if(!(split_idx >= cur_bucket_traits))
  2700. return false;
  2701. }
  2702. else if(new_bucket_traits_size == cur_bucket_traits/2){
  2703. if(!(split_idx <= new_bucket_traits_size))
  2704. return false;
  2705. }
  2706. else{
  2707. return false;
  2708. }
  2709. const size_type ini_n = this->priv_get_cache_bucket_num();
  2710. const bucket_ptr old_buckets = this->priv_bucket_pointer();
  2711. this->priv_bucket_traits() = new_bucket_traits;
  2712. if(new_bucket_traits.bucket_begin() != old_buckets){
  2713. for(size_type n = ini_n; n < split_idx; ++n){
  2714. bucket_type &new_bucket = new_bucket_traits.bucket_begin()[n];
  2715. bucket_type &old_bucket = old_buckets[n];
  2716. new_bucket.splice_after(new_bucket.cbefore_begin(), old_bucket);
  2717. }
  2718. //Put cache to safe position
  2719. this->priv_initialize_cache();
  2720. this->priv_insertion_update_cache(ini_n);
  2721. }
  2722. return true;
  2723. }
  2724. #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
  2725. //! <b>Requires</b>: incremental<> option must be set
  2726. //!
  2727. //! <b>Effects</b>: returns the current split count
  2728. //!
  2729. //! <b>Complexity</b>: Constant
  2730. //!
  2731. //! <b>Throws</b>: Nothing
  2732. size_type split_count() const;
  2733. //! <b>Effects</b>: Returns the nearest new bucket count optimized for
  2734. //! the container that is bigger or equal than n. This suggestion can be
  2735. //! used to create bucket arrays with a size that will usually improve
  2736. //! container's performance. If such value does not exist, the
  2737. //! higher possible value is returned.
  2738. //!
  2739. //! <b>Complexity</b>: Amortized constant time.
  2740. //!
  2741. //! <b>Throws</b>: Nothing.
  2742. static size_type suggested_upper_bucket_count(size_type n);
  2743. //! <b>Effects</b>: Returns the nearest new bucket count optimized for
  2744. //! the container that is smaller or equal than n. This suggestion can be
  2745. //! used to create bucket arrays with a size that will usually improve
  2746. //! container's performance. If such value does not exist, the
  2747. //! lowest possible value is returned.
  2748. //!
  2749. //! <b>Complexity</b>: Amortized constant time.
  2750. //!
  2751. //! <b>Throws</b>: Nothing.
  2752. static size_type suggested_lower_bucket_count(size_type n);
  2753. #endif //#if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
  2754. friend bool operator==(const hashtable_impl &x, const hashtable_impl &y)
  2755. {
  2756. //Taken from N3068
  2757. if(constant_time_size && x.size() != y.size()){
  2758. return false;
  2759. }
  2760. for (const_iterator ix = x.cbegin(), ex = x.cend(); ix != ex; ++ix){
  2761. std::pair<const_iterator, const_iterator> eqx(x.equal_range(key_of_value()(*ix))),
  2762. eqy(y.equal_range(key_of_value()(*ix)));
  2763. if (boost::intrusive::iterator_distance(eqx.first, eqx.second) !=
  2764. boost::intrusive::iterator_distance(eqy.first, eqy.second) ||
  2765. !(priv_algo_is_permutation)(eqx.first, eqx.second, eqy.first) ){
  2766. return false;
  2767. }
  2768. ix = eqx.second;
  2769. }
  2770. return true;
  2771. }
  2772. friend bool operator!=(const hashtable_impl &x, const hashtable_impl &y)
  2773. { return !(x == y); }
  2774. friend bool operator<(const hashtable_impl &x, const hashtable_impl &y)
  2775. { return ::boost::intrusive::algo_lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); }
  2776. friend bool operator>(const hashtable_impl &x, const hashtable_impl &y)
  2777. { return y < x; }
  2778. friend bool operator<=(const hashtable_impl &x, const hashtable_impl &y)
  2779. { return !(y < x); }
  2780. friend bool operator>=(const hashtable_impl &x, const hashtable_impl &y)
  2781. { return !(x < y); }
  2782. /// @cond
  2783. void check() const {}
  2784. private:
  2785. template <class MaybeConstHashtableImpl, class Cloner, class Disposer>
  2786. void priv_clone_from(MaybeConstHashtableImpl &src, Cloner cloner, Disposer disposer)
  2787. {
  2788. this->clear_and_dispose(disposer);
  2789. if(!constant_time_size || !src.empty()){
  2790. const size_type src_bucket_count = src.bucket_count();
  2791. const size_type dst_bucket_count = this->bucket_count();
  2792. //Check power of two bucket array if the option is activated
  2793. BOOST_INTRUSIVE_INVARIANT_ASSERT
  2794. (!power_2_buckets || (0 == (src_bucket_count & (src_bucket_count-1))));
  2795. BOOST_INTRUSIVE_INVARIANT_ASSERT
  2796. (!power_2_buckets || (0 == (dst_bucket_count & (dst_bucket_count-1))));
  2797. //If src bucket count is bigger or equal, structural copy is possible
  2798. const bool structural_copy = (!incremental) && (src_bucket_count >= dst_bucket_count) &&
  2799. (power_2_buckets || (src_bucket_count % dst_bucket_count) == 0);
  2800. if(structural_copy){
  2801. this->priv_structural_clone_from(src, cloner, disposer);
  2802. }
  2803. else{
  2804. //Unlike previous cloning algorithm, this can throw
  2805. //if cloner, hasher or comparison functor throw
  2806. typedef typename detail::if_c< detail::is_const<MaybeConstHashtableImpl>::value
  2807. , typename MaybeConstHashtableImpl::const_iterator
  2808. , typename MaybeConstHashtableImpl::iterator
  2809. >::type clone_iterator;
  2810. clone_iterator b(src.begin()), e(src.end());
  2811. detail::exception_disposer<hashtable_impl, Disposer> rollback(*this, disposer);
  2812. for(; b != e; ++b){
  2813. //No need to check for duplicates and insert it in the first position
  2814. //as this is an unordered container. So use minimal insertion code
  2815. std::size_t const hash_to_store = this->priv_stored_or_compute_hash(*b, store_hash_t());;
  2816. size_type const bucket_number = this->priv_hash_to_bucket(hash_to_store);
  2817. typedef typename detail::if_c
  2818. <detail::is_const<MaybeConstHashtableImpl>::value, const_reference, reference>::type reference_type;
  2819. reference_type r = *b;
  2820. this->priv_clone_front_in_bucket<reference_type>(bucket_number, r, hash_to_store, cloner);
  2821. }
  2822. rollback.release();
  2823. }
  2824. }
  2825. }
  2826. template<class ValueReference, class Cloner>
  2827. void priv_clone_front_in_bucket( size_type const bucket_number
  2828. , typename detail::identity<ValueReference>::type src_ref
  2829. , std::size_t const hash_to_store, Cloner cloner)
  2830. {
  2831. //No need to check for duplicates and insert it in the first position
  2832. //as this is an unordered container. So use minimal insertion code
  2833. //std::size_t const hash_value = this->priv_stored_or_compute_hash(src_ref, store_hash_t());;
  2834. //size_type const bucket_number = this->priv_hash_to_bucket(hash_value);
  2835. bucket_type &cur_bucket = this->priv_bucket_pointer()[bucket_number];
  2836. siterator const prev(cur_bucket.before_begin());
  2837. //Just check if the cloned node is equal to the first inserted value in the new bucket
  2838. //as equal src values were contiguous and they should be already inserted in the
  2839. //destination bucket.
  2840. bool const next_is_in_group = optimize_multikey && !cur_bucket.empty() &&
  2841. this->priv_equal()( key_of_value()(src_ref)
  2842. , key_of_value()(this->priv_value_from_slist_node((++siterator(prev)).pointed_node())));
  2843. this->priv_insert_equal_after_find(*cloner(src_ref), bucket_number, hash_to_store, prev, next_is_in_group);
  2844. }
  2845. template <class MaybeConstHashtableImpl, class Cloner, class Disposer>
  2846. void priv_structural_clone_from(MaybeConstHashtableImpl &src, Cloner cloner, Disposer disposer)
  2847. {
  2848. //First clone the first ones
  2849. const size_type src_bucket_count = src.bucket_count();
  2850. const size_type dst_bucket_count = this->bucket_count();
  2851. const bucket_ptr src_buckets = src.priv_bucket_pointer();
  2852. const bucket_ptr dst_buckets = this->priv_bucket_pointer();
  2853. size_type constructed = 0;
  2854. typedef node_cast_adaptor< detail::node_disposer<Disposer, value_traits, CircularSListAlgorithms>
  2855. , slist_node_ptr, node_ptr > NodeDisposer;
  2856. NodeDisposer node_disp(disposer, &this->priv_value_traits());
  2857. detail::exception_array_disposer<bucket_type, NodeDisposer, size_type>
  2858. rollback(dst_buckets[0], node_disp, constructed);
  2859. //Now insert the remaining ones using the modulo trick
  2860. for( //"constructed" already initialized
  2861. ; constructed < src_bucket_count
  2862. ; ++constructed){
  2863. //Since incremental hashing can't be structurally copied, avoid hash_to_bucket_split
  2864. const std::size_t new_n = detail::hash_to_bucket(constructed, dst_bucket_count, detail::bool_<power_2_buckets>());
  2865. bucket_type &src_b = src_buckets[constructed];
  2866. for( siterator b(src_b.begin()), e(src_b.end()); b != e; ++b){
  2867. slist_node_ptr const n(b.pointed_node());
  2868. typedef typename detail::if_c
  2869. <detail::is_const<MaybeConstHashtableImpl>::value, const_reference, reference>::type reference_type;
  2870. reference_type r = this->priv_value_from_slist_node(n);
  2871. this->priv_clone_front_in_bucket<reference_type>
  2872. (new_n, r, this->priv_stored_hash(n, store_hash_t()), cloner);
  2873. }
  2874. }
  2875. this->priv_hasher() = src.priv_hasher();
  2876. this->priv_equal() = src.priv_equal();
  2877. rollback.release();
  2878. this->priv_size_traits().set_size(src.priv_size_traits().get_size());
  2879. this->priv_split_traits().set_size(dst_bucket_count);
  2880. this->priv_insertion_update_cache(0u);
  2881. this->priv_erasure_update_cache();
  2882. }
  2883. std::size_t priv_hash_to_bucket(std::size_t hash_value) const
  2884. {
  2885. return detail::hash_to_bucket_split<power_2_buckets, incremental>
  2886. (hash_value, this->priv_bucket_traits().bucket_count(), this->priv_split_traits().get_size());
  2887. }
  2888. iterator priv_insert_equal_after_find(reference value, size_type bucket_num, std::size_t hash_value, siterator prev, bool const next_is_in_group)
  2889. {
  2890. //Now store hash if needed
  2891. node_ptr n = pointer_traits<node_ptr>::pointer_to(this->priv_value_to_node(value));
  2892. node_functions_t::store_hash(n, hash_value, store_hash_t());
  2893. //Checks for some modes
  2894. BOOST_INTRUSIVE_SAFE_HOOK_DEFAULT_ASSERT(!safemode_or_autounlink || node_algorithms::unique(n));
  2895. //Shortcut to optimize_multikey cases
  2896. group_functions_t::insert_in_group
  2897. ( next_is_in_group ? detail::dcast_bucket_ptr<node>((++siterator(prev)).pointed_node()) : n
  2898. , n, optimize_multikey_t());
  2899. //Update cache and increment size if needed
  2900. this->priv_insertion_update_cache(bucket_num);
  2901. this->priv_size_traits().increment();
  2902. //Insert the element in the bucket after it
  2903. return iterator(bucket_type::s_insert_after(prev, *n), &this->get_bucket_value_traits());
  2904. }
  2905. template<class KeyType, class KeyHasher, class KeyEqual>
  2906. siterator priv_find //In case it is not found previt is bucket.before_begin()
  2907. ( const KeyType &key, KeyHasher hash_func
  2908. , KeyEqual equal_func, size_type &bucket_number, std::size_t &h, siterator &previt) const
  2909. {
  2910. h = hash_func(key);
  2911. return this->priv_find_with_hash(key, equal_func, bucket_number, h, previt);
  2912. }
  2913. template<class KeyType, class KeyEqual>
  2914. bool priv_is_value_equal_to_key(const value_type &v, const std::size_t h, const KeyType &key, KeyEqual equal_func) const
  2915. {
  2916. (void)h;
  2917. return (!compare_hash || this->priv_stored_or_compute_hash(v, store_hash_t()) == h) && equal_func(key, key_of_value()(v));
  2918. }
  2919. //return previous iterator to the next equal range group in case
  2920. static siterator priv_last_in_group(const siterator &it_first_in_group)
  2921. {
  2922. return bucket_type::s_iterator_to
  2923. (*group_functions_t::get_last_in_group
  2924. (detail::dcast_bucket_ptr<node>(it_first_in_group.pointed_node()), optimize_multikey_t()));
  2925. }
  2926. template<class KeyType, class KeyEqual>
  2927. siterator priv_find_with_hash //In case it is not found previt is bucket.before_begin()
  2928. ( const KeyType &key, KeyEqual equal_func, size_type &bucket_number, const std::size_t h, siterator &previt) const
  2929. {
  2930. bucket_number = this->priv_hash_to_bucket(h);
  2931. bucket_type &b = this->priv_bucket_pointer()[bucket_number];
  2932. previt = b.before_begin();
  2933. siterator it = previt;
  2934. siterator const endit = b.end();
  2935. while(++it != endit){
  2936. if(this->priv_is_value_equal_to_key(this->priv_value_from_slist_node(it.pointed_node()), h, key, equal_func)){
  2937. return it;
  2938. }
  2939. previt = it = (priv_last_in_group)(it);
  2940. }
  2941. previt = b.before_begin();
  2942. return this->priv_invalid_local_it();
  2943. }
  2944. template<class KeyType, class KeyHasher, class KeyEqual>
  2945. std::pair<siterator, siterator> priv_local_equal_range
  2946. ( const KeyType &key
  2947. , KeyHasher hash_func
  2948. , KeyEqual equal_func
  2949. , size_type &found_bucket
  2950. , size_type &cnt) const
  2951. {
  2952. cnt = 0;
  2953. //Let's see if the element is present
  2954. siterator prev;
  2955. size_type n_bucket;
  2956. std::size_t h;
  2957. std::pair<siterator, siterator> to_return
  2958. ( this->priv_find(key, hash_func, equal_func, n_bucket, h, prev)
  2959. , this->priv_invalid_local_it());
  2960. if(to_return.first != to_return.second){
  2961. found_bucket = n_bucket;
  2962. //If it's present, find the first that it's not equal in
  2963. //the same bucket
  2964. bucket_type &b = this->priv_bucket_pointer()[n_bucket];
  2965. siterator it = to_return.first;
  2966. ++cnt; //At least one is found
  2967. if(optimize_multikey){
  2968. to_return.second = ++(priv_last_in_group)(it);
  2969. cnt += boost::intrusive::iterator_distance(++it, to_return.second);
  2970. }
  2971. else{
  2972. siterator const bend = b.end();
  2973. while(++it != bend &&
  2974. this->priv_is_value_equal_to_key(this->priv_value_from_slist_node(it.pointed_node()), h, key, equal_func)){
  2975. ++cnt;
  2976. }
  2977. to_return.second = it;
  2978. }
  2979. }
  2980. return to_return;
  2981. }
  2982. template<class KeyType, class KeyHasher, class KeyEqual>
  2983. std::pair<siterator, siterator> priv_equal_range
  2984. ( const KeyType &key
  2985. , KeyHasher hash_func
  2986. , KeyEqual equal_func) const
  2987. {
  2988. size_type n_bucket;
  2989. size_type cnt;
  2990. //Let's see if the element is present
  2991. std::pair<siterator, siterator> to_return
  2992. (this->priv_local_equal_range(key, hash_func, equal_func, n_bucket, cnt));
  2993. //If not, find the next element as ".second" if ".second" local iterator
  2994. //is not pointing to an element.
  2995. bucket_ptr const bp = this->priv_bucket_pointer();
  2996. if(to_return.first != to_return.second &&
  2997. to_return.second == bp[n_bucket].end()){
  2998. to_return.second = this->priv_invalid_local_it();
  2999. ++n_bucket;
  3000. for( const size_type max_bucket = this->priv_bucket_count()
  3001. ; n_bucket != max_bucket
  3002. ; ++n_bucket){
  3003. bucket_type &b = bp[n_bucket];
  3004. if(!b.empty()){
  3005. to_return.second = b.begin();
  3006. break;
  3007. }
  3008. }
  3009. }
  3010. return to_return;
  3011. }
  3012. std::size_t priv_get_bucket_num(siterator it)
  3013. { return this->priv_get_bucket_num_hash_dispatch(it, store_hash_t()); }
  3014. std::size_t priv_get_bucket_num_hash_dispatch(siterator it, detail::true_) //store_hash
  3015. {
  3016. return this->priv_hash_to_bucket
  3017. (this->priv_stored_hash(it.pointed_node(), store_hash_t()));
  3018. }
  3019. std::size_t priv_get_bucket_num_hash_dispatch(siterator it, detail::false_) //NO store_hash
  3020. { return this->priv_get_bucket_num_no_hash_store(it, optimize_multikey_t()); }
  3021. static siterator priv_get_previous(bucket_type &b, siterator i)
  3022. { return bucket_plus_vtraits_t::priv_get_previous(b, i, optimize_multikey_t()); }
  3023. /// @endcond
  3024. };
  3025. /// @cond
  3026. #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
  3027. template < class T
  3028. , bool UniqueKeys
  3029. , class PackedOptions
  3030. >
  3031. #else
  3032. template <class T, bool UniqueKeys, class ...Options>
  3033. #endif
  3034. struct make_bucket_traits
  3035. {
  3036. //Real value traits must be calculated from options
  3037. typedef typename detail::get_value_traits
  3038. <T, typename PackedOptions::proto_value_traits>::type value_traits;
  3039. typedef typename PackedOptions::bucket_traits specified_bucket_traits;
  3040. //Real bucket traits must be calculated from options and calculated value_traits
  3041. typedef typename detail::get_slist_impl
  3042. <typename detail::reduced_slist_node_traits
  3043. <typename value_traits::node_traits>::type
  3044. >::type slist_impl;
  3045. typedef typename
  3046. detail::if_c< detail::is_same
  3047. < specified_bucket_traits
  3048. , default_bucket_traits
  3049. >::value
  3050. , detail::bucket_traits_impl<slist_impl>
  3051. , specified_bucket_traits
  3052. >::type type;
  3053. };
  3054. /// @endcond
  3055. //! Helper metafunction to define a \c hashtable that yields to the same type when the
  3056. //! same options (either explicitly or implicitly) are used.
  3057. #if defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED) || defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
  3058. template<class T, class ...Options>
  3059. #else
  3060. template<class T, class O1 = void, class O2 = void
  3061. , class O3 = void, class O4 = void
  3062. , class O5 = void, class O6 = void
  3063. , class O7 = void, class O8 = void
  3064. , class O9 = void, class O10= void
  3065. >
  3066. #endif
  3067. struct make_hashtable
  3068. {
  3069. /// @cond
  3070. typedef typename pack_options
  3071. < hashtable_defaults,
  3072. #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
  3073. O1, O2, O3, O4, O5, O6, O7, O8, O9, O10
  3074. #else
  3075. Options...
  3076. #endif
  3077. >::type packed_options;
  3078. typedef typename detail::get_value_traits
  3079. <T, typename packed_options::proto_value_traits>::type value_traits;
  3080. typedef typename make_bucket_traits
  3081. <T, false, packed_options>::type bucket_traits;
  3082. typedef hashtable_impl
  3083. < value_traits
  3084. , typename packed_options::key_of_value
  3085. , typename packed_options::hash
  3086. , typename packed_options::equal
  3087. , bucket_traits
  3088. , typename packed_options::size_type
  3089. , (std::size_t(false)*hash_bool_flags::unique_keys_pos)
  3090. |(std::size_t(packed_options::constant_time_size)*hash_bool_flags::constant_time_size_pos)
  3091. |(std::size_t(packed_options::power_2_buckets)*hash_bool_flags::power_2_buckets_pos)
  3092. |(std::size_t(packed_options::cache_begin)*hash_bool_flags::cache_begin_pos)
  3093. |(std::size_t(packed_options::compare_hash)*hash_bool_flags::compare_hash_pos)
  3094. |(std::size_t(packed_options::incremental)*hash_bool_flags::incremental_pos)
  3095. > implementation_defined;
  3096. /// @endcond
  3097. typedef implementation_defined type;
  3098. };
  3099. #if !defined(BOOST_INTRUSIVE_DOXYGEN_INVOKED)
  3100. #if defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
  3101. template<class T, class ...Options>
  3102. #else
  3103. template<class T, class O1, class O2, class O3, class O4, class O5, class O6, class O7, class O8, class O9, class O10>
  3104. #endif
  3105. class hashtable
  3106. : public make_hashtable<T,
  3107. #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
  3108. O1, O2, O3, O4, O5, O6, O7, O8, O9, O10
  3109. #else
  3110. Options...
  3111. #endif
  3112. >::type
  3113. {
  3114. typedef typename make_hashtable<T,
  3115. #if !defined(BOOST_INTRUSIVE_VARIADIC_TEMPLATES)
  3116. O1, O2, O3, O4, O5, O6, O7, O8, O9, O10
  3117. #else
  3118. Options...
  3119. #endif
  3120. >::type Base;
  3121. BOOST_MOVABLE_BUT_NOT_COPYABLE(hashtable)
  3122. public:
  3123. typedef typename Base::value_traits value_traits;
  3124. typedef typename Base::iterator iterator;
  3125. typedef typename Base::const_iterator const_iterator;
  3126. typedef typename Base::bucket_ptr bucket_ptr;
  3127. typedef typename Base::size_type size_type;
  3128. typedef typename Base::hasher hasher;
  3129. typedef typename Base::bucket_traits bucket_traits;
  3130. typedef typename Base::key_equal key_equal;
  3131. //Assert if passed value traits are compatible with the type
  3132. BOOST_STATIC_ASSERT((detail::is_same<typename value_traits::value_type, T>::value));
  3133. explicit hashtable ( const bucket_traits &b_traits
  3134. , const hasher & hash_func = hasher()
  3135. , const key_equal &equal_func = key_equal()
  3136. , const value_traits &v_traits = value_traits())
  3137. : Base(b_traits, hash_func, equal_func, v_traits)
  3138. {}
  3139. hashtable(BOOST_RV_REF(hashtable) x)
  3140. : Base(BOOST_MOVE_BASE(Base, x))
  3141. {}
  3142. hashtable& operator=(BOOST_RV_REF(hashtable) x)
  3143. { return static_cast<hashtable&>(this->Base::operator=(BOOST_MOVE_BASE(Base, x))); }
  3144. template <class Cloner, class Disposer>
  3145. void clone_from(const hashtable &src, Cloner cloner, Disposer disposer)
  3146. { Base::clone_from(src, cloner, disposer); }
  3147. template <class Cloner, class Disposer>
  3148. void clone_from(BOOST_RV_REF(hashtable) src, Cloner cloner, Disposer disposer)
  3149. { Base::clone_from(BOOST_MOVE_BASE(Base, src), cloner, disposer); }
  3150. };
  3151. #endif
  3152. } //namespace intrusive
  3153. } //namespace boost
  3154. #include <boost/intrusive/detail/config_end.hpp>
  3155. #endif //BOOST_INTRUSIVE_HASHTABLE_HPP