123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088 |
- #if !defined(phmap_base_h_guard_)
- #define phmap_base_h_guard_
- // ---------------------------------------------------------------------------
- // Copyright (c) 2019, Gregory Popovitch - [email protected]
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // https://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- //
- // Includes work from abseil-cpp (https://github.com/abseil/abseil-cpp)
- // with modifications.
- //
- // Copyright 2018 The Abseil Authors.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // https://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- // ---------------------------------------------------------------------------
- #include <algorithm>
- #include <cassert>
- #include <cstddef>
- #include <initializer_list>
- #include <iterator>
- #include <string>
- #include <type_traits>
- #include <utility>
- #include <functional>
- #include <tuple>
- #include <utility>
- #include <memory>
- #include <mutex> // for std::lock
- #include "phmap_config.h"
- #ifdef PHMAP_HAVE_SHARED_MUTEX
- #include <shared_mutex> // after "phmap_config.h"
- #endif
- #ifdef _MSC_VER
- #pragma warning(push)
- #pragma warning(disable : 4514) // unreferenced inline function has been removed
- #pragma warning(disable : 4582) // constructor is not implicitly called
- #pragma warning(disable : 4625) // copy constructor was implicitly defined as deleted
- #pragma warning(disable : 4626) // assignment operator was implicitly defined as deleted
- #pragma warning(disable : 4710) // function not inlined
- #pragma warning(disable : 4711) // selected for automatic inline expansion
- #pragma warning(disable : 4820) // '6' bytes padding added after data member
- #endif // _MSC_VER
- namespace phmap {
- template <class T> using Allocator = typename std::allocator<T>;
- template<class T1, class T2> using Pair = typename std::pair<T1, T2>;
- template <class T>
- struct EqualTo
- {
- LL_INLINE bool operator()(const T& a, const T& b) const
- {
- return std::equal_to<T>()(a, b);
- }
- };
- template <class T>
- struct Less
- {
- LL_INLINE bool operator()(const T& a, const T& b) const
- {
- return std::less<T>()(a, b);
- }
- };
- namespace type_traits_internal {
- template <typename... Ts>
- struct VoidTImpl {
- using type = void;
- };
- // NOTE: The `is_detected` family of templates here differ from the library
- // fundamentals specification in that for library fundamentals, `Op<Args...>` is
- // evaluated as soon as the type `is_detected<Op, Args...>` undergoes
- // substitution, regardless of whether or not the `::value` is accessed. That
- // is inconsistent with all other standard traits and prevents lazy evaluation
- // in larger contexts (such as if the `is_detected` check is a trailing argument
- // of a `conjunction`. This implementation opts to instead be lazy in the same
- // way that the standard traits are (this "defect" of the detection idiom
- // specifications has been reported).
- // ---------------------------------------------------------------------------
- template <class Enabler, template <class...> class Op, class... Args>
- struct is_detected_impl {
- using type = std::false_type;
- };
- template <template <class...> class Op, class... Args>
- struct is_detected_impl<typename VoidTImpl<Op<Args...>>::type, Op, Args...> {
- using type = std::true_type;
- };
- template <template <class...> class Op, class... Args>
- struct is_detected : is_detected_impl<void, Op, Args...>::type {};
- template <class Enabler, class To, template <class...> class Op, class... Args>
- struct is_detected_convertible_impl {
- using type = std::false_type;
- };
- template <class To, template <class...> class Op, class... Args>
- struct is_detected_convertible_impl<
- typename std::enable_if<std::is_convertible<Op<Args...>, To>::value>::type,
- To, Op, Args...> {
- using type = std::true_type;
- };
- template <class To, template <class...> class Op, class... Args>
- struct is_detected_convertible
- : is_detected_convertible_impl<void, To, Op, Args...>::type {};
- template <typename T>
- using IsCopyAssignableImpl =
- decltype(std::declval<T&>() = std::declval<const T&>());
- template <typename T>
- using IsMoveAssignableImpl = decltype(std::declval<T&>() = std::declval<T&&>());
- } // namespace type_traits_internal
- template <typename T>
- struct is_copy_assignable : type_traits_internal::is_detected<
- type_traits_internal::IsCopyAssignableImpl, T> {
- };
- template <typename T>
- struct is_move_assignable : type_traits_internal::is_detected<
- type_traits_internal::IsMoveAssignableImpl, T> {
- };
- // ---------------------------------------------------------------------------
- // void_t()
- //
- // Ignores the type of any its arguments and returns `void`. In general, this
- // metafunction allows you to create a general case that maps to `void` while
- // allowing specializations that map to specific types.
- //
- // This metafunction is designed to be a drop-in replacement for the C++17
- // `std::void_t` metafunction.
- //
- // NOTE: `phmap::void_t` does not use the standard-specified implementation so
- // that it can remain compatible with gcc < 5.1. This can introduce slightly
- // different behavior, such as when ordering partial specializations.
- // ---------------------------------------------------------------------------
- template <typename... Ts>
- using void_t = typename type_traits_internal::VoidTImpl<Ts...>::type;
- // ---------------------------------------------------------------------------
- // conjunction
- //
- // Performs a compile-time logical AND operation on the passed types (which
- // must have `::value` members convertible to `bool`. Short-circuits if it
- // encounters any `false` members (and does not compare the `::value` members
- // of any remaining arguments).
- //
- // This metafunction is designed to be a drop-in replacement for the C++17
- // `std::conjunction` metafunction.
- // ---------------------------------------------------------------------------
- template <typename... Ts>
- struct conjunction;
- template <typename T, typename... Ts>
- struct conjunction<T, Ts...>
- : std::conditional<T::value, conjunction<Ts...>, T>::type {};
- template <typename T>
- struct conjunction<T> : T {};
- template <>
- struct conjunction<> : std::true_type {};
- // Workaround for "deprecated builtins" warnings with clang v15+. HB
- #if defined(__clang__)
- # pragma clang diagnostic push
- # pragma clang diagnostic ignored "-Wunknown-warning-option"
- # pragma clang diagnostic ignored "-Wdeprecated-builtins"
- #endif
- // ---------------------------------------------------------------------------
- // disjunction
- //
- // Performs a compile-time logical OR operation on the passed types (which
- // must have `::value` members convertible to `bool`. Short-circuits if it
- // encounters any `true` members (and does not compare the `::value` members
- // of any remaining arguments).
- //
- // This metafunction is designed to be a drop-in replacement for the C++17
- // `std::disjunction` metafunction.
- // ---------------------------------------------------------------------------
- template <typename... Ts>
- struct disjunction;
- template <typename T, typename... Ts>
- struct disjunction<T, Ts...> :
- std::conditional<T::value, T, disjunction<Ts...>>::type {};
- template <typename T>
- struct disjunction<T> : T {};
- template <>
- struct disjunction<> : std::false_type {};
- template <typename T>
- struct negation : std::integral_constant<bool, !T::value> {};
- #if defined(__clang__)
- # pragma clang diagnostic pop
- #endif
- // -----------------------------------------------------------------------------
- // C++14 "_t" trait aliases
- // -----------------------------------------------------------------------------
- template <typename T>
- using remove_cv_t = typename std::remove_cv<T>::type;
- template <typename T>
- using remove_const_t = typename std::remove_const<T>::type;
- template <typename T>
- using remove_volatile_t = typename std::remove_volatile<T>::type;
- template <typename T>
- using add_cv_t = typename std::add_cv<T>::type;
- template <typename T>
- using add_const_t = typename std::add_const<T>::type;
- template <typename T>
- using add_volatile_t = typename std::add_volatile<T>::type;
- template <typename T>
- using remove_reference_t = typename std::remove_reference<T>::type;
- template <typename T>
- using add_lvalue_reference_t = typename std::add_lvalue_reference<T>::type;
- template <typename T>
- using add_rvalue_reference_t = typename std::add_rvalue_reference<T>::type;
- template <typename T>
- using remove_pointer_t = typename std::remove_pointer<T>::type;
- template <typename T>
- using add_pointer_t = typename std::add_pointer<T>::type;
- template <typename T>
- using make_signed_t = typename std::make_signed<T>::type;
- template <typename T>
- using make_unsigned_t = typename std::make_unsigned<T>::type;
- template <typename T>
- using remove_extent_t = typename std::remove_extent<T>::type;
- template <typename T>
- using remove_all_extents_t = typename std::remove_all_extents<T>::type;
- template<std::size_t Len, std::size_t Align>
- struct aligned_storage {
- struct type {
- alignas(Align) unsigned char data[Len];
- };
- };
- template< std::size_t Len, std::size_t Align>
- using aligned_storage_t = typename aligned_storage<Len, Align>::type;
- template <typename T>
- using decay_t = typename std::decay<T>::type;
- template <bool B, typename T = void>
- using enable_if_t = typename std::enable_if<B, T>::type;
- template <bool B, typename T, typename F>
- using conditional_t = typename std::conditional<B, T, F>::type;
- template <typename... T>
- using common_type_t = typename std::common_type<T...>::type;
- template <typename T>
- using underlying_type_t = typename std::underlying_type<T>::type;
- template< class F, class... ArgTypes>
- #if PHMAP_HAVE_CC17 && defined(__cpp_lib_result_of_sfinae)
- using invoke_result_t = typename std::invoke_result_t<F, ArgTypes...>;
- #else
- using invoke_result_t = typename std::result_of<F(ArgTypes...)>::type;
- #endif
- namespace type_traits_internal {
- // ----------------------------------------------------------------------
- // In MSVC we can't probe std::hash or stdext::hash because it triggers a
- // static_assert instead of failing substitution. Libc++ prior to 4.0
- // also used a static_assert.
- // ----------------------------------------------------------------------
- #if defined(_MSC_VER) || (defined(_LIBCPP_VERSION) && \
- _LIBCPP_VERSION < 4000 && _LIBCPP_STD_VER > 11)
- #define PHMAP_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ 0
- #else
- #define PHMAP_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ 1
- #endif
- #if !PHMAP_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
- template <typename Key, typename = size_t>
- struct IsHashable : std::true_type {};
- #else // PHMAP_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
- template <typename Key, typename = void>
- struct IsHashable : std::false_type {};
- template <typename Key>
- struct IsHashable<Key,
- phmap::enable_if_t<std::is_convertible<
- decltype(std::declval<std::hash<Key>&>()(std::declval<Key const&>())),
- std::size_t>::value>> : std::true_type {};
- #endif
- struct AssertHashEnabledHelper
- {
- private:
- static void Sink(...) {}
- struct NAT {};
- template <class Key>
- static auto GetReturnType(int)
- -> decltype(std::declval<std::hash<Key>>()(std::declval<Key const&>()));
- template <class Key>
- static NAT GetReturnType(...);
- template <class Key>
- static std::nullptr_t DoIt() {
- static_assert(IsHashable<Key>::value,
- "std::hash<Key> does not provide a call operator");
- static_assert(
- std::is_default_constructible<std::hash<Key>>::value,
- "std::hash<Key> must be default constructible when it is enabled");
- static_assert(
- std::is_copy_constructible<std::hash<Key>>::value,
- "std::hash<Key> must be copy constructible when it is enabled");
- static_assert(phmap::is_copy_assignable<std::hash<Key>>::value,
- "std::hash<Key> must be copy assignable when it is enabled");
- // is_destructible is unchecked as it's implied by each of the
- // is_constructible checks.
- using ReturnType = decltype(GetReturnType<Key>(0));
- static_assert(std::is_same<ReturnType, NAT>::value ||
- std::is_same<ReturnType, size_t>::value,
- "std::hash<Key> must return size_t");
- return nullptr;
- }
- template <class... Ts>
- friend void AssertHashEnabled();
- };
- template <class... Ts>
- LL_INLINE void AssertHashEnabled
- ()
- {
- using Helper = AssertHashEnabledHelper;
- Helper::Sink(Helper::DoIt<Ts>()...);
- }
- } // namespace type_traits_internal
- } // namespace phmap
- // -----------------------------------------------------------------------------
- // hash_policy_traits
- // -----------------------------------------------------------------------------
- namespace phmap {
- namespace priv {
- // Defines how slots are initialized/destroyed/moved.
- template <class Policy, class = void>
- struct hash_policy_traits
- {
- private:
- struct ReturnKey
- {
- // We return `Key` here.
- // When Key=T&, we forward the lvalue reference.
- // When Key=T, we return by value to avoid a dangling reference.
- // eg, for string_hash_map.
- template <class Key, class... Args>
- Key operator()(Key&& k, const Args&...) const {
- return std::forward<Key>(k);
- }
- };
- template <class P = Policy, class = void>
- struct ConstantIteratorsImpl : std::false_type {};
- template <class P>
- struct ConstantIteratorsImpl<P, phmap::void_t<typename P::constant_iterators>>
- : P::constant_iterators {};
- public:
- // The actual object stored in the hash table.
- using slot_type = typename Policy::slot_type;
- // The type of the keys stored in the hashtable.
- using key_type = typename Policy::key_type;
- // The argument type for insertions into the hashtable. This is different
- // from value_type for increased performance. See initializer_list constructor
- // and insert() member functions for more details.
- using init_type = typename Policy::init_type;
- using reference = decltype(Policy::element(std::declval<slot_type*>()));
- using pointer = typename std::remove_reference<reference>::type*;
- using value_type = typename std::remove_reference<reference>::type;
- // Policies can set this variable to tell raw_hash_set that all iterators
- // should be constant, even `iterator`. This is useful for set-like
- // containers.
- // Defaults to false if not provided by the policy.
- using constant_iterators = ConstantIteratorsImpl<>;
- // PRECONDITION: `slot` is UNINITIALIZED
- // POSTCONDITION: `slot` is INITIALIZED
- template <class Alloc, class... Args>
- static void construct(Alloc* alloc, slot_type* slot, Args&&... args) {
- Policy::construct(alloc, slot, std::forward<Args>(args)...);
- }
- // PRECONDITION: `slot` is INITIALIZED
- // POSTCONDITION: `slot` is UNINITIALIZED
- template <class Alloc>
- static void destroy(Alloc* alloc, slot_type* slot) {
- Policy::destroy(alloc, slot);
- }
- // Transfers the `old_slot` to `new_slot`. Any memory allocated by the
- // allocator inside `old_slot` to `new_slot` can be transferred.
- //
- // OPTIONAL: defaults to:
- //
- // clone(new_slot, std::move(*old_slot));
- // destroy(old_slot);
- //
- // PRECONDITION: `new_slot` is UNINITIALIZED and `old_slot` is INITIALIZED
- // POSTCONDITION: `new_slot` is INITIALIZED and `old_slot` is
- // UNINITIALIZED
- template <class Alloc>
- static void transfer(Alloc* alloc, slot_type* new_slot, slot_type* old_slot) {
- transfer_impl(alloc, new_slot, old_slot, 0);
- }
- // PRECONDITION: `slot` is INITIALIZED
- // POSTCONDITION: `slot` is INITIALIZED
- template <class P = Policy>
- static auto element(slot_type* slot) -> decltype(P::element(slot)) {
- return P::element(slot);
- }
- // Returns the amount of memory owned by `slot`, exclusive of `sizeof(*slot)`.
- //
- // If `slot` is nullptr, returns the constant amount of memory owned by any
- // full slot or -1 if slots own variable amounts of memory.
- //
- // PRECONDITION: `slot` is INITIALIZED or nullptr
- template <class P = Policy>
- static size_t space_used(const slot_type* slot) {
- return P::space_used(slot);
- }
- // Provides generalized access to the key for elements, both for elements in
- // the table and for elements that have not yet been inserted (or even
- // constructed). We would like an API that allows us to say: `key(args...)`
- // but we cannot do that for all cases, so we use this more general API that
- // can be used for many things, including the following:
- //
- // - Given an element in a table, get its key.
- // - Given an element initializer, get its key.
- // - Given `emplace()` arguments, get the element key.
- //
- // Implementations of this must adhere to a very strict technical
- // specification around aliasing and consuming arguments:
- //
- // Let `value_type` be the result type of `element()` without ref- and
- // cv-qualifiers. The first argument is a functor, the rest are constructor
- // arguments for `value_type`. Returns `std::forward<F>(f)(k, xs...)`, where
- // `k` is the element key, and `xs...` are the new constructor arguments for
- // `value_type`. It's allowed for `k` to alias `xs...`, and for both to alias
- // `ts...`. The key won't be touched once `xs...` are used to construct an
- // element; `ts...` won't be touched at all, which allows `apply()` to consume
- // any rvalues among them.
- //
- // If `value_type` is constructible from `Ts&&...`, `Policy::apply()` must not
- // trigger a hard compile error unless it originates from `f`. In other words,
- // `Policy::apply()` must be SFINAE-friendly. If `value_type` is not
- // constructible from `Ts&&...`, either SFINAE or a hard compile error is OK.
- //
- // If `Ts...` is `[cv] value_type[&]` or `[cv] init_type[&]`,
- // `Policy::apply()` must work. A compile error is not allowed, SFINAE or not.
- template <class F, class... Ts, class P = Policy>
- static auto apply(F&& f, Ts&&... ts)
- -> decltype(P::apply(std::forward<F>(f), std::forward<Ts>(ts)...)) {
- return P::apply(std::forward<F>(f), std::forward<Ts>(ts)...);
- }
- // Returns the "key" portion of the slot.
- // Used for node handle manipulation.
- template <class P = Policy>
- static auto key(slot_type* slot)
- -> decltype(P::apply(ReturnKey(), element(slot))) {
- return P::apply(ReturnKey(), element(slot));
- }
- // Returns the "value" (as opposed to the "key") portion of the element. Used
- // by maps to implement `operator[]`, `at()` and `insert_or_assign()`.
- template <class T, class P = Policy>
- static auto value(T* elem) -> decltype(P::value(elem)) {
- return P::value(elem);
- }
- private:
- // Use auto -> decltype as an enabler.
- template <class Alloc, class P = Policy>
- static auto transfer_impl(Alloc* alloc, slot_type* new_slot,
- slot_type* old_slot, int)
- -> decltype((void)P::transfer(alloc, new_slot, old_slot)) {
- P::transfer(alloc, new_slot, old_slot);
- }
- template <class Alloc>
- static void transfer_impl(Alloc* alloc, slot_type* new_slot,
- slot_type* old_slot, char) {
- construct(alloc, new_slot, std::move(element(old_slot)));
- destroy(alloc, old_slot);
- }
- };
- } // namespace priv
- } // namespace phmap
- // -----------------------------------------------------------------------------
- // file utility.h
- // -----------------------------------------------------------------------------
- // --------- identity.h
- namespace phmap {
- namespace internal {
- template <typename T>
- struct identity {
- typedef T type;
- };
- template <typename T>
- using identity_t = typename identity<T>::type;
- } // namespace internal
- } // namespace phmap
- // --------- inline_variable.h
- #ifdef __cpp_inline_variables
- #if defined(__clang__)
- #define PHMAP_INTERNAL_EXTERN_DECL(type, name) \
- extern const ::phmap::internal::identity_t<type> name;
- #else // Otherwise, just define the macro to do nothing.
- #define PHMAP_INTERNAL_EXTERN_DECL(type, name)
- #endif // defined(__clang__)
- // See above comment at top of file for details.
- #define PHMAP_INTERNAL_INLINE_CONSTEXPR(type, name, init) \
- PHMAP_INTERNAL_EXTERN_DECL(type, name) \
- LL_INLINE constexpr ::phmap::internal::identity_t<type> name = init
- #else
- // See above comment at top of file for details.
- //
- // Note:
- // identity_t is used here so that the const and name are in the
- // appropriate place for pointer types, reference types, function pointer
- // types, etc..
- #define PHMAP_INTERNAL_INLINE_CONSTEXPR(var_type, name, init) \
- template <class /*PhmapInternalDummy*/ = void> \
- struct PhmapInternalInlineVariableHolder##name { \
- static constexpr ::phmap::internal::identity_t<var_type> kInstance = init; \
- }; \
- \
- template <class PhmapInternalDummy> \
- constexpr ::phmap::internal::identity_t<var_type> \
- PhmapInternalInlineVariableHolder##name<PhmapInternalDummy>::kInstance; \
- \
- static constexpr const ::phmap::internal::identity_t<var_type>& \
- name = /* NOLINT */ \
- PhmapInternalInlineVariableHolder##name<>::kInstance; \
- static_assert(sizeof(void (*)(decltype(name))) != 0, \
- "Silence unused variable warnings.")
- #endif // __cpp_inline_variables
- // ----------- throw_delegate
- namespace phmap {
- namespace base_internal {
- namespace {
- #ifdef PHMAP_HAVE_EXCEPTIONS
- #define PHMAP_THROW_IMPL_MSG(e, message) throw e(message)
- #define PHMAP_THROW_IMPL(e) throw e()
- #else
- #define PHMAP_THROW_IMPL_MSG(e, message) do { (void)(message); std::abort(); } while(0)
- #define PHMAP_THROW_IMPL(e) std::abort()
- #endif
- } // namespace
- static LL_INLINE void ThrowStdLogicError(const std::string& what_arg) {
- PHMAP_THROW_IMPL_MSG(std::logic_error, what_arg);
- }
- static LL_INLINE void ThrowStdLogicError(const char* what_arg) {
- PHMAP_THROW_IMPL_MSG(std::logic_error, what_arg);
- }
- static LL_INLINE void ThrowStdInvalidArgument(const std::string& what_arg) {
- PHMAP_THROW_IMPL_MSG(std::invalid_argument, what_arg);
- }
- static LL_INLINE void ThrowStdInvalidArgument(const char* what_arg) {
- PHMAP_THROW_IMPL_MSG(std::invalid_argument, what_arg);
- }
- static LL_INLINE void ThrowStdDomainError(const std::string& what_arg) {
- PHMAP_THROW_IMPL_MSG(std::domain_error, what_arg);
- }
- static LL_INLINE void ThrowStdDomainError(const char* what_arg) {
- PHMAP_THROW_IMPL_MSG(std::domain_error, what_arg);
- }
- static LL_INLINE void ThrowStdLengthError(const std::string& what_arg) {
- PHMAP_THROW_IMPL_MSG(std::length_error, what_arg);
- }
- static LL_INLINE void ThrowStdLengthError(const char* what_arg) {
- PHMAP_THROW_IMPL_MSG(std::length_error, what_arg);
- }
- static LL_INLINE void ThrowStdOutOfRange(const std::string& what_arg) {
- PHMAP_THROW_IMPL_MSG(std::out_of_range, what_arg);
- }
- static LL_INLINE void ThrowStdOutOfRange(const char* what_arg) {
- PHMAP_THROW_IMPL_MSG(std::out_of_range, what_arg);
- }
- static LL_INLINE void ThrowStdRuntimeError(const std::string& what_arg) {
- PHMAP_THROW_IMPL_MSG(std::runtime_error, what_arg);
- }
- static LL_INLINE void ThrowStdRuntimeError(const char* what_arg) {
- PHMAP_THROW_IMPL_MSG(std::runtime_error, what_arg);
- }
- static LL_INLINE void ThrowStdRangeError(const std::string& what_arg) {
- PHMAP_THROW_IMPL_MSG(std::range_error, what_arg);
- }
- static LL_INLINE void ThrowStdRangeError(const char* what_arg) {
- PHMAP_THROW_IMPL_MSG(std::range_error, what_arg);
- }
- static LL_INLINE void ThrowStdOverflowError(const std::string& what_arg) {
- PHMAP_THROW_IMPL_MSG(std::overflow_error, what_arg);
- }
- static LL_INLINE void ThrowStdOverflowError(const char* what_arg) {
- PHMAP_THROW_IMPL_MSG(std::overflow_error, what_arg);
- }
- static LL_INLINE void ThrowStdUnderflowError(const std::string& what_arg) {
- PHMAP_THROW_IMPL_MSG(std::underflow_error, what_arg);
- }
- static LL_INLINE void ThrowStdUnderflowError(const char* what_arg) {
- PHMAP_THROW_IMPL_MSG(std::underflow_error, what_arg);
- }
- static LL_INLINE void ThrowStdBadFunctionCall() {
- PHMAP_THROW_IMPL(std::bad_function_call);
- }
- static LL_INLINE void ThrowStdBadAlloc() {
- PHMAP_THROW_IMPL(std::bad_alloc);
- }
- } // namespace base_internal
- } // namespace phmap
- // ----------- invoke.h
- namespace phmap {
- namespace base_internal {
- template <typename Derived>
- struct StrippedAccept
- {
- template <typename... Args>
- struct Accept : Derived::template AcceptImpl<typename std::remove_cv<
- typename std::remove_reference<Args>::type>::type...> {};
- };
- // (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T
- // and t1 is an object of type T or a reference to an object of type T or a
- // reference to an object of a type derived from T.
- struct MemFunAndRef : StrippedAccept<MemFunAndRef>
- {
- template <typename... Args>
- struct AcceptImpl : std::false_type {};
- template <typename R, typename C, typename... Params, typename Obj,
- typename... Args>
- struct AcceptImpl<R (C::*)(Params...), Obj, Args...>
- : std::is_base_of<C, Obj> {};
- template <typename R, typename C, typename... Params, typename Obj,
- typename... Args>
- struct AcceptImpl<R (C::*)(Params...) const, Obj, Args...>
- : std::is_base_of<C, Obj> {};
- template <typename MemFun, typename Obj, typename... Args>
- static decltype((std::declval<Obj>().*
- std::declval<MemFun>())(std::declval<Args>()...))
- Invoke(MemFun&& mem_fun, Obj&& obj, Args&&... args) {
- return (std::forward<Obj>(obj).*
- std::forward<MemFun>(mem_fun))(std::forward<Args>(args)...);
- }
- };
- // ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a
- // class T and t1 is not one of the types described in the previous item.
- struct MemFunAndPtr : StrippedAccept<MemFunAndPtr>
- {
- template <typename... Args>
- struct AcceptImpl : std::false_type {};
- template <typename R, typename C, typename... Params, typename Ptr,
- typename... Args>
- struct AcceptImpl<R (C::*)(Params...), Ptr, Args...>
- : std::integral_constant<bool, !std::is_base_of<C, Ptr>::value> {};
- template <typename R, typename C, typename... Params, typename Ptr,
- typename... Args>
- struct AcceptImpl<R (C::*)(Params...) const, Ptr, Args...>
- : std::integral_constant<bool, !std::is_base_of<C, Ptr>::value> {};
- template <typename MemFun, typename Ptr, typename... Args>
- static decltype(((*std::declval<Ptr>()).*
- std::declval<MemFun>())(std::declval<Args>()...))
- Invoke(MemFun&& mem_fun, Ptr&& ptr, Args&&... args) {
- return ((*std::forward<Ptr>(ptr)).*
- std::forward<MemFun>(mem_fun))(std::forward<Args>(args)...);
- }
- };
- // t1.*f when N == 1 and f is a pointer to member data of a class T and t1 is
- // an object of type T or a reference to an object of type T or a reference
- // to an object of a type derived from T.
- struct DataMemAndRef : StrippedAccept<DataMemAndRef>
- {
- template <typename... Args>
- struct AcceptImpl : std::false_type {};
- template <typename R, typename C, typename Obj>
- struct AcceptImpl<R C::*, Obj> : std::is_base_of<C, Obj> {};
- template <typename DataMem, typename Ref>
- static decltype(std::declval<Ref>().*std::declval<DataMem>()) Invoke(
- DataMem&& data_mem, Ref&& ref) {
- return std::forward<Ref>(ref).*std::forward<DataMem>(data_mem);
- }
- };
- // (*t1).*f when N == 1 and f is a pointer to member data of a class T and t1
- // is not one of the types described in the previous item.
- struct DataMemAndPtr : StrippedAccept<DataMemAndPtr>
- {
- template <typename... Args>
- struct AcceptImpl : std::false_type {};
- template <typename R, typename C, typename Ptr>
- struct AcceptImpl<R C::*, Ptr>
- : std::integral_constant<bool, !std::is_base_of<C, Ptr>::value> {};
- template <typename DataMem, typename Ptr>
- static decltype((*std::declval<Ptr>()).*std::declval<DataMem>()) Invoke(
- DataMem&& data_mem, Ptr&& ptr) {
- return (*std::forward<Ptr>(ptr)).*std::forward<DataMem>(data_mem);
- }
- };
- // f(t1, t2, ..., tN) in all other cases.
- struct Callable
- {
- // Callable doesn't have Accept because it's the last clause that gets picked
- // when none of the previous clauses are applicable.
- template <typename F, typename... Args>
- static decltype(std::declval<F>()(std::declval<Args>()...)) Invoke(
- F&& f, Args&&... args) {
- return std::forward<F>(f)(std::forward<Args>(args)...);
- }
- };
- // Resolves to the first matching clause.
- template <typename... Args>
- struct Invoker
- {
- typedef typename std::conditional<
- MemFunAndRef::Accept<Args...>::value, MemFunAndRef,
- typename std::conditional<
- MemFunAndPtr::Accept<Args...>::value, MemFunAndPtr,
- typename std::conditional<
- DataMemAndRef::Accept<Args...>::value, DataMemAndRef,
- typename std::conditional<DataMemAndPtr::Accept<Args...>::value,
- DataMemAndPtr, Callable>::type>::type>::
- type>::type type;
- };
- // The result type of Invoke<F, Args...>.
- template <typename F, typename... Args>
- using InvokeT = decltype(Invoker<F, Args...>::type::Invoke(
- std::declval<F>(), std::declval<Args>()...));
- // Invoke(f, args...) is an implementation of INVOKE(f, args...) from section
- // [func.require] of the C++ standard.
- template <typename F, typename... Args>
- InvokeT<F, Args...> Invoke(F&& f, Args&&... args) {
- return Invoker<F, Args...>::type::Invoke(std::forward<F>(f),
- std::forward<Args>(args)...);
- }
- } // namespace base_internal
- } // namespace phmap
- // ----------- utility.h
- namespace phmap {
- // integer_sequence
- //
- // Class template representing a compile-time integer sequence. An instantiation
- // of `integer_sequence<T, Ints...>` has a sequence of integers encoded in its
- // type through its template arguments (which is a common need when
- // working with C++11 variadic templates). `phmap::integer_sequence` is designed
- // to be a drop-in replacement for C++14's `std::integer_sequence`.
- //
- // Example:
- //
- // template< class T, T... Ints >
- // void user_function(integer_sequence<T, Ints...>);
- //
- // int main()
- // {
- // // user_function's `T` will be deduced to `int` and `Ints...`
- // // will be deduced to `0, 1, 2, 3, 4`.
- // user_function(make_integer_sequence<int, 5>());
- // }
- template <typename T, T... Ints>
- struct integer_sequence
- {
- using value_type = T;
- static constexpr size_t size() noexcept { return sizeof...(Ints); }
- };
- // index_sequence
- //
- // A helper template for an `integer_sequence` of `size_t`,
- // `phmap::index_sequence` is designed to be a drop-in replacement for C++14's
- // `std::index_sequence`.
- template <size_t... Ints>
- using index_sequence = integer_sequence<size_t, Ints...>;
- namespace utility_internal {
- template <typename Seq, size_t SeqSize, size_t Rem>
- struct Extend;
- // Note that SeqSize == sizeof...(Ints). It's passed explicitly for efficiency.
- template <typename T, T... Ints, size_t SeqSize>
- struct Extend<integer_sequence<T, Ints...>, SeqSize, 0> {
- using type = integer_sequence<T, Ints..., (Ints + SeqSize)...>;
- };
- template <typename T, T... Ints, size_t SeqSize>
- struct Extend<integer_sequence<T, Ints...>, SeqSize, 1> {
- using type = integer_sequence<T, Ints..., (Ints + SeqSize)..., 2 * SeqSize>;
- };
- // Recursion helper for 'make_integer_sequence<T, N>'.
- // 'Gen<T, N>::type' is an alias for 'integer_sequence<T, 0, 1, ... N-1>'.
- template <typename T, size_t N>
- struct Gen {
- using type =
- typename Extend<typename Gen<T, N / 2>::type, N / 2, N % 2>::type;
- };
- template <typename T>
- struct Gen<T, 0> {
- using type = integer_sequence<T>;
- };
- } // namespace utility_internal
- // Compile-time sequences of integers
- // make_integer_sequence
- //
- // This template alias is equivalent to
- // `integer_sequence<int, 0, 1, ..., N-1>`, and is designed to be a drop-in
- // replacement for C++14's `std::make_integer_sequence`.
- template <typename T, T N>
- using make_integer_sequence = typename utility_internal::Gen<T, N>::type;
- // make_index_sequence
- //
- // This template alias is equivalent to `index_sequence<0, 1, ..., N-1>`,
- // and is designed to be a drop-in replacement for C++14's
- // `std::make_index_sequence`.
- template <size_t N>
- using make_index_sequence = make_integer_sequence<size_t, N>;
- // index_sequence_for
- //
- // Converts a typename pack into an index sequence of the same length, and
- // is designed to be a drop-in replacement for C++14's
- // `std::index_sequence_for()`
- template <typename... Ts>
- using index_sequence_for = make_index_sequence<sizeof...(Ts)>;
- // Tag types
- #ifdef PHMAP_HAVE_STD_OPTIONAL
- using std::in_place_t;
- using std::in_place;
- #else // PHMAP_HAVE_STD_OPTIONAL
- // in_place_t
- //
- // Tag type used to specify in-place construction, such as with
- // `phmap::optional`, designed to be a drop-in replacement for C++17's
- // `std::in_place_t`.
- struct in_place_t {};
- PHMAP_INTERNAL_INLINE_CONSTEXPR(in_place_t, in_place, {});
- #endif // PHMAP_HAVE_STD_OPTIONAL
- #if defined(PHMAP_HAVE_STD_ANY) || defined(PHMAP_HAVE_STD_VARIANT)
- using std::in_place_type_t;
- #else
- // in_place_type_t
- //
- // Tag type used for in-place construction when the type to construct needs to
- // be specified, such as with `phmap::any`, designed to be a drop-in replacement
- // for C++17's `std::in_place_type_t`.
- template <typename T>
- struct in_place_type_t {};
- #endif // PHMAP_HAVE_STD_ANY || PHMAP_HAVE_STD_VARIANT
- #ifdef PHMAP_HAVE_STD_VARIANT
- using std::in_place_index_t;
- #else
- // in_place_index_t
- //
- // Tag type used for in-place construction when the type to construct needs to
- // be specified, such as with `phmap::any`, designed to be a drop-in replacement
- // for C++17's `std::in_place_index_t`.
- template <size_t I>
- struct in_place_index_t {};
- #endif // PHMAP_HAVE_STD_VARIANT
- // Constexpr move and forward
- // move()
- //
- // A constexpr version of `std::move()`, designed to be a drop-in replacement
- // for C++14's `std::move()`.
- template <typename T>
- constexpr phmap::remove_reference_t<T>&& move(T&& t) noexcept {
- return static_cast<phmap::remove_reference_t<T>&&>(t);
- }
- // forward()
- //
- // A constexpr version of `std::forward()`, designed to be a drop-in replacement
- // for C++14's `std::forward()`.
- template <typename T>
- constexpr T&& forward(
- phmap::remove_reference_t<T>& t) noexcept { // NOLINT(runtime/references)
- return static_cast<T&&>(t);
- }
- namespace utility_internal {
- // Helper method for expanding tuple into a called method.
- template <typename Functor, typename Tuple, std::size_t... Indexes>
- auto apply_helper(Functor&& functor, Tuple&& t, index_sequence<Indexes...>)
- -> decltype(phmap::base_internal::Invoke(
- phmap::forward<Functor>(functor),
- std::get<Indexes>(phmap::forward<Tuple>(t))...)) {
- return phmap::base_internal::Invoke(
- phmap::forward<Functor>(functor),
- std::get<Indexes>(phmap::forward<Tuple>(t))...);
- }
- } // namespace utility_internal
- // apply
- //
- // Invokes a Callable using elements of a tuple as its arguments.
- // Each element of the tuple corresponds to an argument of the call (in order).
- // Both the Callable argument and the tuple argument are perfect-forwarded.
- // For member-function Callables, the first tuple element acts as the `this`
- // pointer. `phmap::apply` is designed to be a drop-in replacement for C++17's
- // `std::apply`. Unlike C++17's `std::apply`, this is not currently `constexpr`.
- //
- // Example:
- //
- // class Foo {
- // public:
- // void Bar(int);
- // };
- // void user_function1(int, std::string);
- // void user_function2(std::unique_ptr<Foo>);
- // auto user_lambda = [](int, int) {};
- //
- // int main()
- // {
- // std::tuple<int, std::string> tuple1(42, "bar");
- // // Invokes the first user function on int, std::string.
- // phmap::apply(&user_function1, tuple1);
- //
- // std::tuple<std::unique_ptr<Foo>> tuple2(phmap::make_unique<Foo>());
- // // Invokes the user function that takes ownership of the unique
- // // pointer.
- // phmap::apply(&user_function2, std::move(tuple2));
- //
- // auto foo = phmap::make_unique<Foo>();
- // std::tuple<Foo*, int> tuple3(foo.get(), 42);
- // // Invokes the method Bar on foo with one argument, 42.
- // phmap::apply(&Foo::Bar, tuple3);
- //
- // std::tuple<int, int> tuple4(8, 9);
- // // Invokes a lambda.
- // phmap::apply(user_lambda, tuple4);
- // }
- template <typename Functor, typename Tuple>
- auto apply(Functor&& functor, Tuple&& t)
- -> decltype(utility_internal::apply_helper(
- phmap::forward<Functor>(functor), phmap::forward<Tuple>(t),
- phmap::make_index_sequence<std::tuple_size<
- typename std::remove_reference<Tuple>::type>::value>{})) {
- return utility_internal::apply_helper(
- phmap::forward<Functor>(functor), phmap::forward<Tuple>(t),
- phmap::make_index_sequence<std::tuple_size<
- typename std::remove_reference<Tuple>::type>::value>{});
- }
- #ifdef _MSC_VER
- #pragma warning(push)
- #pragma warning(disable : 4365) // '=': conversion from 'T' to 'T', signed/unsigned mismatch
- #endif // _MSC_VER
- // exchange
- //
- // Replaces the value of `obj` with `new_value` and returns the old value of
- // `obj`. `phmap::exchange` is designed to be a drop-in replacement for C++14's
- // `std::exchange`.
- //
- // Example:
- //
- // Foo& operator=(Foo&& other) {
- // ptr1_ = phmap::exchange(other.ptr1_, nullptr);
- // int1_ = phmap::exchange(other.int1_, -1);
- // return *this;
- // }
- template <typename T, typename U = T>
- T exchange(T& obj, U&& new_value)
- {
- T old_value = phmap::move(obj);
- obj = phmap::forward<U>(new_value);
- return old_value;
- }
- #ifdef _MSC_VER
- #pragma warning(pop)
- #endif // _MSC_VER
- } // namespace phmap
- // -----------------------------------------------------------------------------
- // memory.h
- // -----------------------------------------------------------------------------
- namespace phmap {
- template <typename T>
- std::unique_ptr<T> WrapUnique(T* ptr)
- {
- static_assert(!std::is_array<T>::value, "array types are unsupported");
- static_assert(std::is_object<T>::value, "non-object types are unsupported");
- return std::unique_ptr<T>(ptr);
- }
- namespace memory_internal {
- // Traits to select proper overload and return type for `phmap::make_unique<>`.
- template <typename T>
- struct MakeUniqueResult {
- using scalar = std::unique_ptr<T>;
- };
- template <typename T>
- struct MakeUniqueResult<T[]> {
- using array = std::unique_ptr<T[]>;
- };
- template <typename T, size_t N>
- struct MakeUniqueResult<T[N]> {
- using invalid = void;
- };
- } // namespace memory_internal
- #if (__cplusplus > 201103L || defined(_MSC_VER)) && \
- !(defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 8)
- using std::make_unique;
- #else
- template <typename T, typename... Args>
- typename memory_internal::MakeUniqueResult<T>::scalar make_unique(
- Args&&... args) {
- return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
- }
- template <typename T>
- typename memory_internal::MakeUniqueResult<T>::array make_unique(size_t n) {
- return std::unique_ptr<T>(new typename phmap::remove_extent_t<T>[n]());
- }
- template <typename T, typename... Args>
- typename memory_internal::MakeUniqueResult<T>::invalid make_unique(
- Args&&... /* args */) = delete;
- #endif
- template <typename T>
- auto RawPtr(T&& ptr) -> decltype(std::addressof(*ptr))
- {
- // ptr is a forwarding reference to support Ts with non-const operators.
- return (ptr != nullptr) ? std::addressof(*ptr) : nullptr;
- }
- LL_INLINE std::nullptr_t RawPtr(std::nullptr_t) { return nullptr; }
- template <typename T, typename D>
- std::shared_ptr<T> ShareUniquePtr(std::unique_ptr<T, D>&& ptr) {
- return ptr ? std::shared_ptr<T>(std::move(ptr)) : std::shared_ptr<T>();
- }
- template <typename T>
- std::weak_ptr<T> WeakenPtr(const std::shared_ptr<T>& ptr) {
- return std::weak_ptr<T>(ptr);
- }
- namespace memory_internal {
- // ExtractOr<E, O, D>::type evaluates to E<O> if possible. Otherwise, D.
- template <template <typename> class Extract, typename Obj, typename Default,
- typename>
- struct ExtractOr {
- using type = Default;
- };
- template <template <typename> class Extract, typename Obj, typename Default>
- struct ExtractOr<Extract, Obj, Default, void_t<Extract<Obj>>> {
- using type = Extract<Obj>;
- };
- template <template <typename> class Extract, typename Obj, typename Default>
- using ExtractOrT = typename ExtractOr<Extract, Obj, Default, void>::type;
- // Extractors for the features of allocators.
- template <typename T>
- using GetPointer = typename T::pointer;
- template <typename T>
- using GetConstPointer = typename T::const_pointer;
- template <typename T>
- using GetVoidPointer = typename T::void_pointer;
- template <typename T>
- using GetConstVoidPointer = typename T::const_void_pointer;
- template <typename T>
- using GetDifferenceType = typename T::difference_type;
- template <typename T>
- using GetSizeType = typename T::size_type;
- template <typename T>
- using GetPropagateOnContainerCopyAssignment =
- typename T::propagate_on_container_copy_assignment;
- template <typename T>
- using GetPropagateOnContainerMoveAssignment =
- typename T::propagate_on_container_move_assignment;
- template <typename T>
- using GetPropagateOnContainerSwap = typename T::propagate_on_container_swap;
- template <typename T>
- using GetIsAlwaysEqual = typename T::is_always_equal;
- template <typename T>
- struct GetFirstArg;
- template <template <typename...> class Class, typename T, typename... Args>
- struct GetFirstArg<Class<T, Args...>> {
- using type = T;
- };
- template <typename Ptr, typename = void>
- struct ElementType {
- using type = typename GetFirstArg<Ptr>::type;
- };
- template <typename T>
- struct ElementType<T, void_t<typename T::element_type>> {
- using type = typename T::element_type;
- };
- template <typename T, typename U>
- struct RebindFirstArg;
- template <template <typename...> class Class, typename T, typename... Args,
- typename U>
- struct RebindFirstArg<Class<T, Args...>, U> {
- using type = Class<U, Args...>;
- };
- template <typename T, typename U, typename = void>
- struct RebindPtr {
- using type = typename RebindFirstArg<T, U>::type;
- };
- template <typename T, typename U>
- struct RebindPtr<T, U, void_t<typename T::template rebind<U>>> {
- using type = typename T::template rebind<U>;
- };
- template <typename T, typename U>
- constexpr bool HasRebindAlloc(...) {
- return false;
- }
- template <typename T, typename U>
- constexpr bool HasRebindAlloc(typename std::allocator_traits<T>::template rebind_alloc<U>*) {
- return true;
- }
- template <typename T, typename U, bool = HasRebindAlloc<T, U>(nullptr)>
- struct RebindAlloc {
- using type = typename RebindFirstArg<T, U>::type;
- };
- template <typename A, typename U>
- struct RebindAlloc<A, U, true> {
- using type = typename std::allocator_traits<A>::template rebind_alloc<U>;
- };
- } // namespace memory_internal
- template <typename Ptr>
- struct pointer_traits
- {
- using pointer = Ptr;
- // element_type:
- // Ptr::element_type if present. Otherwise T if Ptr is a template
- // instantiation Template<T, Args...>
- using element_type = typename memory_internal::ElementType<Ptr>::type;
- // difference_type:
- // Ptr::difference_type if present, otherwise std::ptrdiff_t
- using difference_type =
- memory_internal::ExtractOrT<memory_internal::GetDifferenceType, Ptr,
- std::ptrdiff_t>;
- // rebind:
- // Ptr::rebind<U> if exists, otherwise Template<U, Args...> if Ptr is a
- // template instantiation Template<T, Args...>
- template <typename U>
- using rebind = typename memory_internal::RebindPtr<Ptr, U>::type;
- // pointer_to:
- // Calls Ptr::pointer_to(r)
- static pointer pointer_to(element_type& r) { // NOLINT(runtime/references)
- return Ptr::pointer_to(r);
- }
- };
- // Specialization for T*.
- template <typename T>
- struct pointer_traits<T*>
- {
- using pointer = T*;
- using element_type = T;
- using difference_type = std::ptrdiff_t;
- template <typename U>
- using rebind = U*;
- // pointer_to:
- // Calls std::addressof(r)
- static pointer pointer_to(
- element_type& r) noexcept { // NOLINT(runtime/references)
- return std::addressof(r);
- }
- };
- // -----------------------------------------------------------------------------
- // Class Template: allocator_traits
- // -----------------------------------------------------------------------------
- //
- // A C++11 compatible implementation of C++17's std::allocator_traits.
- //
- template <typename Alloc>
- struct allocator_traits
- {
- using allocator_type = Alloc;
- // value_type:
- // Alloc::value_type
- using value_type = typename Alloc::value_type;
- // pointer:
- // Alloc::pointer if present, otherwise value_type*
- using pointer = memory_internal::ExtractOrT<memory_internal::GetPointer,
- Alloc, value_type*>;
- // const_pointer:
- // Alloc::const_pointer if present, otherwise
- // phmap::pointer_traits<pointer>::rebind<const value_type>
- using const_pointer =
- memory_internal::ExtractOrT<memory_internal::GetConstPointer, Alloc,
- typename phmap::pointer_traits<pointer>::
- template rebind<const value_type>>;
- // void_pointer:
- // Alloc::void_pointer if present, otherwise
- // phmap::pointer_traits<pointer>::rebind<void>
- using void_pointer = memory_internal::ExtractOrT<
- memory_internal::GetVoidPointer, Alloc,
- typename phmap::pointer_traits<pointer>::template rebind<void>>;
- // const_void_pointer:
- // Alloc::const_void_pointer if present, otherwise
- // phmap::pointer_traits<pointer>::rebind<const void>
- using const_void_pointer = memory_internal::ExtractOrT<
- memory_internal::GetConstVoidPointer, Alloc,
- typename phmap::pointer_traits<pointer>::template rebind<const void>>;
- // difference_type:
- // Alloc::difference_type if present, otherwise
- // phmap::pointer_traits<pointer>::difference_type
- using difference_type = memory_internal::ExtractOrT<
- memory_internal::GetDifferenceType, Alloc,
- typename phmap::pointer_traits<pointer>::difference_type>;
- // size_type:
- // Alloc::size_type if present, otherwise
- // std::make_unsigned<difference_type>::type
- using size_type = memory_internal::ExtractOrT<
- memory_internal::GetSizeType, Alloc,
- typename std::make_unsigned<difference_type>::type>;
- // propagate_on_container_copy_assignment:
- // Alloc::propagate_on_container_copy_assignment if present, otherwise
- // std::false_type
- using propagate_on_container_copy_assignment = memory_internal::ExtractOrT<
- memory_internal::GetPropagateOnContainerCopyAssignment, Alloc,
- std::false_type>;
- // propagate_on_container_move_assignment:
- // Alloc::propagate_on_container_move_assignment if present, otherwise
- // std::false_type
- using propagate_on_container_move_assignment = memory_internal::ExtractOrT<
- memory_internal::GetPropagateOnContainerMoveAssignment, Alloc,
- std::false_type>;
- // propagate_on_container_swap:
- // Alloc::propagate_on_container_swap if present, otherwise std::false_type
- using propagate_on_container_swap =
- memory_internal::ExtractOrT<memory_internal::GetPropagateOnContainerSwap,
- Alloc, std::false_type>;
- // is_always_equal:
- // Alloc::is_always_equal if present, otherwise std::is_empty<Alloc>::type
- using is_always_equal =
- memory_internal::ExtractOrT<memory_internal::GetIsAlwaysEqual, Alloc,
- typename std::is_empty<Alloc>::type>;
- // rebind_alloc:
- // Alloc::rebind<T>::other if present, otherwise Alloc<T, Args> if this Alloc
- // is Alloc<U, Args>
- template <typename T>
- using rebind_alloc = typename memory_internal::RebindAlloc<Alloc, T>::type;
- // rebind_traits:
- // phmap::allocator_traits<rebind_alloc<T>>
- template <typename T>
- using rebind_traits = phmap::allocator_traits<rebind_alloc<T>>;
- // allocate(Alloc& a, size_type n):
- // Calls a.allocate(n)
- static pointer allocate(Alloc& a, // NOLINT(runtime/references)
- size_type n) {
- return a.allocate(n);
- }
- // allocate(Alloc& a, size_type n, const_void_pointer hint):
- // Calls a.allocate(n, hint) if possible.
- // If not possible, calls a.allocate(n)
- static pointer allocate(Alloc& a, size_type n, // NOLINT(runtime/references)
- const_void_pointer hint) {
- return allocate_impl(0, a, n, hint);
- }
- // deallocate(Alloc& a, pointer p, size_type n):
- // Calls a.deallocate(p, n)
- static void deallocate(Alloc& a, pointer p, // NOLINT(runtime/references)
- size_type n) {
- a.deallocate(p, n);
- }
- // construct(Alloc& a, T* p, Args&&... args):
- // Calls a.construct(p, std::forward<Args>(args)...) if possible.
- // If not possible, calls
- // ::new (static_cast<void*>(p)) T(std::forward<Args>(args)...)
- template <typename T, typename... Args>
- static void construct(Alloc& a, T* p, // NOLINT(runtime/references)
- Args&&... args) {
- construct_impl(0, a, p, std::forward<Args>(args)...);
- }
- // destroy(Alloc& a, T* p):
- // Calls a.destroy(p) if possible. If not possible, calls p->~T().
- template <typename T>
- static void destroy(Alloc& a, T* p) { // NOLINT(runtime/references)
- destroy_impl(0, a, p);
- }
- // max_size(const Alloc& a):
- // Returns a.max_size() if possible. If not possible, returns
- // std::numeric_limits<size_type>::max() / sizeof(value_type)
- static size_type max_size(const Alloc& a) { return max_size_impl(0, a); }
- // select_on_container_copy_construction(const Alloc& a):
- // Returns a.select_on_container_copy_construction() if possible.
- // If not possible, returns a.
- static Alloc select_on_container_copy_construction(const Alloc& a) {
- return select_on_container_copy_construction_impl(0, a);
- }
- private:
- template <typename A>
- static auto allocate_impl(int, A& a, // NOLINT(runtime/references)
- size_type n, const_void_pointer hint)
- -> decltype(a.allocate(n, hint)) {
- return a.allocate(n, hint);
- }
- static pointer allocate_impl(char, Alloc& a, // NOLINT(runtime/references)
- size_type n, const_void_pointer) {
- return a.allocate(n);
- }
- template <typename A, typename... Args>
- static auto construct_impl(int, A& a, // NOLINT(runtime/references)
- Args&&... args)
- -> decltype(std::allocator_traits<A>::construct(a, std::forward<Args>(args)...)) {
- std::allocator_traits<A>::construct(a, std::forward<Args>(args)...);
- }
- template <typename T, typename... Args>
- static void construct_impl(char, Alloc&, T* p, Args&&... args) {
- ::new (static_cast<void*>(p)) T(std::forward<Args>(args)...);
- }
- template <typename A, typename T>
- static auto destroy_impl(int, A& a, // NOLINT(runtime/references)
- T* p) -> decltype(std::allocator_traits<A>::destroy(a, p)) {
- std::allocator_traits<A>::destroy(a, p);
- }
- template <typename T>
- static void destroy_impl(char, Alloc&, T* p) {
- p->~T();
- }
- template <typename A>
- static auto max_size_impl(int, const A& a) -> decltype(a.max_size()) {
- return a.max_size();
- }
- static size_type max_size_impl(char, const Alloc&) {
- return (std::numeric_limits<size_type>::max)() / sizeof(value_type);
- }
- template <typename A>
- static auto select_on_container_copy_construction_impl(int, const A& a)
- -> decltype(a.select_on_container_copy_construction()) {
- return a.select_on_container_copy_construction();
- }
- static Alloc select_on_container_copy_construction_impl(char,
- const Alloc& a) {
- return a;
- }
- };
- namespace memory_internal {
- // This template alias transforms Alloc::is_nothrow into a metafunction with
- // Alloc as a parameter so it can be used with ExtractOrT<>.
- template <typename Alloc>
- using GetIsNothrow = typename Alloc::is_nothrow;
- } // namespace memory_internal
- // PHMAP_ALLOCATOR_NOTHROW is a build time configuration macro for user to
- // specify whether the default allocation function can throw or never throws.
- // If the allocation function never throws, user should define it to a non-zero
- // value (e.g. via `-DPHMAP_ALLOCATOR_NOTHROW`).
- // If the allocation function can throw, user should leave it undefined or
- // define it to zero.
- //
- // allocator_is_nothrow<Alloc> is a traits class that derives from
- // Alloc::is_nothrow if present, otherwise std::false_type. It's specialized
- // for Alloc = std::allocator<T> for any type T according to the state of
- // PHMAP_ALLOCATOR_NOTHROW.
- //
- // default_allocator_is_nothrow is a class that derives from std::true_type
- // when the default allocator (global operator new) never throws, and
- // std::false_type when it can throw. It is a convenience shorthand for writing
- // allocator_is_nothrow<std::allocator<T>> (T can be any type).
- // NOTE: allocator_is_nothrow<std::allocator<T>> is guaranteed to derive from
- // the same type for all T, because users should specialize neither
- // allocator_is_nothrow nor std::allocator.
- template <typename Alloc>
- struct allocator_is_nothrow
- : memory_internal::ExtractOrT<memory_internal::GetIsNothrow, Alloc,
- std::false_type> {};
- #if defined(PHMAP_ALLOCATOR_NOTHROW) && PHMAP_ALLOCATOR_NOTHROW
- template <typename T>
- struct allocator_is_nothrow<std::allocator<T>> : std::true_type {};
- struct default_allocator_is_nothrow : std::true_type {};
- #else
- struct default_allocator_is_nothrow : std::false_type {};
- #endif
- namespace memory_internal {
- template <typename Allocator, typename Iterator, typename... Args>
- void ConstructRange(Allocator& alloc, Iterator first, Iterator last,
- const Args&... args)
- {
- for (Iterator cur = first; cur != last; ++cur) {
- PHMAP_INTERNAL_TRY {
- std::allocator_traits<Allocator>::construct(alloc, std::addressof(*cur),
- args...);
- }
- PHMAP_INTERNAL_CATCH_ANY {
- while (cur != first) {
- --cur;
- std::allocator_traits<Allocator>::destroy(alloc, std::addressof(*cur));
- }
- PHMAP_INTERNAL_RETHROW;
- }
- }
- }
- template <typename Allocator, typename Iterator, typename InputIterator>
- void CopyRange(Allocator& alloc, Iterator destination, InputIterator first,
- InputIterator last)
- {
- for (Iterator cur = destination; first != last;
- static_cast<void>(++cur), static_cast<void>(++first)) {
- PHMAP_INTERNAL_TRY {
- std::allocator_traits<Allocator>::construct(alloc, std::addressof(*cur),
- *first);
- }
- PHMAP_INTERNAL_CATCH_ANY {
- while (cur != destination) {
- --cur;
- std::allocator_traits<Allocator>::destroy(alloc, std::addressof(*cur));
- }
- PHMAP_INTERNAL_RETHROW;
- }
- }
- }
- } // namespace memory_internal
- } // namespace phmap
- // -----------------------------------------------------------------------------
- // optional.h
- // -----------------------------------------------------------------------------
- #ifdef PHMAP_HAVE_STD_OPTIONAL
- #include <optional> // IWYU pragma: export
- namespace phmap {
- using std::bad_optional_access;
- using std::optional;
- using std::make_optional;
- using std::nullopt_t;
- using std::nullopt;
- } // namespace phmap
- #else
- #if defined(__clang__)
- #if __has_feature(cxx_inheriting_constructors)
- #define PHMAP_OPTIONAL_USE_INHERITING_CONSTRUCTORS 1
- #endif
- #elif (defined(__GNUC__) && \
- (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 8)) || \
- (__cpp_inheriting_constructors >= 200802) || \
- (defined(_MSC_VER) && _MSC_VER >= 1910)
- #define PHMAP_OPTIONAL_USE_INHERITING_CONSTRUCTORS 1
- #endif
- namespace phmap {
- class bad_optional_access : public std::exception
- {
- public:
- bad_optional_access() = default;
- ~bad_optional_access() override;
- const char* what() const noexcept override;
- };
- template <typename T>
- class optional;
- // --------------------------------
- struct nullopt_t
- {
- struct init_t {};
- static init_t init;
- explicit constexpr nullopt_t(init_t& /*unused*/) {}
- };
- constexpr nullopt_t nullopt(nullopt_t::init);
- namespace optional_internal {
- // throw delegator
- [[noreturn]] void throw_bad_optional_access();
- struct empty_struct {};
- // This class stores the data in optional<T>.
- // It is specialized based on whether T is trivially destructible.
- // This is the specialization for non trivially destructible type.
- template <typename T, bool unused = std::is_trivially_destructible<T>::value>
- class optional_data_dtor_base
- {
- struct dummy_type {
- static_assert(sizeof(T) % sizeof(empty_struct) == 0, "");
- // Use an array to avoid GCC 6 placement-new warning.
- empty_struct data[sizeof(T) / sizeof(empty_struct)];
- };
- protected:
- // Whether there is data or not.
- bool engaged_;
- // Data storage
- union {
- dummy_type dummy_;
- T data_;
- };
- void destruct() noexcept {
- if (engaged_) {
- data_.~T();
- engaged_ = false;
- }
- }
- // dummy_ must be initialized for constexpr constructor.
- constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{{}} {}
- template <typename... Args>
- constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args)
- : engaged_(true), data_(phmap::forward<Args>(args)...) {}
- ~optional_data_dtor_base() { destruct(); }
- };
- // Specialization for trivially destructible type.
- template <typename T>
- class optional_data_dtor_base<T, true>
- {
- struct dummy_type {
- static_assert(sizeof(T) % sizeof(empty_struct) == 0, "");
- // Use array to avoid GCC 6 placement-new warning.
- empty_struct data[sizeof(T) / sizeof(empty_struct)];
- };
- protected:
- // Whether there is data or not.
- bool engaged_;
- // Data storage
- union {
- dummy_type dummy_;
- T data_;
- };
- void destruct() noexcept { engaged_ = false; }
- // dummy_ must be initialized for constexpr constructor.
- constexpr optional_data_dtor_base() noexcept : engaged_(false), dummy_{{}} {}
- template <typename... Args>
- constexpr explicit optional_data_dtor_base(in_place_t, Args&&... args)
- : engaged_(true), data_(phmap::forward<Args>(args)...) {}
- };
- template <typename T>
- class optional_data_base : public optional_data_dtor_base<T>
- {
- protected:
- using base = optional_data_dtor_base<T>;
- #if PHMAP_OPTIONAL_USE_INHERITING_CONSTRUCTORS
- using base::base;
- #else
- optional_data_base() = default;
- template <typename... Args>
- constexpr explicit optional_data_base(in_place_t t, Args&&... args)
- : base(t, phmap::forward<Args>(args)...) {}
- #endif
- template <typename... Args>
- void construct(Args&&... args) {
- // Use dummy_'s address to work around casting cv-qualified T* to void*.
- ::new (static_cast<void*>(&this->dummy_)) T(std::forward<Args>(args)...);
- this->engaged_ = true;
- }
- template <typename U>
- void assign(U&& u) {
- if (this->engaged_) {
- this->data_ = std::forward<U>(u);
- } else {
- construct(std::forward<U>(u));
- }
- }
- };
- // TODO: Add another class using
- // std::is_trivially_move_constructible trait when available to match
- // http://cplusplus.github.io/LWG/lwg-defects.html#2900, for types that
- // have trivial move but nontrivial copy.
- // Also, we should be checking is_trivially_copyable here, which is not
- // supported now, so we use is_trivially_* traits instead.
- template <typename T,
- bool unused =
- std::is_trivially_copy_constructible<T>::value &&
- std::is_trivially_copy_assignable<typename std::remove_cv<T>::type>::value &&
- std::is_trivially_destructible<T>::value>
- class optional_data;
- // Trivially copyable types
- template <typename T>
- class optional_data<T, true> : public optional_data_base<T>
- {
- protected:
- #if PHMAP_OPTIONAL_USE_INHERITING_CONSTRUCTORS
- using optional_data_base<T>::optional_data_base;
- #else
- optional_data() = default;
- template <typename... Args>
- constexpr explicit optional_data(in_place_t t, Args&&... args)
- : optional_data_base<T>(t, phmap::forward<Args>(args)...) {}
- #endif
- };
- template <typename T>
- class optional_data<T, false> : public optional_data_base<T>
- {
- protected:
- #if PHMAP_OPTIONAL_USE_INHERITING_CONSTRUCTORS
- using optional_data_base<T>::optional_data_base;
- #else
- template <typename... Args>
- constexpr explicit optional_data(in_place_t t, Args&&... args)
- : optional_data_base<T>(t, phmap::forward<Args>(args)...) {}
- #endif
- optional_data() = default;
- optional_data(const optional_data& rhs) : optional_data_base<T>() {
- if (rhs.engaged_) {
- this->construct(rhs.data_);
- }
- }
- optional_data(optional_data&& rhs) noexcept(
- phmap::default_allocator_is_nothrow::value ||
- std::is_nothrow_move_constructible<T>::value)
- : optional_data_base<T>() {
- if (rhs.engaged_) {
- this->construct(std::move(rhs.data_));
- }
- }
- optional_data& operator=(const optional_data& rhs) {
- if (rhs.engaged_) {
- this->assign(rhs.data_);
- } else {
- this->destruct();
- }
- return *this;
- }
- optional_data& operator=(optional_data&& rhs) noexcept(
- std::is_nothrow_move_assignable<T>::value&&
- std::is_nothrow_move_constructible<T>::value) {
- if (rhs.engaged_) {
- this->assign(std::move(rhs.data_));
- } else {
- this->destruct();
- }
- return *this;
- }
- };
- // Ordered by level of restriction, from low to high.
- // Copyable implies movable.
- enum class copy_traits { copyable = 0, movable = 1, non_movable = 2 };
- // Base class for enabling/disabling copy/move constructor.
- template <copy_traits>
- class optional_ctor_base;
- template <>
- class optional_ctor_base<copy_traits::copyable>
- {
- public:
- constexpr optional_ctor_base() = default;
- optional_ctor_base(const optional_ctor_base&) = default;
- optional_ctor_base(optional_ctor_base&&) = default;
- optional_ctor_base& operator=(const optional_ctor_base&) = default;
- optional_ctor_base& operator=(optional_ctor_base&&) = default;
- };
- template <>
- class optional_ctor_base<copy_traits::movable>
- {
- public:
- constexpr optional_ctor_base() = default;
- optional_ctor_base(const optional_ctor_base&) = delete;
- optional_ctor_base(optional_ctor_base&&) = default;
- optional_ctor_base& operator=(const optional_ctor_base&) = default;
- optional_ctor_base& operator=(optional_ctor_base&&) = default;
- };
- template <>
- class optional_ctor_base<copy_traits::non_movable>
- {
- public:
- constexpr optional_ctor_base() = default;
- optional_ctor_base(const optional_ctor_base&) = delete;
- optional_ctor_base(optional_ctor_base&&) = delete;
- optional_ctor_base& operator=(const optional_ctor_base&) = default;
- optional_ctor_base& operator=(optional_ctor_base&&) = default;
- };
- // Base class for enabling/disabling copy/move assignment.
- template <copy_traits>
- class optional_assign_base;
- template <>
- class optional_assign_base<copy_traits::copyable>
- {
- public:
- constexpr optional_assign_base() = default;
- optional_assign_base(const optional_assign_base&) = default;
- optional_assign_base(optional_assign_base&&) = default;
- optional_assign_base& operator=(const optional_assign_base&) = default;
- optional_assign_base& operator=(optional_assign_base&&) = default;
- };
- template <>
- class optional_assign_base<copy_traits::movable>
- {
- public:
- constexpr optional_assign_base() = default;
- optional_assign_base(const optional_assign_base&) = default;
- optional_assign_base(optional_assign_base&&) = default;
- optional_assign_base& operator=(const optional_assign_base&) = delete;
- optional_assign_base& operator=(optional_assign_base&&) = default;
- };
- template <>
- class optional_assign_base<copy_traits::non_movable>
- {
- public:
- constexpr optional_assign_base() = default;
- optional_assign_base(const optional_assign_base&) = default;
- optional_assign_base(optional_assign_base&&) = default;
- optional_assign_base& operator=(const optional_assign_base&) = delete;
- optional_assign_base& operator=(optional_assign_base&&) = delete;
- };
- template <typename T>
- constexpr copy_traits get_ctor_copy_traits()
- {
- return std::is_copy_constructible<T>::value
- ? copy_traits::copyable
- : std::is_move_constructible<T>::value ? copy_traits::movable
- : copy_traits::non_movable;
- }
- template <typename T>
- constexpr copy_traits get_assign_copy_traits()
- {
- return phmap::is_copy_assignable<T>::value &&
- std::is_copy_constructible<T>::value
- ? copy_traits::copyable
- : phmap::is_move_assignable<T>::value &&
- std::is_move_constructible<T>::value
- ? copy_traits::movable
- : copy_traits::non_movable;
- }
- // Whether T is constructible or convertible from optional<U>.
- template <typename T, typename U>
- struct is_constructible_convertible_from_optional
- : std::integral_constant<
- bool, std::is_constructible<T, optional<U>&>::value ||
- std::is_constructible<T, optional<U>&&>::value ||
- std::is_constructible<T, const optional<U>&>::value ||
- std::is_constructible<T, const optional<U>&&>::value ||
- std::is_convertible<optional<U>&, T>::value ||
- std::is_convertible<optional<U>&&, T>::value ||
- std::is_convertible<const optional<U>&, T>::value ||
- std::is_convertible<const optional<U>&&, T>::value> {};
- // Whether T is constructible or convertible or assignable from optional<U>.
- template <typename T, typename U>
- struct is_constructible_convertible_assignable_from_optional
- : std::integral_constant<
- bool, is_constructible_convertible_from_optional<T, U>::value ||
- std::is_assignable<T&, optional<U>&>::value ||
- std::is_assignable<T&, optional<U>&&>::value ||
- std::is_assignable<T&, const optional<U>&>::value ||
- std::is_assignable<T&, const optional<U>&&>::value> {};
- // Helper function used by [optional.relops], [optional.comp_with_t],
- // for checking whether an expression is convertible to bool.
- bool convertible_to_bool(bool);
- // Base class for std::hash<phmap::optional<T>>:
- // If std::hash<std::remove_const_t<T>> is enabled, it provides operator() to
- // compute the hash; Otherwise, it is disabled.
- // Reference N4659 23.14.15 [unord.hash].
- template <typename T, typename = size_t>
- struct optional_hash_base
- {
- optional_hash_base() = delete;
- optional_hash_base(const optional_hash_base&) = delete;
- optional_hash_base(optional_hash_base&&) = delete;
- optional_hash_base& operator=(const optional_hash_base&) = delete;
- optional_hash_base& operator=(optional_hash_base&&) = delete;
- };
- template <typename T>
- struct optional_hash_base<T, decltype(std::hash<phmap::remove_const_t<T> >()(
- std::declval<phmap::remove_const_t<T> >()))>
- {
- using argument_type = phmap::optional<T>;
- using result_type = size_t;
- size_t operator()(const phmap::optional<T>& opt) const {
- phmap::type_traits_internal::AssertHashEnabled<phmap::remove_const_t<T>>();
- if (opt) {
- return std::hash<phmap::remove_const_t<T> >()(*opt);
- } else {
- return static_cast<size_t>(0x297814aaad196e6dULL);
- }
- }
- };
- } // namespace optional_internal
- // -----------------------------------------------------------------------------
- // phmap::optional class definition
- // -----------------------------------------------------------------------------
- template <typename T>
- class optional : private optional_internal::optional_data<T>,
- private optional_internal::optional_ctor_base<
- optional_internal::get_ctor_copy_traits<T>()>,
- private optional_internal::optional_assign_base<
- optional_internal::get_assign_copy_traits<T>()>
- {
- using data_base = optional_internal::optional_data<T>;
- public:
- typedef T value_type;
- // Constructors
- // Constructs an `optional` holding an empty value, NOT a default constructed
- // `T`.
- constexpr optional() noexcept {}
- // Constructs an `optional` initialized with `nullopt` to hold an empty value.
- constexpr optional(nullopt_t) noexcept {} // NOLINT(runtime/explicit)
- // Copy constructor, standard semantics
- optional(const optional& src) = default;
- // Move constructor, standard semantics
- optional(optional&& src) noexcept = default;
- // Constructs a non-empty `optional` direct-initialized value of type `T` from
- // the arguments `std::forward<Args>(args)...` within the `optional`.
- // (The `in_place_t` is a tag used to indicate that the contained object
- // should be constructed in-place.)
- template <typename InPlaceT, typename... Args,
- phmap::enable_if_t<phmap::conjunction<
- std::is_same<InPlaceT, in_place_t>,
- std::is_constructible<T, Args&&...> >::value>* = nullptr>
- constexpr explicit optional(InPlaceT, Args&&... args)
- : data_base(in_place_t(), phmap::forward<Args>(args)...) {}
- // Constructs a non-empty `optional` direct-initialized value of type `T` from
- // the arguments of an initializer_list and `std::forward<Args>(args)...`.
- // (The `in_place_t` is a tag used to indicate that the contained object
- // should be constructed in-place.)
- template <typename U, typename... Args,
- typename = typename std::enable_if<std::is_constructible<
- T, std::initializer_list<U>&, Args&&...>::value>::type>
- constexpr explicit optional(in_place_t, std::initializer_list<U> il,
- Args&&... args)
- : data_base(in_place_t(), il, phmap::forward<Args>(args)...) {
- }
- // Value constructor (implicit)
- template <
- typename U = T,
- typename std::enable_if<
- phmap::conjunction<phmap::negation<std::is_same<
- in_place_t, typename std::decay<U>::type> >,
- phmap::negation<std::is_same<
- optional<T>, typename std::decay<U>::type> >,
- std::is_convertible<U&&, T>,
- std::is_constructible<T, U&&> >::value,
- bool>::type = false>
- constexpr optional(U&& v) : data_base(in_place_t(), phmap::forward<U>(v)) {}
- // Value constructor (explicit)
- template <
- typename U = T,
- typename std::enable_if<
- phmap::conjunction<phmap::negation<std::is_same<
- in_place_t, typename std::decay<U>::type>>,
- phmap::negation<std::is_same<
- optional<T>, typename std::decay<U>::type>>,
- phmap::negation<std::is_convertible<U&&, T>>,
- std::is_constructible<T, U&&>>::value,
- bool>::type = false>
- explicit constexpr optional(U&& v)
- : data_base(in_place_t(), phmap::forward<U>(v)) {}
- // Converting copy constructor (implicit)
- template <typename U,
- typename std::enable_if<
- phmap::conjunction<
- phmap::negation<std::is_same<T, U> >,
- std::is_constructible<T, const U&>,
- phmap::negation<
- optional_internal::
- is_constructible_convertible_from_optional<T, U> >,
- std::is_convertible<const U&, T> >::value,
- bool>::type = false>
- optional(const optional<U>& rhs) {
- if (rhs) {
- this->construct(*rhs);
- }
- }
- // Converting copy constructor (explicit)
- template <typename U,
- typename std::enable_if<
- phmap::conjunction<
- phmap::negation<std::is_same<T, U>>,
- std::is_constructible<T, const U&>,
- phmap::negation<
- optional_internal::
- is_constructible_convertible_from_optional<T, U>>,
- phmap::negation<std::is_convertible<const U&, T>>>::value,
- bool>::type = false>
- explicit optional(const optional<U>& rhs) {
- if (rhs) {
- this->construct(*rhs);
- }
- }
- // Converting move constructor (implicit)
- template <typename U,
- typename std::enable_if<
- phmap::conjunction<
- phmap::negation<std::is_same<T, U> >,
- std::is_constructible<T, U&&>,
- phmap::negation<
- optional_internal::
- is_constructible_convertible_from_optional<T, U> >,
- std::is_convertible<U&&, T> >::value,
- bool>::type = false>
- optional(optional<U>&& rhs) {
- if (rhs) {
- this->construct(std::move(*rhs));
- }
- }
- // Converting move constructor (explicit)
- template <
- typename U,
- typename std::enable_if<
- phmap::conjunction<
- phmap::negation<std::is_same<T, U>>, std::is_constructible<T, U&&>,
- phmap::negation<
- optional_internal::is_constructible_convertible_from_optional<
- T, U>>,
- phmap::negation<std::is_convertible<U&&, T>>>::value,
- bool>::type = false>
- explicit optional(optional<U>&& rhs) {
- if (rhs) {
- this->construct(std::move(*rhs));
- }
- }
- // Destructor. Trivial if `T` is trivially destructible.
- ~optional() = default;
- // Assignment Operators
- // Assignment from `nullopt`
- //
- // Example:
- //
- // struct S { int value; };
- // optional<S> opt = phmap::nullopt; // Could also use opt = { };
- optional& operator=(nullopt_t) noexcept {
- this->destruct();
- return *this;
- }
- // Copy assignment operator, standard semantics
- optional& operator=(const optional& src) = default;
- // Move assignment operator, standard semantics
- optional& operator=(optional&& src) noexcept = default;
- // Value assignment operators
- template <
- typename U = T,
- typename = typename std::enable_if<phmap::conjunction<
- phmap::negation<
- std::is_same<optional<T>, typename std::decay<U>::type>>,
- phmap::negation<
- phmap::conjunction<std::is_scalar<T>,
- std::is_same<T, typename std::decay<U>::type>>>,
- std::is_constructible<T, U>, std::is_assignable<T&, U>>::value>::type>
- optional& operator=(U&& v) {
- this->assign(std::forward<U>(v));
- return *this;
- }
- template <
- typename U,
- typename = typename std::enable_if<phmap::conjunction<
- phmap::negation<std::is_same<T, U>>,
- std::is_constructible<T, const U&>, std::is_assignable<T&, const U&>,
- phmap::negation<
- optional_internal::
- is_constructible_convertible_assignable_from_optional<
- T, U>>>::value>::type>
- optional& operator=(const optional<U>& rhs) {
- if (rhs) {
- this->assign(*rhs);
- } else {
- this->destruct();
- }
- return *this;
- }
- template <typename U,
- typename = typename std::enable_if<phmap::conjunction<
- phmap::negation<std::is_same<T, U>>, std::is_constructible<T, U>,
- std::is_assignable<T&, U>,
- phmap::negation<
- optional_internal::
- is_constructible_convertible_assignable_from_optional<
- T, U>>>::value>::type>
- optional& operator=(optional<U>&& rhs) {
- if (rhs) {
- this->assign(std::move(*rhs));
- } else {
- this->destruct();
- }
- return *this;
- }
- // Modifiers
- // optional::reset()
- //
- // Destroys the inner `T` value of an `phmap::optional` if one is present.
- PHMAP_ATTRIBUTE_REINITIALIZES void reset() noexcept { this->destruct(); }
- // optional::emplace()
- //
- // (Re)constructs the underlying `T` in-place with the given forwarded
- // arguments.
- //
- // Example:
- //
- // optional<Foo> opt;
- // opt.emplace(arg1,arg2,arg3); // Constructs Foo(arg1,arg2,arg3)
- //
- // If the optional is non-empty, and the `args` refer to subobjects of the
- // current object, then behaviour is undefined, because the current object
- // will be destructed before the new object is constructed with `args`.
- template <typename... Args,
- typename = typename std::enable_if<
- std::is_constructible<T, Args&&...>::value>::type>
- T& emplace(Args&&... args) {
- this->destruct();
- this->construct(std::forward<Args>(args)...);
- return reference();
- }
- // Emplace reconstruction overload for an initializer list and the given
- // forwarded arguments.
- //
- // Example:
- //
- // struct Foo {
- // Foo(std::initializer_list<int>);
- // };
- //
- // optional<Foo> opt;
- // opt.emplace({1,2,3}); // Constructs Foo({1,2,3})
- template <typename U, typename... Args,
- typename = typename std::enable_if<std::is_constructible<
- T, std::initializer_list<U>&, Args&&...>::value>::type>
- T& emplace(std::initializer_list<U> il, Args&&... args) {
- this->destruct();
- this->construct(il, std::forward<Args>(args)...);
- return reference();
- }
- // Swaps
- // Swap, standard semantics
- void swap(optional& rhs) noexcept(
- std::is_nothrow_move_constructible<T>::value&&
- std::is_trivial<T>::value) {
- if (*this) {
- if (rhs) {
- using std::swap;
- swap(**this, *rhs);
- } else {
- rhs.construct(std::move(**this));
- this->destruct();
- }
- } else {
- if (rhs) {
- this->construct(std::move(*rhs));
- rhs.destruct();
- } else {
- // No effect (swap(disengaged, disengaged)).
- }
- }
- }
- // Observers
- // optional::operator->()
- //
- // Accesses the underlying `T` value's member `m` of an `optional`. If the
- // `optional` is empty, behavior is undefined.
- //
- // If you need myOpt->foo in constexpr, use (*myOpt).foo instead.
- const T* operator->() const {
- assert(this->engaged_);
- return std::addressof(this->data_);
- }
- T* operator->() {
- assert(this->engaged_);
- return std::addressof(this->data_);
- }
- // optional::operator*()
- //
- // Accesses the underlying `T` value of an `optional`. If the `optional` is
- // empty, behavior is undefined.
- constexpr const T& operator*() const & { return reference(); }
- T& operator*() & {
- assert(this->engaged_);
- return reference();
- }
- constexpr const T&& operator*() const && {
- return phmap::move(reference());
- }
- T&& operator*() && {
- assert(this->engaged_);
- return std::move(reference());
- }
- // optional::operator bool()
- //
- // Returns false if and only if the `optional` is empty.
- //
- // if (opt) {
- // // do something with opt.value();
- // } else {
- // // opt is empty.
- // }
- //
- constexpr explicit operator bool() const noexcept { return this->engaged_; }
- // optional::has_value()
- //
- // Determines whether the `optional` contains a value. Returns `false` if and
- // only if `*this` is empty.
- constexpr bool has_value() const noexcept { return this->engaged_; }
- // Suppress bogus warning on MSVC: MSVC complains call to reference() after
- // throw_bad_optional_access() is unreachable.
- #ifdef _MSC_VER
- #pragma warning(push)
- #pragma warning(disable : 4702)
- #endif // _MSC_VER
- // optional::value()
- //
- // Returns a reference to an `optional`s underlying value. The constness
- // and lvalue/rvalue-ness of the `optional` is preserved to the view of
- // the `T` sub-object. Throws `phmap::bad_optional_access` when the `optional`
- // is empty.
- constexpr const T& value() const & {
- return static_cast<bool>(*this)
- ? reference()
- : (optional_internal::throw_bad_optional_access(), reference());
- }
- T& value() & {
- return static_cast<bool>(*this)
- ? reference()
- : (optional_internal::throw_bad_optional_access(), reference());
- }
- T&& value() && { // NOLINT(build/c++11)
- return std::move(
- static_cast<bool>(*this)
- ? reference()
- : (optional_internal::throw_bad_optional_access(), reference()));
- }
- constexpr const T&& value() const && { // NOLINT(build/c++11)
- return phmap::move(
- static_cast<bool>(*this)
- ? reference()
- : (optional_internal::throw_bad_optional_access(), reference()));
- }
- #ifdef _MSC_VER
- #pragma warning(pop)
- #endif // _MSC_VER
- // optional::value_or()
- //
- // Returns either the value of `T` or a passed default `v` if the `optional`
- // is empty.
- template <typename U>
- constexpr T value_or(U&& v) const& {
- static_assert(std::is_copy_constructible<value_type>::value,
- "optional<T>::value_or: T must by copy constructible");
- static_assert(std::is_convertible<U&&, value_type>::value,
- "optional<T>::value_or: U must be convertible to T");
- return static_cast<bool>(*this)
- ? **this
- : static_cast<T>(phmap::forward<U>(v));
- }
- template <typename U>
- T value_or(U&& v) && { // NOLINT(build/c++11)
- static_assert(std::is_move_constructible<value_type>::value,
- "optional<T>::value_or: T must by move constructible");
- static_assert(std::is_convertible<U&&, value_type>::value,
- "optional<T>::value_or: U must be convertible to T");
- return static_cast<bool>(*this) ? std::move(**this)
- : static_cast<T>(std::forward<U>(v));
- }
- private:
- // Private accessors for internal storage viewed as reference to T.
- constexpr const T& reference() const { return this->data_; }
- T& reference() { return this->data_; }
- // T constraint checks. You can't have an optional of nullopt_t, in_place_t
- // or a reference.
- static_assert(
- !std::is_same<nullopt_t, typename std::remove_cv<T>::type>::value,
- "optional<nullopt_t> is not allowed.");
- static_assert(
- !std::is_same<in_place_t, typename std::remove_cv<T>::type>::value,
- "optional<in_place_t> is not allowed.");
- static_assert(!std::is_reference<T>::value,
- "optional<reference> is not allowed.");
- };
- // Non-member functions
- // swap()
- //
- // Performs a swap between two `phmap::optional` objects, using standard
- // semantics.
- //
- // NOTE: we assume `is_swappable()` is always `true`. A compile error will
- // result if this is not the case.
- template <typename T,
- typename std::enable_if<std::is_move_constructible<T>::value,
- bool>::type = false>
- void swap(optional<T>& a, optional<T>& b) noexcept(noexcept(a.swap(b))) {
- a.swap(b);
- }
- // make_optional()
- //
- // Creates a non-empty `optional<T>` where the type of `T` is deduced. An
- // `phmap::optional` can also be explicitly instantiated with
- // `make_optional<T>(v)`.
- //
- // Note: `make_optional()` constructions may be declared `constexpr` for
- // trivially copyable types `T`. Non-trivial types require copy elision
- // support in C++17 for `make_optional` to support `constexpr` on such
- // non-trivial types.
- //
- // Example:
- //
- // constexpr phmap::optional<int> opt = phmap::make_optional(1);
- // static_assert(opt.value() == 1, "");
- template <typename T>
- constexpr optional<typename std::decay<T>::type> make_optional(T&& v) {
- return optional<typename std::decay<T>::type>(phmap::forward<T>(v));
- }
- template <typename T, typename... Args>
- constexpr optional<T> make_optional(Args&&... args) {
- return optional<T>(in_place_t(), phmap::forward<Args>(args)...);
- }
- template <typename T, typename U, typename... Args>
- constexpr optional<T> make_optional(std::initializer_list<U> il,
- Args&&... args) {
- return optional<T>(in_place_t(), il,
- phmap::forward<Args>(args)...);
- }
- // Relational operators [optional.relops]
- // Empty optionals are considered equal to each other and less than non-empty
- // optionals. Supports relations between optional<T> and optional<U>, between
- // optional<T> and U, and between optional<T> and nullopt.
- //
- // Note: We're careful to support T having non-bool relationals.
- // Requires: The expression, e.g. "*x == *y" shall be well-formed and its result
- // shall be convertible to bool.
- // The C++17 (N4606) "Returns:" statements are translated into
- // code in an obvious way here, and the original text retained as function docs.
- // Returns: If bool(x) != bool(y), false; otherwise if bool(x) == false, true;
- // otherwise *x == *y.
- template <typename T, typename U>
- constexpr auto operator==(const optional<T>& x, const optional<U>& y)
- -> decltype(optional_internal::convertible_to_bool(*x == *y)) {
- return static_cast<bool>(x) != static_cast<bool>(y)
- ? false
- : static_cast<bool>(x) == false ? true
- : static_cast<bool>(*x == *y);
- }
- // Returns: If bool(x) != bool(y), true; otherwise, if bool(x) == false, false;
- // otherwise *x != *y.
- template <typename T, typename U>
- constexpr auto operator!=(const optional<T>& x, const optional<U>& y)
- -> decltype(optional_internal::convertible_to_bool(*x != *y)) {
- return static_cast<bool>(x) != static_cast<bool>(y)
- ? true
- : static_cast<bool>(x) == false ? false
- : static_cast<bool>(*x != *y);
- }
- // Returns: If !y, false; otherwise, if !x, true; otherwise *x < *y.
- template <typename T, typename U>
- constexpr auto operator<(const optional<T>& x, const optional<U>& y)
- -> decltype(optional_internal::convertible_to_bool(*x < *y)) {
- return !y ? false : !x ? true : static_cast<bool>(*x < *y);
- }
- // Returns: If !x, false; otherwise, if !y, true; otherwise *x > *y.
- template <typename T, typename U>
- constexpr auto operator>(const optional<T>& x, const optional<U>& y)
- -> decltype(optional_internal::convertible_to_bool(*x > *y)) {
- return !x ? false : !y ? true : static_cast<bool>(*x > *y);
- }
- // Returns: If !x, true; otherwise, if !y, false; otherwise *x <= *y.
- template <typename T, typename U>
- constexpr auto operator<=(const optional<T>& x, const optional<U>& y)
- -> decltype(optional_internal::convertible_to_bool(*x <= *y)) {
- return !x ? true : !y ? false : static_cast<bool>(*x <= *y);
- }
- // Returns: If !y, true; otherwise, if !x, false; otherwise *x >= *y.
- template <typename T, typename U>
- constexpr auto operator>=(const optional<T>& x, const optional<U>& y)
- -> decltype(optional_internal::convertible_to_bool(*x >= *y)) {
- return !y ? true : !x ? false : static_cast<bool>(*x >= *y);
- }
- // Comparison with nullopt [optional.nullops]
- // The C++17 (N4606) "Returns:" statements are used directly here.
- template <typename T>
- constexpr bool operator==(const optional<T>& x, nullopt_t) noexcept {
- return !x;
- }
- template <typename T>
- constexpr bool operator==(nullopt_t, const optional<T>& x) noexcept {
- return !x;
- }
- template <typename T>
- constexpr bool operator!=(const optional<T>& x, nullopt_t) noexcept {
- return static_cast<bool>(x);
- }
- template <typename T>
- constexpr bool operator!=(nullopt_t, const optional<T>& x) noexcept {
- return static_cast<bool>(x);
- }
- template <typename T>
- constexpr bool operator<(const optional<T>&, nullopt_t) noexcept {
- return false;
- }
- template <typename T>
- constexpr bool operator<(nullopt_t, const optional<T>& x) noexcept {
- return static_cast<bool>(x);
- }
- template <typename T>
- constexpr bool operator<=(const optional<T>& x, nullopt_t) noexcept {
- return !x;
- }
- template <typename T>
- constexpr bool operator<=(nullopt_t, const optional<T>&) noexcept {
- return true;
- }
- template <typename T>
- constexpr bool operator>(const optional<T>& x, nullopt_t) noexcept {
- return static_cast<bool>(x);
- }
- template <typename T>
- constexpr bool operator>(nullopt_t, const optional<T>&) noexcept {
- return false;
- }
- template <typename T>
- constexpr bool operator>=(const optional<T>&, nullopt_t) noexcept {
- return true;
- }
- template <typename T>
- constexpr bool operator>=(nullopt_t, const optional<T>& x) noexcept {
- return !x;
- }
- // Comparison with T [optional.comp_with_t]
- // Requires: The expression, e.g. "*x == v" shall be well-formed and its result
- // shall be convertible to bool.
- // The C++17 (N4606) "Equivalent to:" statements are used directly here.
- template <typename T, typename U>
- constexpr auto operator==(const optional<T>& x, const U& v)
- -> decltype(optional_internal::convertible_to_bool(*x == v)) {
- return static_cast<bool>(x) ? static_cast<bool>(*x == v) : false;
- }
- template <typename T, typename U>
- constexpr auto operator==(const U& v, const optional<T>& x)
- -> decltype(optional_internal::convertible_to_bool(v == *x)) {
- return static_cast<bool>(x) ? static_cast<bool>(v == *x) : false;
- }
- template <typename T, typename U>
- constexpr auto operator!=(const optional<T>& x, const U& v)
- -> decltype(optional_internal::convertible_to_bool(*x != v)) {
- return static_cast<bool>(x) ? static_cast<bool>(*x != v) : true;
- }
- template <typename T, typename U>
- constexpr auto operator!=(const U& v, const optional<T>& x)
- -> decltype(optional_internal::convertible_to_bool(v != *x)) {
- return static_cast<bool>(x) ? static_cast<bool>(v != *x) : true;
- }
- template <typename T, typename U>
- constexpr auto operator<(const optional<T>& x, const U& v)
- -> decltype(optional_internal::convertible_to_bool(*x < v)) {
- return static_cast<bool>(x) ? static_cast<bool>(*x < v) : true;
- }
- template <typename T, typename U>
- constexpr auto operator<(const U& v, const optional<T>& x)
- -> decltype(optional_internal::convertible_to_bool(v < *x)) {
- return static_cast<bool>(x) ? static_cast<bool>(v < *x) : false;
- }
- template <typename T, typename U>
- constexpr auto operator<=(const optional<T>& x, const U& v)
- -> decltype(optional_internal::convertible_to_bool(*x <= v)) {
- return static_cast<bool>(x) ? static_cast<bool>(*x <= v) : true;
- }
- template <typename T, typename U>
- constexpr auto operator<=(const U& v, const optional<T>& x)
- -> decltype(optional_internal::convertible_to_bool(v <= *x)) {
- return static_cast<bool>(x) ? static_cast<bool>(v <= *x) : false;
- }
- template <typename T, typename U>
- constexpr auto operator>(const optional<T>& x, const U& v)
- -> decltype(optional_internal::convertible_to_bool(*x > v)) {
- return static_cast<bool>(x) ? static_cast<bool>(*x > v) : false;
- }
- template <typename T, typename U>
- constexpr auto operator>(const U& v, const optional<T>& x)
- -> decltype(optional_internal::convertible_to_bool(v > *x)) {
- return static_cast<bool>(x) ? static_cast<bool>(v > *x) : true;
- }
- template <typename T, typename U>
- constexpr auto operator>=(const optional<T>& x, const U& v)
- -> decltype(optional_internal::convertible_to_bool(*x >= v)) {
- return static_cast<bool>(x) ? static_cast<bool>(*x >= v) : false;
- }
- template <typename T, typename U>
- constexpr auto operator>=(const U& v, const optional<T>& x)
- -> decltype(optional_internal::convertible_to_bool(v >= *x)) {
- return static_cast<bool>(x) ? static_cast<bool>(v >= *x) : true;
- }
- } // namespace phmap
- namespace std {
- // std::hash specialization for phmap::optional.
- template <typename T>
- struct hash<phmap::optional<T> >
- : phmap::optional_internal::optional_hash_base<T> {};
- } // namespace std
- #endif
- // -----------------------------------------------------------------------------
- // common.h
- // -----------------------------------------------------------------------------
- namespace phmap {
- namespace priv {
- template <class, class = void>
- struct IsTransparent : std::false_type {};
- template <class T>
- struct IsTransparent<T, phmap::void_t<typename T::is_transparent>>
- : std::true_type {};
- template <bool is_transparent>
- struct KeyArg
- {
- // Transparent. Forward `K`.
- template <typename K, typename key_type>
- using type = K;
- };
- template <>
- struct KeyArg<false>
- {
- // Not transparent. Always use `key_type`.
- template <typename K, typename key_type>
- using type = key_type;
- };
- #ifdef _MSC_VER
- #pragma warning(push)
- // warning C4820: '6' bytes padding added after data member
- #pragma warning(disable : 4820)
- #endif
- // The node_handle concept from C++17.
- // We specialize node_handle for sets and maps. node_handle_base holds the
- // common API of both.
- // -----------------------------------------------------------------------
- template <typename PolicyTraits, typename Alloc>
- class node_handle_base
- {
- protected:
- using slot_type = typename PolicyTraits::slot_type;
- public:
- using allocator_type = Alloc;
- constexpr node_handle_base() {}
- node_handle_base(node_handle_base&& other) noexcept {
- *this = std::move(other);
- }
- ~node_handle_base() { destroy(); }
- node_handle_base& operator=(node_handle_base&& other) noexcept {
- destroy();
- if (!other.empty()) {
- alloc_ = other.alloc_;
- PolicyTraits::transfer(alloc(), slot(), other.slot());
- other.reset();
- }
- return *this;
- }
- bool empty() const noexcept { return !alloc_; }
- explicit operator bool() const noexcept { return !empty(); }
- allocator_type get_allocator() const { return *alloc_; }
- protected:
- friend struct CommonAccess;
- struct transfer_tag_t {};
- node_handle_base(transfer_tag_t, const allocator_type& a, slot_type* s)
- : alloc_(a) {
- PolicyTraits::transfer(alloc(), slot(), s);
- }
- struct move_tag_t {};
- node_handle_base(move_tag_t, const allocator_type& a, slot_type* s)
- : alloc_(a) {
- PolicyTraits::construct(alloc(), slot(), s);
- }
- node_handle_base(const allocator_type& a, slot_type* s) : alloc_(a) {
- PolicyTraits::transfer(alloc(), slot(), s);
- }
- //node_handle_base(const node_handle_base&) = delete;
- //node_handle_base& operator=(const node_handle_base&) = delete;
- void destroy() {
- if (!empty()) {
- PolicyTraits::destroy(alloc(), slot());
- reset();
- }
- }
- void reset() {
- assert(alloc_.has_value());
- alloc_ = phmap::nullopt;
- }
- slot_type* slot() const {
- assert(!empty());
- return reinterpret_cast<slot_type*>(std::addressof(slot_space_));
- }
- allocator_type* alloc() { return std::addressof(*alloc_); }
- private:
- phmap::optional<allocator_type> alloc_;
- mutable phmap::aligned_storage_t<sizeof(slot_type), alignof(slot_type)> slot_space_;
- };
- #ifdef _MSC_VER
- #pragma warning(pop)
- #endif
- // For sets.
- // ---------
- template <typename Policy, typename PolicyTraits, typename Alloc,
- typename = void>
- class node_handle : public node_handle_base<PolicyTraits, Alloc>
- {
- using Base = node_handle_base<PolicyTraits, Alloc>;
- public:
- using value_type = typename PolicyTraits::value_type;
- constexpr node_handle() {}
- value_type& value() const { return PolicyTraits::element(this->slot()); }
- value_type& key() const { return PolicyTraits::element(this->slot()); }
- private:
- friend struct CommonAccess;
- using Base::Base;
- };
- // For maps.
- // ---------
- template <typename Policy, typename PolicyTraits, typename Alloc>
- class node_handle<Policy, PolicyTraits, Alloc,
- phmap::void_t<typename Policy::mapped_type>>
- : public node_handle_base<PolicyTraits, Alloc>
- {
- using Base = node_handle_base<PolicyTraits, Alloc>;
- using slot_type = typename PolicyTraits::slot_type;
- public:
- using key_type = typename Policy::key_type;
- using mapped_type = typename Policy::mapped_type;
- constexpr node_handle() {}
- auto key() const -> decltype(PolicyTraits::key(this->slot())) {
- return PolicyTraits::key(this->slot());
- }
- mapped_type& mapped() const {
- return PolicyTraits::value(&PolicyTraits::element(this->slot()));
- }
- private:
- friend struct CommonAccess;
- using Base::Base;
- };
- // Provide access to non-public node-handle functions.
- struct CommonAccess
- {
- template <typename Node>
- static auto GetSlot(const Node& node) -> decltype(node.slot()) {
- return node.slot();
- }
- template <typename Node>
- static void Destroy(Node* node) {
- node->destroy();
- }
- template <typename Node>
- static void Reset(Node* node) {
- node->reset();
- }
- template <typename T, typename... Args>
- static T Make(Args&&... args) {
- return T(std::forward<Args>(args)...);
- }
- template <typename T, typename... Args>
- static T Transfer(Args&&... args) {
- return T(typename T::transfer_tag_t{}, std::forward<Args>(args)...);
- }
- template <typename T, typename... Args>
- static T Move(Args&&... args) {
- return T(typename T::move_tag_t{}, std::forward<Args>(args)...);
- }
- };
- // Implement the insert_return_type<> concept of C++17.
- template <class Iterator, class NodeType>
- struct InsertReturnType
- {
- Iterator position;
- bool inserted;
- NodeType node;
- };
- } // namespace priv
- } // namespace phmap
- #ifdef ADDRESS_SANITIZER
- #include <sanitizer/asan_interface.h>
- #endif
- // ---------------------------------------------------------------------------
- // span.h
- // ---------------------------------------------------------------------------
- namespace phmap {
- template <typename T>
- class Span;
- namespace span_internal {
- // A constexpr min function
- constexpr size_t Min(size_t a, size_t b) noexcept { return a < b ? a : b; }
- // Wrappers for access to container data pointers.
- template <typename C>
- constexpr auto GetDataImpl(C& c, char) noexcept // NOLINT(runtime/references)
- -> decltype(c.data()) {
- return c.data();
- }
- // Before C++17, std::string::data returns a const char* in all cases.
- LL_INLINE char* GetDataImpl(std::string& s, // NOLINT(runtime/references)
- int) noexcept {
- return &s[0];
- }
- template <typename C>
- constexpr auto GetData(C& c) noexcept // NOLINT(runtime/references)
- -> decltype(GetDataImpl(c, 0)) {
- return GetDataImpl(c, 0);
- }
- // Detection idioms for size() and data().
- template <typename C>
- using HasSize =
- std::is_integral<phmap::decay_t<decltype(std::declval<C&>().size())>>;
- // We want to enable conversion from vector<T*> to Span<const T* const> but
- // disable conversion from vector<Derived> to Span<Base>. Here we use
- // the fact that U** is convertible to Q* const* if and only if Q is the same
- // type or a more cv-qualified version of U. We also decay the result type of
- // data() to avoid problems with classes which have a member function data()
- // which returns a reference.
- template <typename T, typename C>
- using HasData =
- std::is_convertible<phmap::decay_t<decltype(GetData(std::declval<C&>()))>*,
- T* const*>;
- // Extracts value type from a Container
- template <typename C>
- struct ElementType {
- using type = typename phmap::remove_reference_t<C>::value_type;
- };
- template <typename T, size_t N>
- struct ElementType<T (&)[N]> {
- using type = T;
- };
- template <typename C>
- using ElementT = typename ElementType<C>::type;
- template <typename T>
- using EnableIfMutable =
- typename std::enable_if<!std::is_const<T>::value, int>::type;
- template <typename T>
- bool EqualImpl(Span<T> a, Span<T> b) {
- static_assert(std::is_const<T>::value, "");
- return std::equal(a.begin(), a.end(), b.begin(), b.end());
- }
- template <typename T>
- bool LessThanImpl(Span<T> a, Span<T> b) {
- static_assert(std::is_const<T>::value, "");
- return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end());
- }
- // The `IsConvertible` classes here are needed because of the
- // `std::is_convertible` bug in libcxx when compiled with GCC. This build
- // configuration is used by Android NDK toolchain. Reference link:
- // https://bugs.llvm.org/show_bug.cgi?id=27538.
- template <typename From, typename To>
- struct IsConvertibleHelper {
- static std::true_type testval(To);
- static std::false_type testval(...);
- using type = decltype(testval(std::declval<From>()));
- };
- template <typename From, typename To>
- struct IsConvertible : IsConvertibleHelper<From, To>::type {};
- // TODO(zhangxy): replace `IsConvertible` with `std::is_convertible` once the
- // older version of libcxx is not supported.
- template <typename From, typename To>
- using EnableIfConvertibleToSpanConst =
- typename std::enable_if<IsConvertible<From, Span<const To>>::value>::type;
- } // namespace span_internal
- //------------------------------------------------------------------------------
- // Span
- //------------------------------------------------------------------------------
- //
- // A `Span` is an "array view" type for holding a view of a contiguous data
- // array; the `Span` object does not and cannot own such data itself. A span
- // provides an easy way to provide overloads for anything operating on
- // contiguous sequences without needing to manage pointers and array lengths
- // manually.
- // A span is conceptually a pointer (ptr) and a length (size) into an already
- // existing array of contiguous memory; the array it represents references the
- // elements "ptr[0] .. ptr[size-1]". Passing a properly-constructed `Span`
- // instead of raw pointers avoids many issues related to index out of bounds
- // errors.
- //
- // Spans may also be constructed from containers holding contiguous sequences.
- // Such containers must supply `data()` and `size() const` methods (e.g
- // `std::vector<T>`, `phmap::InlinedVector<T, N>`). All implicit conversions to
- // `phmap::Span` from such containers will create spans of type `const T`;
- // spans which can mutate their values (of type `T`) must use explicit
- // constructors.
- //
- // A `Span<T>` is somewhat analogous to an `phmap::string_view`, but for an array
- // of elements of type `T`. A user of `Span` must ensure that the data being
- // pointed to outlives the `Span` itself.
- //
- // You can construct a `Span<T>` in several ways:
- //
- // * Explicitly from a reference to a container type
- // * Explicitly from a pointer and size
- // * Implicitly from a container type (but only for spans of type `const T`)
- // * Using the `MakeSpan()` or `MakeConstSpan()` factory functions.
- //
- // Examples:
- //
- // // Construct a Span explicitly from a container:
- // std::vector<int> v = {1, 2, 3, 4, 5};
- // auto span = phmap::Span<const int>(v);
- //
- // // Construct a Span explicitly from a C-style array:
- // int a[5] = {1, 2, 3, 4, 5};
- // auto span = phmap::Span<const int>(a);
- //
- // // Construct a Span implicitly from a container
- // void MyRoutine(phmap::Span<const int> a) {
- // ...
- // }
- // std::vector v = {1,2,3,4,5};
- // MyRoutine(v) // convert to Span<const T>
- //
- // Note that `Span` objects, in addition to requiring that the memory they
- // point to remains alive, must also ensure that such memory does not get
- // reallocated. Therefore, to avoid undefined behavior, containers with
- // associated span views should not invoke operations that may reallocate memory
- // (such as resizing) or invalidate iterators into the container.
- //
- // One common use for a `Span` is when passing arguments to a routine that can
- // accept a variety of array types (e.g. a `std::vector`, `phmap::InlinedVector`,
- // a C-style array, etc.). Instead of creating overloads for each case, you
- // can simply specify a `Span` as the argument to such a routine.
- //
- // Example:
- //
- // void MyRoutine(phmap::Span<const int> a) {
- // ...
- // }
- //
- // std::vector v = {1,2,3,4,5};
- // MyRoutine(v);
- //
- // phmap::InlinedVector<int, 4> my_inline_vector;
- // MyRoutine(my_inline_vector);
- //
- // // Explicit constructor from pointer,size
- // int* my_array = new int[10];
- // MyRoutine(phmap::Span<const int>(my_array, 10));
- template <typename T>
- class Span
- {
- private:
- // Used to determine whether a Span can be constructed from a container of
- // type C.
- template <typename C>
- using EnableIfConvertibleFrom =
- typename std::enable_if<span_internal::HasData<T, C>::value &&
- span_internal::HasSize<C>::value>::type;
- // Used to SFINAE-enable a function when the slice elements are const.
- template <typename U>
- using EnableIfConstView =
- typename std::enable_if<std::is_const<T>::value, U>::type;
- // Used to SFINAE-enable a function when the slice elements are mutable.
- template <typename U>
- using EnableIfMutableView =
- typename std::enable_if<!std::is_const<T>::value, U>::type;
- public:
- using value_type = phmap::remove_cv_t<T>;
- using pointer = T*;
- using const_pointer = const T*;
- using reference = T&;
- using const_reference = const T&;
- using iterator = pointer;
- using const_iterator = const_pointer;
- using reverse_iterator = std::reverse_iterator<iterator>;
- using const_reverse_iterator = std::reverse_iterator<const_iterator>;
- using size_type = size_t;
- using difference_type = ptrdiff_t;
- static const size_type npos = ~(size_type(0));
- constexpr Span() noexcept : Span(nullptr, 0) {}
- constexpr Span(pointer array, size_type lgth) noexcept
- : ptr_(array), len_(lgth) {}
- // Implicit conversion constructors
- template <size_t N>
- constexpr Span(T (&a)[N]) noexcept // NOLINT(runtime/explicit)
- : Span(a, N) {}
- // Explicit reference constructor for a mutable `Span<T>` type. Can be
- // replaced with MakeSpan() to infer the type parameter.
- template <typename V, typename = EnableIfConvertibleFrom<V>,
- typename = EnableIfMutableView<V>>
- explicit Span(V& v) noexcept // NOLINT(runtime/references)
- : Span(span_internal::GetData(v), v.size()) {}
- // Implicit reference constructor for a read-only `Span<const T>` type
- template <typename V, typename = EnableIfConvertibleFrom<V>,
- typename = EnableIfConstView<V>>
- constexpr Span(const V& v) noexcept // NOLINT(runtime/explicit)
- : Span(span_internal::GetData(v), v.size()) {}
- // Implicit constructor from an initializer list, making it possible to pass a
- // brace-enclosed initializer list to a function expecting a `Span`. Such
- // spans constructed from an initializer list must be of type `Span<const T>`.
- //
- // void Process(phmap::Span<const int> x);
- // Process({1, 2, 3});
- //
- // Note that as always the array referenced by the span must outlive the span.
- // Since an initializer list constructor acts as if it is fed a temporary
- // array (cf. C++ standard [dcl.init.list]/5), it's safe to use this
- // constructor only when the `std::initializer_list` itself outlives the span.
- // In order to meet this requirement it's sufficient to ensure that neither
- // the span nor a copy of it is used outside of the expression in which it's
- // created:
- //
- // // Assume that this function uses the array directly, not retaining any
- // // copy of the span or pointer to any of its elements.
- // void Process(phmap::Span<const int> ints);
- //
- // // Okay: the std::initializer_list<int> will reference a temporary array
- // // that isn't destroyed until after the call to Process returns.
- // Process({ 17, 19 });
- //
- // // Not okay: the storage used by the std::initializer_list<int> is not
- // // allowed to be referenced after the first line.
- // phmap::Span<const int> ints = { 17, 19 };
- // Process(ints);
- //
- // // Not okay for the same reason as above: even when the elements of the
- // // initializer list expression are not temporaries the underlying array
- // // is, so the initializer list must still outlive the span.
- // const int foo = 17;
- // phmap::Span<const int> ints = { foo };
- // Process(ints);
- //
- template <typename LazyT = T,
- typename = EnableIfConstView<LazyT>>
- Span(
- std::initializer_list<value_type> v) noexcept // NOLINT(runtime/explicit)
- : Span(v.begin(), v.size()) {}
- // Accessors
- // Span::data()
- //
- // Returns a pointer to the span's underlying array of data (which is held
- // outside the span).
- constexpr pointer data() const noexcept { return ptr_; }
- // Span::size()
- //
- // Returns the size of this span.
- constexpr size_type size() const noexcept { return len_; }
- // Span::length()
- //
- // Returns the length (size) of this span.
- constexpr size_type length() const noexcept { return size(); }
- // Span::empty()
- //
- // Returns a boolean indicating whether or not this span is considered empty.
- constexpr bool empty() const noexcept { return size() == 0; }
- // Span::operator[]
- //
- // Returns a reference to the i'th element of this span.
- constexpr reference operator[](size_type i) const noexcept {
- // MSVC 2015 accepts this as constexpr, but not ptr_[i]
- return *(data() + i);
- }
- // Span::at()
- //
- // Returns a reference to the i'th element of this span.
- constexpr reference at(size_type i) const {
- return PHMAP_PREDICT_TRUE(i < size()) //
- ? *(data() + i)
- : (base_internal::ThrowStdOutOfRange(
- "Span::at failed bounds check"),
- *(data() + i));
- }
- // Span::front()
- //
- // Returns a reference to the first element of this span.
- constexpr reference front() const noexcept {
- return PHMAP_ASSERT(size() > 0), *data();
- }
- // Span::back()
- //
- // Returns a reference to the last element of this span.
- constexpr reference back() const noexcept {
- return PHMAP_ASSERT(size() > 0), *(data() + size() - 1);
- }
- // Span::begin()
- //
- // Returns an iterator to the first element of this span.
- constexpr iterator begin() const noexcept { return data(); }
- // Span::cbegin()
- //
- // Returns a const iterator to the first element of this span.
- constexpr const_iterator cbegin() const noexcept { return begin(); }
- // Span::end()
- //
- // Returns an iterator to the last element of this span.
- constexpr iterator end() const noexcept { return data() + size(); }
- // Span::cend()
- //
- // Returns a const iterator to the last element of this span.
- constexpr const_iterator cend() const noexcept { return end(); }
- // Span::rbegin()
- //
- // Returns a reverse iterator starting at the last element of this span.
- constexpr reverse_iterator rbegin() const noexcept {
- return reverse_iterator(end());
- }
- // Span::crbegin()
- //
- // Returns a reverse const iterator starting at the last element of this span.
- constexpr const_reverse_iterator crbegin() const noexcept { return rbegin(); }
- // Span::rend()
- //
- // Returns a reverse iterator starting at the first element of this span.
- constexpr reverse_iterator rend() const noexcept {
- return reverse_iterator(begin());
- }
- // Span::crend()
- //
- // Returns a reverse iterator starting at the first element of this span.
- constexpr const_reverse_iterator crend() const noexcept { return rend(); }
- // Span mutations
- // Span::remove_prefix()
- //
- // Removes the first `n` elements from the span.
- void remove_prefix(size_type n) noexcept {
- assert(size() >= n);
- ptr_ += n;
- len_ -= n;
- }
- // Span::remove_suffix()
- //
- // Removes the last `n` elements from the span.
- void remove_suffix(size_type n) noexcept {
- assert(size() >= n);
- len_ -= n;
- }
- // Span::subspan()
- //
- // Returns a `Span` starting at element `pos` and of length `len`. Both `pos`
- // and `len` are of type `size_type` and thus non-negative. Parameter `pos`
- // must be <= size(). Any `len` value that points past the end of the span
- // will be trimmed to at most size() - `pos`. A default `len` value of `npos`
- // ensures the returned subspan continues until the end of the span.
- //
- // Examples:
- //
- // std::vector<int> vec = {10, 11, 12, 13};
- // phmap::MakeSpan(vec).subspan(1, 2); // {11, 12}
- // phmap::MakeSpan(vec).subspan(2, 8); // {12, 13}
- // phmap::MakeSpan(vec).subspan(1); // {11, 12, 13}
- // phmap::MakeSpan(vec).subspan(4); // {}
- // phmap::MakeSpan(vec).subspan(5); // throws std::out_of_range
- constexpr Span subspan(size_type pos = 0, size_type len = npos) const {
- return (pos <= size())
- ? Span(data() + pos, span_internal::Min(size() - pos, len))
- : (base_internal::ThrowStdOutOfRange("pos > size()"), Span());
- }
- // Span::first()
- //
- // Returns a `Span` containing first `len` elements. Parameter `len` is of
- // type `size_type` and thus non-negative. `len` value must be <= size().
- //
- // Examples:
- //
- // std::vector<int> vec = {10, 11, 12, 13};
- // phmap::MakeSpan(vec).first(1); // {10}
- // phmap::MakeSpan(vec).first(3); // {10, 11, 12}
- // phmap::MakeSpan(vec).first(5); // throws std::out_of_range
- constexpr Span first(size_type len) const {
- return (len <= size())
- ? Span(data(), len)
- : (base_internal::ThrowStdOutOfRange("len > size()"), Span());
- }
- // Span::last()
- //
- // Returns a `Span` containing last `len` elements. Parameter `len` is of
- // type `size_type` and thus non-negative. `len` value must be <= size().
- //
- // Examples:
- //
- // std::vector<int> vec = {10, 11, 12, 13};
- // phmap::MakeSpan(vec).last(1); // {13}
- // phmap::MakeSpan(vec).last(3); // {11, 12, 13}
- // phmap::MakeSpan(vec).last(5); // throws std::out_of_range
- constexpr Span last(size_type len) const {
- return (len <= size())
- ? Span(size() - len + data(), len)
- : (base_internal::ThrowStdOutOfRange("len > size()"), Span());
- }
- // Support for phmap::Hash.
- template <typename H>
- friend H AbslHashValue(H h, Span v) {
- return H::combine(H::combine_contiguous(std::move(h), v.data(), v.size()),
- v.size());
- }
- private:
- pointer ptr_;
- size_type len_;
- };
- template <typename T>
- const typename Span<T>::size_type Span<T>::npos;
- // Span relationals
- // Equality is compared element-by-element, while ordering is lexicographical.
- // We provide three overloads for each operator to cover any combination on the
- // left or right hand side of mutable Span<T>, read-only Span<const T>, and
- // convertible-to-read-only Span<T>.
- // TODO(zhangxy): Due to MSVC overload resolution bug with partial ordering
- // template functions, 5 overloads per operator is needed as a workaround. We
- // should update them to 3 overloads per operator using non-deduced context like
- // string_view, i.e.
- // - (Span<T>, Span<T>)
- // - (Span<T>, non_deduced<Span<const T>>)
- // - (non_deduced<Span<const T>>, Span<T>)
- // operator==
- template <typename T>
- bool operator==(Span<T> a, Span<T> b) {
- return span_internal::EqualImpl<const T>(a, b);
- }
- template <typename T>
- bool operator==(Span<const T> a, Span<T> b) {
- return span_internal::EqualImpl<const T>(a, b);
- }
- template <typename T>
- bool operator==(Span<T> a, Span<const T> b) {
- return span_internal::EqualImpl<const T>(a, b);
- }
- template <typename T, typename U,
- typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
- bool operator==(const U& a, Span<T> b) {
- return span_internal::EqualImpl<const T>(a, b);
- }
- template <typename T, typename U,
- typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
- bool operator==(Span<T> a, const U& b) {
- return span_internal::EqualImpl<const T>(a, b);
- }
- // operator!=
- template <typename T>
- bool operator!=(Span<T> a, Span<T> b) {
- return !(a == b);
- }
- template <typename T>
- bool operator!=(Span<const T> a, Span<T> b) {
- return !(a == b);
- }
- template <typename T>
- bool operator!=(Span<T> a, Span<const T> b) {
- return !(a == b);
- }
- template <typename T, typename U,
- typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
- bool operator!=(const U& a, Span<T> b) {
- return !(a == b);
- }
- template <typename T, typename U,
- typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
- bool operator!=(Span<T> a, const U& b) {
- return !(a == b);
- }
- // operator<
- template <typename T>
- bool operator<(Span<T> a, Span<T> b) {
- return span_internal::LessThanImpl<const T>(a, b);
- }
- template <typename T>
- bool operator<(Span<const T> a, Span<T> b) {
- return span_internal::LessThanImpl<const T>(a, b);
- }
- template <typename T>
- bool operator<(Span<T> a, Span<const T> b) {
- return span_internal::LessThanImpl<const T>(a, b);
- }
- template <typename T, typename U,
- typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
- bool operator<(const U& a, Span<T> b) {
- return span_internal::LessThanImpl<const T>(a, b);
- }
- template <typename T, typename U,
- typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
- bool operator<(Span<T> a, const U& b) {
- return span_internal::LessThanImpl<const T>(a, b);
- }
- // operator>
- template <typename T>
- bool operator>(Span<T> a, Span<T> b) {
- return b < a;
- }
- template <typename T>
- bool operator>(Span<const T> a, Span<T> b) {
- return b < a;
- }
- template <typename T>
- bool operator>(Span<T> a, Span<const T> b) {
- return b < a;
- }
- template <typename T, typename U,
- typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
- bool operator>(const U& a, Span<T> b) {
- return b < a;
- }
- template <typename T, typename U,
- typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
- bool operator>(Span<T> a, const U& b) {
- return b < a;
- }
- // operator<=
- template <typename T>
- bool operator<=(Span<T> a, Span<T> b) {
- return !(b < a);
- }
- template <typename T>
- bool operator<=(Span<const T> a, Span<T> b) {
- return !(b < a);
- }
- template <typename T>
- bool operator<=(Span<T> a, Span<const T> b) {
- return !(b < a);
- }
- template <typename T, typename U,
- typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
- bool operator<=(const U& a, Span<T> b) {
- return !(b < a);
- }
- template <typename T, typename U,
- typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
- bool operator<=(Span<T> a, const U& b) {
- return !(b < a);
- }
- // operator>=
- template <typename T>
- bool operator>=(Span<T> a, Span<T> b) {
- return !(a < b);
- }
- template <typename T>
- bool operator>=(Span<const T> a, Span<T> b) {
- return !(a < b);
- }
- template <typename T>
- bool operator>=(Span<T> a, Span<const T> b) {
- return !(a < b);
- }
- template <typename T, typename U,
- typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
- bool operator>=(const U& a, Span<T> b) {
- return !(a < b);
- }
- template <typename T, typename U,
- typename = span_internal::EnableIfConvertibleToSpanConst<U, T>>
- bool operator>=(Span<T> a, const U& b) {
- return !(a < b);
- }
- // MakeSpan()
- //
- // Constructs a mutable `Span<T>`, deducing `T` automatically from either a
- // container or pointer+size.
- //
- // Because a read-only `Span<const T>` is implicitly constructed from container
- // types regardless of whether the container itself is a const container,
- // constructing mutable spans of type `Span<T>` from containers requires
- // explicit constructors. The container-accepting version of `MakeSpan()`
- // deduces the type of `T` by the constness of the pointer received from the
- // container's `data()` member. Similarly, the pointer-accepting version returns
- // a `Span<const T>` if `T` is `const`, and a `Span<T>` otherwise.
- //
- // Examples:
- //
- // void MyRoutine(phmap::Span<MyComplicatedType> a) {
- // ...
- // };
- // // my_vector is a container of non-const types
- // std::vector<MyComplicatedType> my_vector;
- //
- // // Constructing a Span implicitly attempts to create a Span of type
- // // `Span<const T>`
- // MyRoutine(my_vector); // error, type mismatch
- //
- // // Explicitly constructing the Span is verbose
- // MyRoutine(phmap::Span<MyComplicatedType>(my_vector));
- //
- // // Use MakeSpan() to make an phmap::Span<T>
- // MyRoutine(phmap::MakeSpan(my_vector));
- //
- // // Construct a span from an array ptr+size
- // phmap::Span<T> my_span() {
- // return phmap::MakeSpan(&array[0], num_elements_);
- // }
- //
- template <int&... ExplicitArgumentBarrier, typename T>
- constexpr Span<T> MakeSpan(T* ptr, size_t size) noexcept {
- return Span<T>(ptr, size);
- }
- template <int&... ExplicitArgumentBarrier, typename T>
- Span<T> MakeSpan(T* begin, T* end) noexcept {
- return PHMAP_ASSERT(begin <= end), Span<T>(begin, end - begin);
- }
- template <int&... ExplicitArgumentBarrier, typename C>
- constexpr auto MakeSpan(C& c) noexcept // NOLINT(runtime/references)
- -> decltype(phmap::MakeSpan(span_internal::GetData(c), c.size())) {
- return MakeSpan(span_internal::GetData(c), c.size());
- }
- template <int&... ExplicitArgumentBarrier, typename T, size_t N>
- constexpr Span<T> MakeSpan(T (&array)[N]) noexcept {
- return Span<T>(array, N);
- }
- // MakeConstSpan()
- //
- // Constructs a `Span<const T>` as with `MakeSpan`, deducing `T` automatically,
- // but always returning a `Span<const T>`.
- //
- // Examples:
- //
- // void ProcessInts(phmap::Span<const int> some_ints);
- //
- // // Call with a pointer and size.
- // int array[3] = { 0, 0, 0 };
- // ProcessInts(phmap::MakeConstSpan(&array[0], 3));
- //
- // // Call with a [begin, end) pair.
- // ProcessInts(phmap::MakeConstSpan(&array[0], &array[3]));
- //
- // // Call directly with an array.
- // ProcessInts(phmap::MakeConstSpan(array));
- //
- // // Call with a contiguous container.
- // std::vector<int> some_ints = ...;
- // ProcessInts(phmap::MakeConstSpan(some_ints));
- // ProcessInts(phmap::MakeConstSpan(std::vector<int>{ 0, 0, 0 }));
- //
- template <int&... ExplicitArgumentBarrier, typename T>
- constexpr Span<const T> MakeConstSpan(T* ptr, size_t size) noexcept {
- return Span<const T>(ptr, size);
- }
- template <int&... ExplicitArgumentBarrier, typename T>
- Span<const T> MakeConstSpan(T* begin, T* end) noexcept {
- return PHMAP_ASSERT(begin <= end), Span<const T>(begin, end - begin);
- }
- template <int&... ExplicitArgumentBarrier, typename C>
- constexpr auto MakeConstSpan(const C& c) noexcept -> decltype(MakeSpan(c)) {
- return MakeSpan(c);
- }
- template <int&... ExplicitArgumentBarrier, typename T, size_t N>
- constexpr Span<const T> MakeConstSpan(const T (&array)[N]) noexcept {
- return Span<const T>(array, N);
- }
- } // namespace phmap
- // ---------------------------------------------------------------------------
- // layout.h
- // ---------------------------------------------------------------------------
- namespace phmap {
- namespace priv {
- // A type wrapper that instructs `Layout` to use the specific alignment for the
- // array. `Layout<..., Aligned<T, N>, ...>` has exactly the same API
- // and behavior as `Layout<..., T, ...>` except that the first element of the
- // array of `T` is aligned to `N` (the rest of the elements follow without
- // padding).
- //
- // Requires: `N >= alignof(T)` and `N` is a power of 2.
- template <class T, size_t N>
- struct Aligned;
- namespace internal_layout {
- template <class T>
- struct NotAligned {};
- template <class T, size_t N>
- struct NotAligned<const Aligned<T, N>> {
- static_assert(sizeof(T) == 0, "Aligned<T, N> cannot be const-qualified");
- };
- template <size_t>
- using IntToSize = size_t;
- template <class>
- using TypeToSize = size_t;
- template <class T>
- struct Type : NotAligned<T> {
- using type = T;
- };
- template <class T, size_t N>
- struct Type<Aligned<T, N>> {
- using type = T;
- };
- template <class T>
- struct SizeOf : NotAligned<T>, std::integral_constant<size_t, sizeof(T)> {};
- template <class T, size_t N>
- struct SizeOf<Aligned<T, N>> : std::integral_constant<size_t, sizeof(T)> {};
- // Note: workaround for https://gcc.gnu.org/PR88115
- template <class T>
- struct AlignOf : NotAligned<T> {
- static constexpr size_t value = alignof(T);
- };
- template <class T, size_t N>
- struct AlignOf<Aligned<T, N>> {
- static_assert(N % alignof(T) == 0,
- "Custom alignment can't be lower than the type's alignment");
- static constexpr size_t value = N;
- };
- // Does `Ts...` contain `T`?
- template <class T, class... Ts>
- using Contains = phmap::disjunction<std::is_same<T, Ts>...>;
- template <class From, class To>
- using CopyConst =
- typename std::conditional<std::is_const<From>::value, const To, To>::type;
- // Note: We're not qualifying this with phmap:: because it doesn't compile under
- // MSVC.
- template <class T>
- using SliceType = Span<T>;
- // This namespace contains no types. It prevents functions defined in it from
- // being found by ADL.
- namespace adl_barrier {
- template <class Needle, class... Ts>
- constexpr size_t Find(Needle, Needle, Ts...) {
- static_assert(!Contains<Needle, Ts...>(), "Duplicate element type");
- return 0;
- }
- template <class Needle, class T, class... Ts>
- constexpr size_t Find(Needle, T, Ts...) {
- return adl_barrier::Find(Needle(), Ts()...) + 1;
- }
- constexpr bool IsPow2(size_t n) { return !(n & (n - 1)); }
- // Returns `q * m` for the smallest `q` such that `q * m >= n`.
- // Requires: `m` is a power of two. It's enforced by IsLegalElementType below.
- constexpr size_t Align(size_t n, size_t m) { return (n + m - 1) & ~(m - 1); }
- constexpr size_t Min(size_t a, size_t b) { return b < a ? b : a; }
- constexpr size_t Max(size_t a) { return a; }
- template <class... Ts>
- constexpr size_t Max(size_t a, size_t b, Ts... rest) {
- return adl_barrier::Max(b < a ? a : b, rest...);
- }
- } // namespace adl_barrier
- template <bool C>
- using EnableIf = typename std::enable_if<C, int>::type;
- // Can `T` be a template argument of `Layout`?
- // ---------------------------------------------------------------------------
- template <class T>
- using IsLegalElementType = std::integral_constant<
- bool, !std::is_reference<T>::value && !std::is_volatile<T>::value &&
- !std::is_reference<typename Type<T>::type>::value &&
- !std::is_volatile<typename Type<T>::type>::value &&
- adl_barrier::IsPow2(AlignOf<T>::value)>;
- template <class Elements, class SizeSeq, class OffsetSeq>
- class LayoutImpl;
- // ---------------------------------------------------------------------------
- // Public base class of `Layout` and the result type of `Layout::Partial()`.
- //
- // `Elements...` contains all template arguments of `Layout` that created this
- // instance.
- //
- // `SizeSeq...` is `[0, NumSizes)` where `NumSizes` is the number of arguments
- // passed to `Layout::Partial()` or `Layout::Layout()`.
- //
- // `OffsetSeq...` is `[0, NumOffsets)` where `NumOffsets` is
- // `Min(sizeof...(Elements), NumSizes + 1)` (the number of arrays for which we
- // can compute offsets).
- // ---------------------------------------------------------------------------
- template <class... Elements, size_t... SizeSeq, size_t... OffsetSeq>
- class LayoutImpl<std::tuple<Elements...>, phmap::index_sequence<SizeSeq...>,
- phmap::index_sequence<OffsetSeq...>>
- {
- private:
- static_assert(sizeof...(Elements) > 0, "At least one field is required");
- static_assert(phmap::conjunction<IsLegalElementType<Elements>...>::value,
- "Invalid element type (see IsLegalElementType)");
- enum {
- NumTypes = sizeof...(Elements),
- NumSizes = sizeof...(SizeSeq),
- NumOffsets = sizeof...(OffsetSeq),
- };
- // These are guaranteed by `Layout`.
- static_assert(NumOffsets == adl_barrier::Min(NumTypes, NumSizes + 1),
- "Internal error");
- static_assert(NumTypes > 0, "Internal error");
- // Returns the index of `T` in `Elements...`. Results in a compilation error
- // if `Elements...` doesn't contain exactly one instance of `T`.
- template <class T>
- static constexpr size_t ElementIndex() {
- static_assert(Contains<Type<T>, Type<typename Type<Elements>::type>...>(),
- "Type not found");
- return adl_barrier::Find(Type<T>(),
- Type<typename Type<Elements>::type>()...);
- }
- template <size_t N>
- using ElementAlignment =
- AlignOf<typename std::tuple_element<N, std::tuple<Elements...>>::type>;
- public:
- // Element types of all arrays packed in a tuple.
- using ElementTypes = std::tuple<typename Type<Elements>::type...>;
- // Element type of the Nth array.
- template <size_t N>
- using ElementType = typename std::tuple_element<N, ElementTypes>::type;
- constexpr explicit LayoutImpl(IntToSize<SizeSeq>... sizes)
- : size_{sizes...} {}
- // Alignment of the layout, equal to the strictest alignment of all elements.
- // All pointers passed to the methods of layout must be aligned to this value.
- static constexpr size_t Alignment() {
- return adl_barrier::Max(AlignOf<Elements>::value...);
- }
- // Offset in bytes of the Nth array.
- //
- // // int[3], 4 bytes of padding, double[4].
- // Layout<int, double> x(3, 4);
- // assert(x.Offset<0>() == 0); // The ints starts from 0.
- // assert(x.Offset<1>() == 16); // The doubles starts from 16.
- //
- // Requires: `N <= NumSizes && N < sizeof...(Ts)`.
- template <size_t N, EnableIf<N == 0> = 0>
- constexpr size_t Offset() const {
- return 0;
- }
- template <size_t N, EnableIf<N != 0> = 0>
- constexpr size_t Offset() const {
- static_assert(N < NumOffsets, "Index out of bounds");
- return adl_barrier::Align(
- Offset<N - 1>() + SizeOf<ElementType<N - 1>>::value * size_[N - 1],
- ElementAlignment<N>::value);
- }
- // Offset in bytes of the array with the specified element type. There must
- // be exactly one such array and its zero-based index must be at most
- // `NumSizes`.
- //
- // // int[3], 4 bytes of padding, double[4].
- // Layout<int, double> x(3, 4);
- // assert(x.Offset<int>() == 0); // The ints starts from 0.
- // assert(x.Offset<double>() == 16); // The doubles starts from 16.
- template <class T>
- constexpr size_t Offset() const {
- return Offset<ElementIndex<T>()>();
- }
- // Offsets in bytes of all arrays for which the offsets are known.
- constexpr std::array<size_t, NumOffsets> Offsets() const {
- return {{Offset<OffsetSeq>()...}};
- }
- // The number of elements in the Nth array. This is the Nth argument of
- // `Layout::Partial()` or `Layout::Layout()` (zero-based).
- //
- // // int[3], 4 bytes of padding, double[4].
- // Layout<int, double> x(3, 4);
- // assert(x.Size<0>() == 3);
- // assert(x.Size<1>() == 4);
- //
- // Requires: `N < NumSizes`.
- template <size_t N>
- constexpr size_t Size() const {
- static_assert(N < NumSizes, "Index out of bounds");
- return size_[N];
- }
- // The number of elements in the array with the specified element type.
- // There must be exactly one such array and its zero-based index must be
- // at most `NumSizes`.
- //
- // // int[3], 4 bytes of padding, double[4].
- // Layout<int, double> x(3, 4);
- // assert(x.Size<int>() == 3);
- // assert(x.Size<double>() == 4);
- template <class T>
- constexpr size_t Size() const {
- return Size<ElementIndex<T>()>();
- }
- // The number of elements of all arrays for which they are known.
- constexpr std::array<size_t, NumSizes> Sizes() const {
- return {{Size<SizeSeq>()...}};
- }
- // Pointer to the beginning of the Nth array.
- //
- // `Char` must be `[const] [signed|unsigned] char`.
- //
- // // int[3], 4 bytes of padding, double[4].
- // Layout<int, double> x(3, 4);
- // unsigned char* p = new unsigned char[x.AllocSize()];
- // int* ints = x.Pointer<0>(p);
- // double* doubles = x.Pointer<1>(p);
- //
- // Requires: `N <= NumSizes && N < sizeof...(Ts)`.
- // Requires: `p` is aligned to `Alignment()`.
- template <size_t N, class Char>
- CopyConst<Char, ElementType<N>>* Pointer(Char* p) const {
- using C = typename std::remove_const<Char>::type;
- static_assert(
- std::is_same<C, char>() || std::is_same<C, unsigned char>() ||
- std::is_same<C, signed char>(),
- "The argument must be a pointer to [const] [signed|unsigned] char");
- constexpr size_t alignment = Alignment();
- (void)alignment;
- assert(reinterpret_cast<uintptr_t>(p) % alignment == 0);
- return reinterpret_cast<CopyConst<Char, ElementType<N>>*>(p + Offset<N>());
- }
- // Pointer to the beginning of the array with the specified element type.
- // There must be exactly one such array and its zero-based index must be at
- // most `NumSizes`.
- //
- // `Char` must be `[const] [signed|unsigned] char`.
- //
- // // int[3], 4 bytes of padding, double[4].
- // Layout<int, double> x(3, 4);
- // unsigned char* p = new unsigned char[x.AllocSize()];
- // int* ints = x.Pointer<int>(p);
- // double* doubles = x.Pointer<double>(p);
- //
- // Requires: `p` is aligned to `Alignment()`.
- template <class T, class Char>
- CopyConst<Char, T>* Pointer(Char* p) const {
- return Pointer<ElementIndex<T>()>(p);
- }
- // Pointers to all arrays for which pointers are known.
- //
- // `Char` must be `[const] [signed|unsigned] char`.
- //
- // // int[3], 4 bytes of padding, double[4].
- // Layout<int, double> x(3, 4);
- // unsigned char* p = new unsigned char[x.AllocSize()];
- //
- // int* ints;
- // double* doubles;
- // std::tie(ints, doubles) = x.Pointers(p);
- //
- // Requires: `p` is aligned to `Alignment()`.
- //
- // Note: We're not using ElementType alias here because it does not compile
- // under MSVC.
- template <class Char>
- std::tuple<CopyConst<
- Char, typename std::tuple_element<OffsetSeq, ElementTypes>::type>*...>
- Pointers(Char* p) const {
- return std::tuple<CopyConst<Char, ElementType<OffsetSeq>>*...>(
- Pointer<OffsetSeq>(p)...);
- }
- // The Nth array.
- //
- // `Char` must be `[const] [signed|unsigned] char`.
- //
- // // int[3], 4 bytes of padding, double[4].
- // Layout<int, double> x(3, 4);
- // unsigned char* p = new unsigned char[x.AllocSize()];
- // Span<int> ints = x.Slice<0>(p);
- // Span<double> doubles = x.Slice<1>(p);
- //
- // Requires: `N < NumSizes`.
- // Requires: `p` is aligned to `Alignment()`.
- template <size_t N, class Char>
- SliceType<CopyConst<Char, ElementType<N>>> Slice(Char* p) const {
- return SliceType<CopyConst<Char, ElementType<N>>>(Pointer<N>(p), Size<N>());
- }
- // The array with the specified element type. There must be exactly one
- // such array and its zero-based index must be less than `NumSizes`.
- //
- // `Char` must be `[const] [signed|unsigned] char`.
- //
- // // int[3], 4 bytes of padding, double[4].
- // Layout<int, double> x(3, 4);
- // unsigned char* p = new unsigned char[x.AllocSize()];
- // Span<int> ints = x.Slice<int>(p);
- // Span<double> doubles = x.Slice<double>(p);
- //
- // Requires: `p` is aligned to `Alignment()`.
- template <class T, class Char>
- SliceType<CopyConst<Char, T>> Slice(Char* p) const {
- return Slice<ElementIndex<T>()>(p);
- }
- // All arrays with known sizes.
- //
- // `Char` must be `[const] [signed|unsigned] char`.
- //
- // // int[3], 4 bytes of padding, double[4].
- // Layout<int, double> x(3, 4);
- // unsigned char* p = new unsigned char[x.AllocSize()];
- //
- // Span<int> ints;
- // Span<double> doubles;
- // std::tie(ints, doubles) = x.Slices(p);
- //
- // Requires: `p` is aligned to `Alignment()`.
- //
- // Note: We're not using ElementType alias here because it does not compile
- // under MSVC.
- template <class Char>
- std::tuple<SliceType<CopyConst<
- Char, typename std::tuple_element<SizeSeq, ElementTypes>::type>>...>
- Slices(Char* p) const {
- // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63875 (fixed
- // in 6.1).
- (void)p;
- return std::tuple<SliceType<CopyConst<Char, ElementType<SizeSeq>>>...>(
- Slice<SizeSeq>(p)...);
- }
- // The size of the allocation that fits all arrays.
- //
- // // int[3], 4 bytes of padding, double[4].
- // Layout<int, double> x(3, 4);
- // unsigned char* p = new unsigned char[x.AllocSize()]; // 48 bytes
- //
- // Requires: `NumSizes == sizeof...(Ts)`.
- constexpr size_t AllocSize() const {
- static_assert(NumTypes == NumSizes, "You must specify sizes of all fields");
- return Offset<NumTypes - 1>() +
- SizeOf<ElementType<NumTypes - 1>>::value * size_[NumTypes - 1];
- }
- // If built with --config=asan, poisons padding bytes (if any) in the
- // allocation. The pointer must point to a memory block at least
- // `AllocSize()` bytes in length.
- //
- // `Char` must be `[const] [signed|unsigned] char`.
- //
- // Requires: `p` is aligned to `Alignment()`.
- template <class Char, size_t N = NumOffsets - 1, EnableIf<N == 0> = 0>
- void PoisonPadding(const Char* p) const {
- Pointer<0>(p); // verify the requirements on `Char` and `p`
- }
- template <class Char, size_t N = NumOffsets - 1, EnableIf<N != 0> = 0>
- void PoisonPadding(const Char* p) const {
- static_assert(N < NumOffsets, "Index out of bounds");
- (void)p;
- #ifdef ADDRESS_SANITIZER
- PoisonPadding<Char, N - 1>(p);
- // The `if` is an optimization. It doesn't affect the observable behaviour.
- if (ElementAlignment<N - 1>::value % ElementAlignment<N>::value) {
- size_t start =
- Offset<N - 1>() + SizeOf<ElementType<N - 1>>::value * size_[N - 1];
- ASAN_POISON_MEMORY_REGION(p + start, Offset<N>() - start);
- }
- #endif
- }
- private:
- // Arguments of `Layout::Partial()` or `Layout::Layout()`.
- size_t size_[NumSizes > 0 ? NumSizes : 1];
- };
- template <size_t NumSizes, class... Ts>
- using LayoutType = LayoutImpl<
- std::tuple<Ts...>, phmap::make_index_sequence<NumSizes>,
- phmap::make_index_sequence<adl_barrier::Min(sizeof...(Ts), NumSizes + 1)>>;
- } // namespace internal_layout
- // ---------------------------------------------------------------------------
- // Descriptor of arrays of various types and sizes laid out in memory one after
- // another. See the top of the file for documentation.
- //
- // Check out the public API of internal_layout::LayoutImpl above. The type is
- // internal to the library but its methods are public, and they are inherited
- // by `Layout`.
- // ---------------------------------------------------------------------------
- template <class... Ts>
- class Layout : public internal_layout::LayoutType<sizeof...(Ts), Ts...>
- {
- public:
- static_assert(sizeof...(Ts) > 0, "At least one field is required");
- static_assert(
- phmap::conjunction<internal_layout::IsLegalElementType<Ts>...>::value,
- "Invalid element type (see IsLegalElementType)");
- template <size_t NumSizes>
- using PartialType = internal_layout::LayoutType<NumSizes, Ts...>;
- template <class... Sizes>
- static constexpr PartialType<sizeof...(Sizes)> Partial(Sizes&&... sizes) {
- static_assert(sizeof...(Sizes) <= sizeof...(Ts), "");
- return PartialType<sizeof...(Sizes)>(phmap::forward<Sizes>(sizes)...);
- }
- // Creates a layout with the sizes of all arrays specified. If you know
- // only the sizes of the first N arrays (where N can be zero), you can use
- // `Partial()` defined above. The constructor is essentially equivalent to
- // calling `Partial()` and passing in all array sizes; the constructor is
- // provided as a convenient abbreviation.
- //
- // Note: The sizes of the arrays must be specified in number of elements,
- // not in bytes.
- constexpr explicit Layout(internal_layout::TypeToSize<Ts>... sizes)
- : internal_layout::LayoutType<sizeof...(Ts), Ts...>(sizes...) {}
- };
- #ifdef _MSC_VER
- #pragma warning(push)
- // warning warning C4324: structure was padded due to alignment specifier
- #pragma warning(disable : 4324)
- #endif
- // ----------------------------------------------------------------------------
- // Allocates at least n bytes aligned to the specified alignment.
- // Alignment must be a power of 2. It must be positive.
- //
- // Note that many allocators don't honor alignment requirements above certain
- // threshold (usually either alignof(std::max_align_t) or alignof(void*)).
- // Allocate() doesn't apply alignment corrections. If the underlying allocator
- // returns insufficiently alignment pointer, that's what you are going to get.
- // ----------------------------------------------------------------------------
- template <size_t Alignment, class Alloc>
- void* Allocate(Alloc* alloc, size_t n) {
- static_assert(Alignment > 0, "");
- assert(n && "n must be positive");
- struct alignas(Alignment) M {};
- using A = typename phmap::allocator_traits<Alloc>::template rebind_alloc<M>;
- using AT = typename phmap::allocator_traits<Alloc>::template rebind_traits<M>;
- A mem_alloc(*alloc);
- void* p = AT::allocate(mem_alloc, (n + sizeof(M) - 1) / sizeof(M));
- assert(reinterpret_cast<uintptr_t>(p) % Alignment == 0 &&
- "allocator does not respect alignment");
- return p;
- }
- // ----------------------------------------------------------------------------
- // The pointer must have been previously obtained by calling
- // Allocate<Alignment>(alloc, n).
- // ----------------------------------------------------------------------------
- template <size_t Alignment, class Alloc>
- void Deallocate(Alloc* alloc, void* p, size_t n) {
- static_assert(Alignment > 0, "");
- assert(n && "n must be positive");
- struct alignas(Alignment) M {};
- using A = typename phmap::allocator_traits<Alloc>::template rebind_alloc<M>;
- using AT = typename phmap::allocator_traits<Alloc>::template rebind_traits<M>;
- A mem_alloc(*alloc);
- AT::deallocate(mem_alloc, static_cast<M*>(p),
- (n + sizeof(M) - 1) / sizeof(M));
- }
- #ifdef _MSC_VER
- #pragma warning(pop)
- #endif
- // Helper functions for asan and msan.
- // ----------------------------------------------------------------------------
- LL_INLINE void SanitizerPoisonMemoryRegion(const void* m, size_t s) {
- #ifdef ADDRESS_SANITIZER
- ASAN_POISON_MEMORY_REGION(m, s);
- #endif
- #ifdef MEMORY_SANITIZER
- __msan_poison(m, s);
- #endif
- (void)m;
- (void)s;
- }
- LL_INLINE void SanitizerUnpoisonMemoryRegion(const void* m, size_t s) {
- #ifdef ADDRESS_SANITIZER
- ASAN_UNPOISON_MEMORY_REGION(m, s);
- #endif
- #ifdef MEMORY_SANITIZER
- __msan_unpoison(m, s);
- #endif
- (void)m;
- (void)s;
- }
- template <typename T>
- LL_INLINE void SanitizerPoisonObject(const T* object) {
- SanitizerPoisonMemoryRegion(object, sizeof(T));
- }
- template <typename T>
- LL_INLINE void SanitizerUnpoisonObject(const T* object) {
- SanitizerUnpoisonMemoryRegion(object, sizeof(T));
- }
- } // namespace priv
- } // namespace phmap
- // ---------------------------------------------------------------------------
- // thread_annotations.h
- // ---------------------------------------------------------------------------
- #if defined(__clang__)
- #define PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
- #else
- #define PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
- #endif
- #define PHMAP_GUARDED_BY(x) PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
- #define PHMAP_PT_GUARDED_BY(x) PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
- #define PHMAP_ACQUIRED_AFTER(...) \
- PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
- #define PHMAP_ACQUIRED_BEFORE(...) \
- PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
- #define PHMAP_EXCLUSIVE_LOCKS_REQUIRED(...) \
- PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__))
- #define PHMAP_SHARED_LOCKS_REQUIRED(...) \
- PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__))
- #define PHMAP_LOCKS_EXCLUDED(...) \
- PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
- #define PHMAP_LOCK_RETURNED(x) \
- PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
- #define PHMAP_LOCKABLE \
- PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(lockable)
- #define PHMAP_SCOPED_LOCKABLE \
- PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
- #define PHMAP_EXCLUSIVE_LOCK_FUNCTION(...) \
- PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__))
- #define PHMAP_SHARED_LOCK_FUNCTION(...) \
- PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__))
- #define PHMAP_UNLOCK_FUNCTION(...) \
- PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__))
- #define PHMAP_EXCLUSIVE_TRYLOCK_FUNCTION(...) \
- PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__))
- #define PHMAP_SHARED_TRYLOCK_FUNCTION(...) \
- PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__))
- #define PHMAP_ASSERT_EXCLUSIVE_LOCK(...) \
- PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(assert_exclusive_lock(__VA_ARGS__))
- #define PHMAP_ASSERT_SHARED_LOCK(...) \
- PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_lock(__VA_ARGS__))
- #define PHMAP_NO_THREAD_SAFETY_ANALYSIS \
- PHMAP_THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
- //------------------------------------------------------------------------------
- // Tool-Supplied Annotations
- //------------------------------------------------------------------------------
- // TS_UNCHECKED should be placed around lock expressions that are not valid
- // C++ syntax, but which are present for documentation purposes. These
- // annotations will be ignored by the analysis.
- #define PHMAP_TS_UNCHECKED(x) ""
- // TS_FIXME is used to mark lock expressions that are not valid C++ syntax.
- // It is used by automated tools to mark and disable invalid expressions.
- // The annotation should either be fixed, or changed to TS_UNCHECKED.
- #define PHMAP_TS_FIXME(x) ""
- // Like NO_THREAD_SAFETY_ANALYSIS, this turns off checking within the body of
- // a particular function. However, this attribute is used to mark functions
- // that are incorrect and need to be fixed. It is used by automated tools to
- // avoid breaking the build when the analysis is updated.
- // Code owners are expected to eventually fix the routine.
- #define PHMAP_NO_THREAD_SAFETY_ANALYSIS_FIXME PHMAP_NO_THREAD_SAFETY_ANALYSIS
- // Similar to NO_THREAD_SAFETY_ANALYSIS_FIXME, this macro marks a GUARDED_BY
- // annotation that needs to be fixed, because it is producing thread safety
- // warning. It disables the GUARDED_BY.
- #define PHMAP_GUARDED_BY_FIXME(x)
- // Disables warnings for a single read operation. This can be used to avoid
- // warnings when it is known that the read is not actually involved in a race,
- // but the compiler cannot confirm that.
- #define PHMAP_TS_UNCHECKED_READ(x) thread_safety_analysis::ts_unchecked_read(x)
- namespace phmap {
- namespace thread_safety_analysis {
- // Takes a reference to a guarded data member, and returns an unguarded
- // reference.
- template <typename T>
- LL_INLINE const T& ts_unchecked_read(const T& v) PHMAP_NO_THREAD_SAFETY_ANALYSIS {
- return v;
- }
- template <typename T>
- LL_INLINE T& ts_unchecked_read(T& v) PHMAP_NO_THREAD_SAFETY_ANALYSIS {
- return v;
- }
- } // namespace thread_safety_analysis
- namespace priv {
- namespace memory_internal {
- // ----------------------------------------------------------------------------
- // If Pair is a standard-layout type, OffsetOf<Pair>::kFirst and
- // OffsetOf<Pair>::kSecond are equivalent to offsetof(Pair, first) and
- // offsetof(Pair, second) respectively. Otherwise they are -1.
- //
- // The purpose of OffsetOf is to avoid calling offsetof() on non-standard-layout
- // type, which is non-portable.
- // ----------------------------------------------------------------------------
- template <class Pair, class = std::true_type>
- struct OffsetOf {
- static constexpr size_t kFirst = static_cast<size_t>(-1);
- static constexpr size_t kSecond = static_cast<size_t>(-1);
- };
- template <class Pair>
- struct OffsetOf<Pair, typename std::is_standard_layout<Pair>::type>
- {
- static constexpr size_t kFirst = offsetof(Pair, first);
- static constexpr size_t kSecond = offsetof(Pair, second);
- };
- // ----------------------------------------------------------------------------
- template <class K, class V>
- struct IsLayoutCompatible
- {
- private:
- struct Pair {
- K first;
- V second;
- };
- // Is P layout-compatible with Pair?
- template <class P>
- static constexpr bool LayoutCompatible() {
- return std::is_standard_layout<P>() && sizeof(P) == sizeof(Pair) &&
- alignof(P) == alignof(Pair) &&
- memory_internal::OffsetOf<P>::kFirst ==
- memory_internal::OffsetOf<Pair>::kFirst &&
- memory_internal::OffsetOf<P>::kSecond ==
- memory_internal::OffsetOf<Pair>::kSecond;
- }
- public:
- // Whether pair<const K, V> and pair<K, V> are layout-compatible. If they are,
- // then it is safe to store them in a union and read from either.
- static constexpr bool value = std::is_standard_layout<K>() &&
- std::is_standard_layout<Pair>() &&
- memory_internal::OffsetOf<Pair>::kFirst == 0 &&
- LayoutCompatible<std::pair<K, V>>() &&
- LayoutCompatible<std::pair<const K, V>>();
- };
- } // namespace memory_internal
- // ----------------------------------------------------------------------------
- // The internal storage type for key-value containers like flat_hash_map.
- //
- // It is convenient for the value_type of a flat_hash_map<K, V> to be
- // pair<const K, V>; the "const K" prevents accidental modification of the key
- // when dealing with the reference returned from find() and similar methods.
- // However, this creates other problems; we want to be able to emplace(K, V)
- // efficiently with move operations, and similarly be able to move a
- // pair<K, V> in insert().
- //
- // The solution is this union, which aliases the const and non-const versions
- // of the pair. This also allows flat_hash_map<const K, V> to work, even though
- // that has the same efficiency issues with move in emplace() and insert() -
- // but people do it anyway.
- //
- // If kMutableKeys is false, only the value member can be accessed.
- //
- // If kMutableKeys is true, key can be accessed through all slots while value
- // and mutable_value must be accessed only via INITIALIZED slots. Slots are
- // created and destroyed via mutable_value so that the key can be moved later.
- //
- // Accessing one of the union fields while the other is active is safe as
- // long as they are layout-compatible, which is guaranteed by the definition of
- // kMutableKeys. For C++11, the relevant section of the standard is
- // https://timsong-cpp.github.io/cppwp/n3337/class.mem#19 (9.2.19)
- // ----------------------------------------------------------------------------
- template <class K, class V>
- union map_slot_type
- {
- map_slot_type() {}
- ~map_slot_type() = delete;
- map_slot_type(const map_slot_type&) = delete;
- map_slot_type& operator=(const map_slot_type&) = delete;
- using value_type = std::pair<const K, V>;
- using mutable_value_type = std::pair<K, V>;
- value_type value;
- mutable_value_type mutable_value;
- K key;
- };
- // ----------------------------------------------------------------------------
- // ----------------------------------------------------------------------------
- template <class K, class V>
- struct map_slot_policy
- {
- using slot_type = map_slot_type<K, V>;
- using value_type = std::pair<const K, V>;
- using mutable_value_type = std::pair<K, V>;
- private:
- static void emplace(slot_type* slot) {
- // The construction of union doesn't do anything at runtime but it allows us
- // to access its members without violating aliasing rules.
- new (slot) slot_type;
- }
- // If pair<const K, V> and pair<K, V> are layout-compatible, we can accept one
- // or the other via slot_type. We are also free to access the key via
- // slot_type::key in this case.
- using kMutableKeys = memory_internal::IsLayoutCompatible<K, V>;
- public:
- static value_type& element(slot_type* slot) { return slot->value; }
- static const value_type& element(const slot_type* slot) {
- return slot->value;
- }
- static const K& key(const slot_type* slot) {
- return kMutableKeys::value ? slot->key : slot->value.first;
- }
- template <class Allocator, class... Args>
- static void construct(Allocator* alloc, slot_type* slot, Args&&... args) {
- emplace(slot);
- if (kMutableKeys::value) {
- phmap::allocator_traits<Allocator>::construct(*alloc, &slot->mutable_value,
- std::forward<Args>(args)...);
- } else {
- phmap::allocator_traits<Allocator>::construct(*alloc, &slot->value,
- std::forward<Args>(args)...);
- }
- }
- // Construct this slot by moving from another slot.
- template <class Allocator>
- static void construct(Allocator* alloc, slot_type* slot, slot_type* other) {
- emplace(slot);
- if (kMutableKeys::value) {
- phmap::allocator_traits<Allocator>::construct(
- *alloc, &slot->mutable_value, std::move(other->mutable_value));
- } else {
- phmap::allocator_traits<Allocator>::construct(*alloc, &slot->value,
- std::move(other->value));
- }
- }
- template <class Allocator>
- static void destroy(Allocator* alloc, slot_type* slot) {
- if (kMutableKeys::value) {
- phmap::allocator_traits<Allocator>::destroy(*alloc, &slot->mutable_value);
- } else {
- phmap::allocator_traits<Allocator>::destroy(*alloc, &slot->value);
- }
- }
- template <class Allocator>
- static void transfer(Allocator* alloc, slot_type* new_slot,
- slot_type* old_slot) {
- emplace(new_slot);
- if (kMutableKeys::value) {
- phmap::allocator_traits<Allocator>::construct(
- *alloc, &new_slot->mutable_value, std::move(old_slot->mutable_value));
- } else {
- phmap::allocator_traits<Allocator>::construct(*alloc, &new_slot->value,
- std::move(old_slot->value));
- }
- destroy(alloc, old_slot);
- }
- template <class Allocator>
- static void swap(Allocator* alloc, slot_type* a, slot_type* b) {
- if (kMutableKeys::value) {
- using std::swap;
- swap(a->mutable_value, b->mutable_value);
- } else {
- value_type tmp = std::move(a->value);
- phmap::allocator_traits<Allocator>::destroy(*alloc, &a->value);
- phmap::allocator_traits<Allocator>::construct(*alloc, &a->value,
- std::move(b->value));
- phmap::allocator_traits<Allocator>::destroy(*alloc, &b->value);
- phmap::allocator_traits<Allocator>::construct(*alloc, &b->value,
- std::move(tmp));
- }
- }
- template <class Allocator>
- static void move(Allocator* alloc, slot_type* src, slot_type* dest) {
- if (kMutableKeys::value) {
- dest->mutable_value = std::move(src->mutable_value);
- } else {
- phmap::allocator_traits<Allocator>::destroy(*alloc, &dest->value);
- phmap::allocator_traits<Allocator>::construct(*alloc, &dest->value,
- std::move(src->value));
- }
- }
- template <class Allocator>
- static void move(Allocator* alloc, slot_type* first, slot_type* last,
- slot_type* result) {
- for (slot_type *src = first, *dest = result; src != last; ++src, ++dest)
- move(alloc, src, dest);
- }
- };
- } // namespace priv
- } // phmap
- namespace phmap {
- #if PHMAP_USE_BOOST_MUTEX && defined(BOOST_THREAD_LOCK_OPTIONS_HPP)
- using defer_lock_t = boost::defer_lock_t;
- using try_to_lock_t = boost::try_to_lock_t;
- using adopt_lock_t = boost::adopt_lock_t;
- #else
- struct adopt_lock_t { explicit adopt_lock_t() = default; };
- struct defer_lock_t { explicit defer_lock_t() = default; };
- struct try_to_lock_t { explicit try_to_lock_t() = default; };
- #endif
- // -----------------------------------------------------------------------------
- // NullMutex
- // -----------------------------------------------------------------------------
- // A class that implements the Mutex interface, but does nothing. This is to be
- // used as a default template parameters for classes who provide optional
- // internal locking (like phmap::parallel_flat_hash_map).
- // -----------------------------------------------------------------------------
- class NullMutex {
- public:
- LL_INLINE NullMutex() {}
- LL_INLINE ~NullMutex() {}
- LL_INLINE void lock() {}
- LL_INLINE void unlock() {}
- LL_INLINE bool try_lock() { return true; }
- LL_INLINE void lock_shared() {}
- LL_INLINE void unlock_shared() {}
- LL_INLINE bool try_lock_shared() { return true; }
- };
- // ------------------------ lockable object used internally -------------------------
- template <class MutexType>
- class LockableBaseImpl
- {
- public:
- // ----------------------------------------------------
- struct DoNothing
- {
- using mutex_type = MutexType;
- LL_INLINE DoNothing() noexcept {}
- LL_INLINE explicit DoNothing(mutex_type& ) noexcept {}
- LL_INLINE explicit DoNothing(mutex_type& , mutex_type&) noexcept {}
- LL_INLINE DoNothing(mutex_type&, phmap::adopt_lock_t) noexcept {}
- LL_INLINE DoNothing(mutex_type&, phmap::defer_lock_t) noexcept {}
- LL_INLINE DoNothing(mutex_type&, phmap::try_to_lock_t) {}
- template<class T> explicit LL_INLINE DoNothing(T&&) {}
- LL_INLINE DoNothing& operator=(const DoNothing&) { return *this; }
- LL_INLINE DoNothing& operator=(DoNothing&&) noexcept { return *this; }
- LL_INLINE void swap(DoNothing &) noexcept {}
- LL_INLINE bool owns_lock() const noexcept { return true; }
- LL_INLINE void lock() {}
- LL_INLINE void unlock() {}
- LL_INLINE void lock_shared() {}
- LL_INLINE void unlock_shared() {}
- LL_INLINE bool switch_to_unique() { return false; }
- };
- // ----------------------------------------------------
- class WriteLock
- {
- public:
- using mutex_type = MutexType;
- WriteLock() : m_(nullptr), locked_(false) {}
- explicit WriteLock(mutex_type &m) : m_(&m) {
- m_->lock();
- locked_ = true;
- }
- WriteLock(mutex_type& m, adopt_lock_t) noexcept :
- m_(&m), locked_(true)
- {}
- WriteLock(mutex_type& m, defer_lock_t) noexcept :
- m_(&m), locked_(false)
- {}
- WriteLock(mutex_type& m, try_to_lock_t) :
- m_(&m), locked_(false) {
- m_->try_lock();
- }
- WriteLock(WriteLock &&o) noexcept :
- m_(std::move(o.m_)), locked_(std::move(o.locked_)) {
- o.locked_ = false;
- o.m_ = nullptr;
- }
- WriteLock& operator=(WriteLock&& other) noexcept {
- WriteLock temp(std::move(other));
- swap(temp);
- return *this;
- }
- ~WriteLock() {
- if (locked_)
- m_->unlock();
- }
- void lock() {
- if (!locked_) {
- m_->lock();
- locked_ = true;
- }
- }
- void unlock() {
- if (locked_) {
- m_->unlock();
- locked_ = false;
- }
- }
- bool try_lock() {
- if (locked_)
- return true;
- locked_ = m_->try_lock();
- return locked_;
- }
- bool owns_lock() const noexcept { return locked_; }
- void swap(WriteLock &o) noexcept {
- std::swap(m_, o.m_);
- std::swap(locked_, o.locked_);
- }
- mutex_type *mutex() const noexcept { return m_; }
- bool switch_to_unique() { return false; }
- private:
- mutex_type *m_;
- bool locked_;
- };
- // ----------------------------------------------------
- class ReadLock
- {
- public:
- using mutex_type = MutexType;
- ReadLock() : m_(nullptr), locked_(false) {}
- explicit ReadLock(mutex_type &m) : m_(&m) {
- m_->lock_shared();
- locked_ = true;
- }
- ReadLock(mutex_type& m, adopt_lock_t) noexcept :
- m_(&m), locked_(true)
- {}
- ReadLock(mutex_type& m, defer_lock_t) noexcept :
- m_(&m), locked_(false)
- {}
- ReadLock(mutex_type& m, try_to_lock_t) :
- m_(&m), locked_(false) {
- m_->try_lock_shared();
- }
- ReadLock(ReadLock &&o) noexcept :
- m_(std::move(o.m_)), locked_(std::move(o.locked_)) {
- o.locked_ = false;
- o.m_ = nullptr;
- }
- ReadLock& operator=(ReadLock&& other) noexcept {
- ReadLock temp(std::move(other));
- swap(temp);
- return *this;
- }
- ~ReadLock() {
- if (locked_)
- m_->unlock_shared();
- }
- void lock() {
- if (!locked_) {
- m_->lock_shared();
- locked_ = true;
- }
- }
- void unlock() {
- if (locked_) {
- m_->unlock_shared();
- locked_ = false;
- }
- }
- bool try_lock() {
- if (locked_)
- return true;
- locked_ = m_->try_lock_shared();
- return locked_;
- }
- bool owns_lock() const noexcept { return locked_; }
- void swap(ReadLock &o) noexcept {
- std::swap(m_, o.m_);
- std::swap(locked_, o.locked_);
- }
- mutex_type *mutex() const noexcept { return m_; }
- bool switch_to_unique() { return false; }
- private:
- mutex_type *m_;
- bool locked_;
- };
- // ----------------------------------------------------
- class ReadWriteLock
- {
- public:
- using mutex_type = MutexType;
- ReadWriteLock() : m_(nullptr), locked_(false), locked_shared_(false) {}
- explicit ReadWriteLock(mutex_type &m) : m_(&m), locked_(false), locked_shared_(true) {
- m_->lock_shared();
- }
- ReadWriteLock(mutex_type& m, defer_lock_t) noexcept :
- m_(&m), locked_(false), locked_shared_(false)
- {}
- ReadWriteLock(ReadWriteLock &&o) noexcept :
- m_(std::move(o.m_)), locked_(o.locked_), locked_shared_(o.locked_shared_) {
- o.locked_ = false;
- o.locked_shared_ = false;
- o.m_ = nullptr;
- }
- ReadWriteLock& operator=(ReadWriteLock&& other) noexcept {
- ReadWriteLock temp(std::move(other));
- swap(temp);
- return *this;
- }
- ~ReadWriteLock() {
- if (locked_shared_)
- m_->unlock_shared();
- else if (locked_)
- m_->unlock();
- }
- void lock_shared() {
- assert(!locked_);
- if (!locked_shared_) {
- m_->lock_shared();
- locked_shared_ = true;
- }
- }
- void unlock_shared() {
- if (locked_shared_) {
- m_->unlock_shared();
- locked_shared_ = false;
- }
- }
- void lock() {
- assert(!locked_shared_);
- if (!locked_) {
- m_->lock();
- locked_ = true;
- }
- }
- void unlock() {
- if (locked_) {
- m_->unlock();
- locked_ = false;
- }
- }
- bool owns_lock() const noexcept { return locked_; }
- bool owns_shared_lock() const noexcept { return locked_shared_; }
- void swap(ReadWriteLock &o) noexcept {
- std::swap(m_, o.m_);
- std::swap(locked_, o.locked_);
- std::swap(locked_shared_, o.locked_shared_);
- }
- mutex_type *mutex() const noexcept { return m_; }
- bool switch_to_unique() {
- assert(locked_shared_);
- unlock_shared();
- lock();
- return true;
- }
- private:
- mutex_type *m_;
- bool locked_;
- bool locked_shared_;
- };
- // ----------------------------------------------------
- class WriteLocks
- {
- public:
- using mutex_type = MutexType;
- explicit WriteLocks(mutex_type& m1, mutex_type& m2) :
- _m1(m1), _m2(m2)
- {
- std::lock(m1, m2);
- }
- WriteLocks(adopt_lock_t, mutex_type& m1, mutex_type& m2) :
- _m1(m1), _m2(m2)
- { // adopt means we already own the mutexes
- }
- ~WriteLocks()
- {
- _m1.unlock();
- _m2.unlock();
- }
- WriteLocks(WriteLocks const&) = delete;
- WriteLocks& operator=(WriteLocks const&) = delete;
- private:
- mutex_type& _m1;
- mutex_type& _m2;
- };
- // ----------------------------------------------------
- class ReadLocks
- {
- public:
- using mutex_type = MutexType;
- explicit ReadLocks(mutex_type& m1, mutex_type& m2) :
- _m1(m1), _m2(m2)
- {
- _m1.lock_shared();
- _m2.lock_shared();
- }
- ReadLocks(adopt_lock_t, mutex_type& m1, mutex_type& m2) :
- _m1(m1), _m2(m2)
- { // adopt means we already own the mutexes
- }
- ~ReadLocks()
- {
- _m1.unlock_shared();
- _m2.unlock_shared();
- }
- ReadLocks(ReadLocks const&) = delete;
- ReadLocks& operator=(ReadLocks const&) = delete;
- private:
- mutex_type& _m1;
- mutex_type& _m2;
- };
- };
- // ------------------------ holds a mutex ------------------------------------
- // Default implementation for Lockable, should work fine for std::mutex
- // -----------------------------------
- // use as:
- // using Lockable = phmap::LockableImpl<mutex_type>;
- // Lockable m;
- //
- // Lockable::ReadWriteLock read_lock(m); // take a lock (read if supported, otherwise write)
- // ... do something
- //
- // m.switch_to_unique(); // returns true if we had a read lock and switched to write
- // // now locked for write
- //
- // ---------------------------------------------------------------------------
- // Generic mutex support (always write locks)
- // --------------------------------------------------------------------------
- template <class Mtx_>
- class LockableImpl : public Mtx_
- {
- public:
- using mutex_type = Mtx_;
- using Base = LockableBaseImpl<Mtx_>;
- using SharedLock = typename Base::WriteLock;
- using UniqueLock = typename Base::WriteLock;
- using ReadWriteLock = typename Base::WriteLock;
- using SharedLocks = typename Base::WriteLocks;
- using UniqueLocks = typename Base::WriteLocks;
- };
- // ---------------------------------------------------------------------------
- // Null mutex (no-op) - when we don't want internal synchronization
- // ---------------------------------------------------------------------------
- template <>
- class LockableImpl<phmap::NullMutex>: public phmap::NullMutex
- {
- public:
- using mutex_type = phmap::NullMutex;
- using Base = LockableBaseImpl<phmap::NullMutex>;
- using SharedLock = typename Base::DoNothing;
- using ReadWriteLock = typename Base::DoNothing;
- using UniqueLock = typename Base::DoNothing;
- using SharedLocks = typename Base::DoNothing;
- using UniqueLocks = typename Base::DoNothing;
- };
- // --------------------------------------------------------------------------
- // Abseil Mutex support (read and write lock support)
- // use: `phmap::AbslMutex` instead of `std::mutex`
- // --------------------------------------------------------------------------
- #ifdef ABSL_SYNCHRONIZATION_MUTEX_H_
- struct AbslMutex : protected absl::Mutex
- {
- void lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() { this->Lock(); }
- void unlock() ABSL_UNLOCK_FUNCTION() { this->Unlock(); }
- void try_lock() ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true) { this->TryLock(); }
- void lock_shared() ABSL_SHARED_LOCK_FUNCTION() { this->ReaderLock(); }
- void unlock_shared() ABSL_UNLOCK_FUNCTION() { this->ReaderUnlock(); }
- void try_lock_shared() ABSL_SHARED_TRYLOCK_FUNCTION(true) { this->ReaderTryLock(); }
- };
- template <>
- class LockableImpl<absl::Mutex> : public AbslMutex
- {
- public:
- using mutex_type = phmap::AbslMutex;
- using Base = LockableBaseImpl<phmap::AbslMutex>;
- using SharedLock = typename Base::ReadLock;
- using ReadWriteLock = typename Base::ReadWriteLock;
- using UniqueLock = typename Base::WriteLock;
- using SharedLocks = typename Base::ReadLocks;
- using UniqueLocks = typename Base::WriteLocks;
- };
- #endif
- // --------------------------------------------------------------------------
- // Microsoft SRWLOCK support (read and write lock support)
- // use: `phmap::srwlock` instead of `std::mutex`
- // --------------------------------------------------------------------------
- #if defined(_MSC_VER) && defined(SRWLOCK_INIT) && 0 // Disabled (broken). HB
- class srwlock {
- SRWLOCK _lock;
- public:
- srwlock() { InitializeSRWLock(&_lock); }
- void lock() { AcquireSRWLockExclusive(&_lock); }
- void unlock() { ReleaseSRWLockExclusive(&_lock); }
- bool try_lock() { return !!TryAcquireSRWLockExclusive(&_lock); }
- void lock_shared() { AcquireSRWLockShared(&_lock); }
- void unlock_shared() { ReleaseSRWLockShared(&_lock); }
- bool try_lock_shared() { return !!TryAcquireSRWLockShared(&_lock); }
- };
- template<>
- class LockableImpl<srwlock> : public srwlock
- {
- public:
- using mutex_type = srwlock;
- using Base = LockableBaseImpl<srwlock>;
- using SharedLock = typename Base::ReadLock;
- using ReadWriteLock = typename Base::ReadWriteLock;
- using UniqueLock = typename Base::WriteLock;
- using SharedLocks = typename Base::ReadLocks;
- using UniqueLocks = typename Base::WriteLocks;
- };
- #endif
- // --------------------------------------------------------------------------
- // Boost shared_mutex support (read and write lock support)
- // --------------------------------------------------------------------------
- #if PHMAP_USE_BOOST_MUTEX && defined(BOOST_THREAD_SHARED_MUTEX_HPP)
- // ---------------------------------------------------------------------------
- template <>
- class LockableImpl<boost::shared_mutex> : public boost::shared_mutex
- {
- public:
- using mutex_type = boost::shared_mutex;
- using Base = LockableBaseImpl<boost::shared_mutex>;
- using SharedLock = boost::shared_lock<mutex_type>;
- using ReadWriteLock = typename Base::ReadWriteLock;
- using UniqueLock = boost::unique_lock<mutex_type>;
- using SharedLocks = typename Base::ReadLocks;
- using UniqueLocks = typename Base::WriteLocks;
- };
- #endif // PHMAP_USE_BOOST_MUTEX && defined(BOOST_THREAD_SHARED_MUTEX_HPP)
- // --------------------------------------------------------------------------
- // std::shared_mutex support (read and write lock support)
- // --------------------------------------------------------------------------
- #ifdef PHMAP_HAVE_SHARED_MUTEX
- // ---------------------------------------------------------------------------
- template <>
- class LockableImpl<std::shared_mutex> : public std::shared_mutex
- {
- public:
- using mutex_type = std::shared_mutex;
- using Base = LockableBaseImpl<std::shared_mutex>;
- using SharedLock = std::shared_lock<mutex_type>;
- using ReadWriteLock = typename Base::ReadWriteLock;
- using UniqueLock = std::unique_lock<mutex_type>;
- using SharedLocks = typename Base::ReadLocks;
- using UniqueLocks = typename Base::WriteLocks;
- };
- #endif // PHMAP_HAVE_SHARED_MUTEX
- } // phmap
- #ifdef _MSC_VER
- #pragma warning(pop)
- #endif
- #endif // phmap_base_h_guard_
|