hashtable.hpp 154 KB

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