hashtable.hpp 181 KB

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