123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850 |
- /* Dictionary object implementation using a hash table */
- /* The distribution includes a separate file, Objects/dictnotes.txt,
- describing explorations into dictionary design and optimization.
- It covers typical dictionary use patterns, the parameters for
- tuning dictionaries, and several ideas for possible optimizations.
- */
- /* PyDictKeysObject
- This implements the dictionary's hashtable.
- As of Python 3.6, this is compact and ordered. Basic idea is described here:
- * https://mail.python.org/pipermail/python-dev/2012-December/123028.html
- * https://morepypy.blogspot.com/2015/01/faster-more-memory-efficient-and-more.html
- layout:
- +---------------------+
- | dk_refcnt |
- | dk_log2_size |
- | dk_log2_index_bytes |
- | dk_kind |
- | dk_usable |
- | dk_nentries |
- +---------------------+
- | dk_indices[] |
- | |
- +---------------------+
- | dk_entries[] |
- | |
- +---------------------+
- dk_indices is actual hashtable. It holds index in entries, or DKIX_EMPTY(-1)
- or DKIX_DUMMY(-2).
- Size of indices is dk_size. Type of each index in indices is vary on dk_size:
- * int8 for dk_size <= 128
- * int16 for 256 <= dk_size <= 2**15
- * int32 for 2**16 <= dk_size <= 2**31
- * int64 for 2**32 <= dk_size
- dk_entries is array of PyDictKeyEntry when dk_kind == DICT_KEYS_GENERAL or
- PyDictUnicodeEntry otherwise. Its length is USABLE_FRACTION(dk_size).
- NOTE: Since negative value is used for DKIX_EMPTY and DKIX_DUMMY, type of
- dk_indices entry is signed integer and int16 is used for table which
- dk_size == 256.
- */
- /*
- The DictObject can be in one of two forms.
- Either:
- A combined table:
- ma_values == NULL, dk_refcnt == 1.
- Values are stored in the me_value field of the PyDictKeysObject.
- Or:
- A split table:
- ma_values != NULL, dk_refcnt >= 1
- Values are stored in the ma_values array.
- Only string (unicode) keys are allowed.
- There are four kinds of slots in the table (slot is index, and
- DK_ENTRIES(keys)[index] if index >= 0):
- 1. Unused. index == DKIX_EMPTY
- Does not hold an active (key, value) pair now and never did. Unused can
- transition to Active upon key insertion. This is each slot's initial state.
- 2. Active. index >= 0, me_key != NULL and me_value != NULL
- Holds an active (key, value) pair. Active can transition to Dummy or
- Pending upon key deletion (for combined and split tables respectively).
- This is the only case in which me_value != NULL.
- 3. Dummy. index == DKIX_DUMMY (combined only)
- Previously held an active (key, value) pair, but that was deleted and an
- active pair has not yet overwritten the slot. Dummy can transition to
- Active upon key insertion. Dummy slots cannot be made Unused again
- else the probe sequence in case of collision would have no way to know
- they were once active.
- 4. Pending. index >= 0, key != NULL, and value == NULL (split only)
- Not yet inserted in split-table.
- */
- /*
- Preserving insertion order
- It's simple for combined table. Since dk_entries is mostly append only, we can
- get insertion order by just iterating dk_entries.
- One exception is .popitem(). It removes last item in dk_entries and decrement
- dk_nentries to achieve amortized O(1). Since there are DKIX_DUMMY remains in
- dk_indices, we can't increment dk_usable even though dk_nentries is
- decremented.
- To preserve the order in a split table, a bit vector is used to record the
- insertion order. When a key is inserted the bit vector is shifted up by 4 bits
- and the index of the key is stored in the low 4 bits.
- As a consequence of this, split keys have a maximum size of 16.
- */
- /* PyDict_MINSIZE is the starting size for any new dict.
- * 8 allows dicts with no more than 5 active entries; experiments suggested
- * this suffices for the majority of dicts (consisting mostly of usually-small
- * dicts created to pass keyword arguments).
- * Making this 8, rather than 4 reduces the number of resizes for most
- * dictionaries, without any significant extra memory use.
- */
- #define PyDict_LOG_MINSIZE 3
- #define PyDict_MINSIZE 8
- #include "Python.h"
- #include "pycore_bitutils.h" // _Py_bit_length
- #include "pycore_call.h" // _PyObject_CallNoArgs()
- #include "pycore_code.h" // stats
- #include "pycore_dict.h" // PyDictKeysObject
- #include "pycore_gc.h" // _PyObject_GC_IS_TRACKED()
- #include "pycore_object.h" // _PyObject_GC_TRACK()
- #include "pycore_pyerrors.h" // _PyErr_GetRaisedException()
- #include "pycore_pystate.h" // _PyThreadState_GET()
- #include "stringlib/eq.h" // unicode_eq()
- #include <stdbool.h>
- /*[clinic input]
- class dict "PyDictObject *" "&PyDict_Type"
- [clinic start generated code]*/
- /*[clinic end generated code: output=da39a3ee5e6b4b0d input=f157a5a0ce9589d6]*/
- /*
- To ensure the lookup algorithm terminates, there must be at least one Unused
- slot (NULL key) in the table.
- To avoid slowing down lookups on a near-full table, we resize the table when
- it's USABLE_FRACTION (currently two-thirds) full.
- */
- #define PERTURB_SHIFT 5
- /*
- Major subtleties ahead: Most hash schemes depend on having a "good" hash
- function, in the sense of simulating randomness. Python doesn't: its most
- important hash functions (for ints) are very regular in common
- cases:
- >>>[hash(i) for i in range(4)]
- [0, 1, 2, 3]
- This isn't necessarily bad! To the contrary, in a table of size 2**i, taking
- the low-order i bits as the initial table index is extremely fast, and there
- are no collisions at all for dicts indexed by a contiguous range of ints. So
- this gives better-than-random behavior in common cases, and that's very
- desirable.
- OTOH, when collisions occur, the tendency to fill contiguous slices of the
- hash table makes a good collision resolution strategy crucial. Taking only
- the last i bits of the hash code is also vulnerable: for example, consider
- the list [i << 16 for i in range(20000)] as a set of keys. Since ints are
- their own hash codes, and this fits in a dict of size 2**15, the last 15 bits
- of every hash code are all 0: they *all* map to the same table index.
- But catering to unusual cases should not slow the usual ones, so we just take
- the last i bits anyway. It's up to collision resolution to do the rest. If
- we *usually* find the key we're looking for on the first try (and, it turns
- out, we usually do -- the table load factor is kept under 2/3, so the odds
- are solidly in our favor), then it makes best sense to keep the initial index
- computation dirt cheap.
- The first half of collision resolution is to visit table indices via this
- recurrence:
- j = ((5*j) + 1) mod 2**i
- For any initial j in range(2**i), repeating that 2**i times generates each
- int in range(2**i) exactly once (see any text on random-number generation for
- proof). By itself, this doesn't help much: like linear probing (setting
- j += 1, or j -= 1, on each loop trip), it scans the table entries in a fixed
- order. This would be bad, except that's not the only thing we do, and it's
- actually *good* in the common cases where hash keys are consecutive. In an
- example that's really too small to make this entirely clear, for a table of
- size 2**3 the order of indices is:
- 0 -> 1 -> 6 -> 7 -> 4 -> 5 -> 2 -> 3 -> 0 [and here it's repeating]
- If two things come in at index 5, the first place we look after is index 2,
- not 6, so if another comes in at index 6 the collision at 5 didn't hurt it.
- Linear probing is deadly in this case because there the fixed probe order
- is the *same* as the order consecutive keys are likely to arrive. But it's
- extremely unlikely hash codes will follow a 5*j+1 recurrence by accident,
- and certain that consecutive hash codes do not.
- The other half of the strategy is to get the other bits of the hash code
- into play. This is done by initializing a (unsigned) vrbl "perturb" to the
- full hash code, and changing the recurrence to:
- perturb >>= PERTURB_SHIFT;
- j = (5*j) + 1 + perturb;
- use j % 2**i as the next table index;
- Now the probe sequence depends (eventually) on every bit in the hash code,
- and the pseudo-scrambling property of recurring on 5*j+1 is more valuable,
- because it quickly magnifies small differences in the bits that didn't affect
- the initial index. Note that because perturb is unsigned, if the recurrence
- is executed often enough perturb eventually becomes and remains 0. At that
- point (very rarely reached) the recurrence is on (just) 5*j+1 again, and
- that's certain to find an empty slot eventually (since it generates every int
- in range(2**i), and we make sure there's always at least one empty slot).
- Selecting a good value for PERTURB_SHIFT is a balancing act. You want it
- small so that the high bits of the hash code continue to affect the probe
- sequence across iterations; but you want it large so that in really bad cases
- the high-order hash bits have an effect on early iterations. 5 was "the
- best" in minimizing total collisions across experiments Tim Peters ran (on
- both normal and pathological cases), but 4 and 6 weren't significantly worse.
- Historical: Reimer Behrends contributed the idea of using a polynomial-based
- approach, using repeated multiplication by x in GF(2**n) where an irreducible
- polynomial for each table size was chosen such that x was a primitive root.
- Christian Tismer later extended that to use division by x instead, as an
- efficient way to get the high bits of the hash code into play. This scheme
- also gave excellent collision statistics, but was more expensive: two
- if-tests were required inside the loop; computing "the next" index took about
- the same number of operations but without as much potential parallelism
- (e.g., computing 5*j can go on at the same time as computing 1+perturb in the
- above, and then shifting perturb can be done while the table index is being
- masked); and the PyDictObject struct required a member to hold the table's
- polynomial. In Tim's experiments the current scheme ran faster, produced
- equally good collision statistics, needed less code & used less memory.
- */
- static int dictresize(PyInterpreterState *interp, PyDictObject *mp,
- uint8_t log_newsize, int unicode);
- static PyObject* dict_iter(PyDictObject *dict);
- #include "clinic/dictobject.c.h"
- #if PyDict_MAXFREELIST > 0
- static struct _Py_dict_state *
- get_dict_state(PyInterpreterState *interp)
- {
- return &interp->dict_state;
- }
- #endif
- void
- _PyDict_ClearFreeList(PyInterpreterState *interp)
- {
- #if PyDict_MAXFREELIST > 0
- struct _Py_dict_state *state = &interp->dict_state;
- while (state->numfree) {
- PyDictObject *op = state->free_list[--state->numfree];
- assert(PyDict_CheckExact(op));
- PyObject_GC_Del(op);
- }
- while (state->keys_numfree) {
- PyObject_Free(state->keys_free_list[--state->keys_numfree]);
- }
- #endif
- }
- void
- _PyDict_Fini(PyInterpreterState *interp)
- {
- _PyDict_ClearFreeList(interp);
- #if defined(Py_DEBUG) && PyDict_MAXFREELIST > 0
- struct _Py_dict_state *state = &interp->dict_state;
- state->numfree = -1;
- state->keys_numfree = -1;
- #endif
- }
- static inline Py_hash_t
- unicode_get_hash(PyObject *o)
- {
- assert(PyUnicode_CheckExact(o));
- return _PyASCIIObject_CAST(o)->hash;
- }
- /* Print summary info about the state of the optimized allocator */
- void
- _PyDict_DebugMallocStats(FILE *out)
- {
- #if PyDict_MAXFREELIST > 0
- PyInterpreterState *interp = _PyInterpreterState_GET();
- struct _Py_dict_state *state = get_dict_state(interp);
- _PyDebugAllocatorStats(out, "free PyDictObject",
- state->numfree, sizeof(PyDictObject));
- #endif
- }
- #define DK_MASK(dk) (DK_SIZE(dk)-1)
- static void free_keys_object(PyInterpreterState *interp, PyDictKeysObject *keys);
- /* PyDictKeysObject has refcounts like PyObject does, so we have the
- following two functions to mirror what Py_INCREF() and Py_DECREF() do.
- (Keep in mind that PyDictKeysObject isn't actually a PyObject.)
- Likewise a PyDictKeysObject can be immortal (e.g. Py_EMPTY_KEYS),
- so we apply a naive version of what Py_INCREF() and Py_DECREF() do
- for immortal objects. */
- static inline void
- dictkeys_incref(PyDictKeysObject *dk)
- {
- if (dk->dk_refcnt == _Py_IMMORTAL_REFCNT) {
- return;
- }
- #ifdef Py_REF_DEBUG
- _Py_IncRefTotal(_PyInterpreterState_GET());
- #endif
- dk->dk_refcnt++;
- }
- static inline void
- dictkeys_decref(PyInterpreterState *interp, PyDictKeysObject *dk)
- {
- if (dk->dk_refcnt == _Py_IMMORTAL_REFCNT) {
- return;
- }
- assert(dk->dk_refcnt > 0);
- #ifdef Py_REF_DEBUG
- _Py_DecRefTotal(_PyInterpreterState_GET());
- #endif
- if (--dk->dk_refcnt == 0) {
- free_keys_object(interp, dk);
- }
- }
- /* lookup indices. returns DKIX_EMPTY, DKIX_DUMMY, or ix >=0 */
- static inline Py_ssize_t
- dictkeys_get_index(const PyDictKeysObject *keys, Py_ssize_t i)
- {
- int log2size = DK_LOG_SIZE(keys);
- Py_ssize_t ix;
- if (log2size < 8) {
- const int8_t *indices = (const int8_t*)(keys->dk_indices);
- ix = indices[i];
- }
- else if (log2size < 16) {
- const int16_t *indices = (const int16_t*)(keys->dk_indices);
- ix = indices[i];
- }
- #if SIZEOF_VOID_P > 4
- else if (log2size >= 32) {
- const int64_t *indices = (const int64_t*)(keys->dk_indices);
- ix = indices[i];
- }
- #endif
- else {
- const int32_t *indices = (const int32_t*)(keys->dk_indices);
- ix = indices[i];
- }
- assert(ix >= DKIX_DUMMY);
- return ix;
- }
- /* write to indices. */
- static inline void
- dictkeys_set_index(PyDictKeysObject *keys, Py_ssize_t i, Py_ssize_t ix)
- {
- int log2size = DK_LOG_SIZE(keys);
- assert(ix >= DKIX_DUMMY);
- assert(keys->dk_version == 0);
- if (log2size < 8) {
- int8_t *indices = (int8_t*)(keys->dk_indices);
- assert(ix <= 0x7f);
- indices[i] = (char)ix;
- }
- else if (log2size < 16) {
- int16_t *indices = (int16_t*)(keys->dk_indices);
- assert(ix <= 0x7fff);
- indices[i] = (int16_t)ix;
- }
- #if SIZEOF_VOID_P > 4
- else if (log2size >= 32) {
- int64_t *indices = (int64_t*)(keys->dk_indices);
- indices[i] = ix;
- }
- #endif
- else {
- int32_t *indices = (int32_t*)(keys->dk_indices);
- assert(ix <= 0x7fffffff);
- indices[i] = (int32_t)ix;
- }
- }
- /* USABLE_FRACTION is the maximum dictionary load.
- * Increasing this ratio makes dictionaries more dense resulting in more
- * collisions. Decreasing it improves sparseness at the expense of spreading
- * indices over more cache lines and at the cost of total memory consumed.
- *
- * USABLE_FRACTION must obey the following:
- * (0 < USABLE_FRACTION(n) < n) for all n >= 2
- *
- * USABLE_FRACTION should be quick to calculate.
- * Fractions around 1/2 to 2/3 seem to work well in practice.
- */
- #define USABLE_FRACTION(n) (((n) << 1)/3)
- /* Find the smallest dk_size >= minsize. */
- static inline uint8_t
- calculate_log2_keysize(Py_ssize_t minsize)
- {
- #if SIZEOF_LONG == SIZEOF_SIZE_T
- minsize = (minsize | PyDict_MINSIZE) - 1;
- return _Py_bit_length(minsize | (PyDict_MINSIZE-1));
- #elif defined(_MSC_VER)
- // On 64bit Windows, sizeof(long) == 4.
- minsize = (minsize | PyDict_MINSIZE) - 1;
- unsigned long msb;
- _BitScanReverse64(&msb, (uint64_t)minsize);
- return (uint8_t)(msb + 1);
- #else
- uint8_t log2_size;
- for (log2_size = PyDict_LOG_MINSIZE;
- (((Py_ssize_t)1) << log2_size) < minsize;
- log2_size++)
- ;
- return log2_size;
- #endif
- }
- /* estimate_keysize is reverse function of USABLE_FRACTION.
- *
- * This can be used to reserve enough size to insert n entries without
- * resizing.
- */
- static inline uint8_t
- estimate_log2_keysize(Py_ssize_t n)
- {
- return calculate_log2_keysize((n*3 + 1) / 2);
- }
- /* GROWTH_RATE. Growth rate upon hitting maximum load.
- * Currently set to used*3.
- * This means that dicts double in size when growing without deletions,
- * but have more head room when the number of deletions is on a par with the
- * number of insertions. See also bpo-17563 and bpo-33205.
- *
- * GROWTH_RATE was set to used*4 up to version 3.2.
- * GROWTH_RATE was set to used*2 in version 3.3.0
- * GROWTH_RATE was set to used*2 + capacity/2 in 3.4.0-3.6.0.
- */
- #define GROWTH_RATE(d) ((d)->ma_used*3)
- /* This immutable, empty PyDictKeysObject is used for PyDict_Clear()
- * (which cannot fail and thus can do no allocation).
- */
- static PyDictKeysObject empty_keys_struct = {
- _Py_IMMORTAL_REFCNT, /* dk_refcnt */
- 0, /* dk_log2_size */
- 0, /* dk_log2_index_bytes */
- DICT_KEYS_UNICODE, /* dk_kind */
- 1, /* dk_version */
- 0, /* dk_usable (immutable) */
- 0, /* dk_nentries */
- {DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY,
- DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY, DKIX_EMPTY}, /* dk_indices */
- };
- #define Py_EMPTY_KEYS &empty_keys_struct
- /* Uncomment to check the dict content in _PyDict_CheckConsistency() */
- // #define DEBUG_PYDICT
- #ifdef DEBUG_PYDICT
- # define ASSERT_CONSISTENT(op) assert(_PyDict_CheckConsistency((PyObject *)(op), 1))
- #else
- # define ASSERT_CONSISTENT(op) assert(_PyDict_CheckConsistency((PyObject *)(op), 0))
- #endif
- static inline int
- get_index_from_order(PyDictObject *mp, Py_ssize_t i)
- {
- assert(mp->ma_used <= SHARED_KEYS_MAX_SIZE);
- assert(i < (((char *)mp->ma_values)[-2]));
- return ((char *)mp->ma_values)[-3-i];
- }
- #ifdef DEBUG_PYDICT
- static void
- dump_entries(PyDictKeysObject *dk)
- {
- for (Py_ssize_t i = 0; i < dk->dk_nentries; i++) {
- if (DK_IS_UNICODE(dk)) {
- PyDictUnicodeEntry *ep = &DK_UNICODE_ENTRIES(dk)[i];
- printf("key=%p value=%p\n", ep->me_key, ep->me_value);
- }
- else {
- PyDictKeyEntry *ep = &DK_ENTRIES(dk)[i];
- printf("key=%p hash=%lx value=%p\n", ep->me_key, ep->me_hash, ep->me_value);
- }
- }
- }
- #endif
- int
- _PyDict_CheckConsistency(PyObject *op, int check_content)
- {
- #define CHECK(expr) \
- do { if (!(expr)) { _PyObject_ASSERT_FAILED_MSG(op, Py_STRINGIFY(expr)); } } while (0)
- assert(op != NULL);
- CHECK(PyDict_Check(op));
- PyDictObject *mp = (PyDictObject *)op;
- PyDictKeysObject *keys = mp->ma_keys;
- int splitted = _PyDict_HasSplitTable(mp);
- Py_ssize_t usable = USABLE_FRACTION(DK_SIZE(keys));
- CHECK(0 <= mp->ma_used && mp->ma_used <= usable);
- CHECK(0 <= keys->dk_usable && keys->dk_usable <= usable);
- CHECK(0 <= keys->dk_nentries && keys->dk_nentries <= usable);
- CHECK(keys->dk_usable + keys->dk_nentries <= usable);
- if (!splitted) {
- /* combined table */
- CHECK(keys->dk_kind != DICT_KEYS_SPLIT);
- CHECK(keys->dk_refcnt == 1 || keys == Py_EMPTY_KEYS);
- }
- else {
- CHECK(keys->dk_kind == DICT_KEYS_SPLIT);
- CHECK(mp->ma_used <= SHARED_KEYS_MAX_SIZE);
- }
- if (check_content) {
- for (Py_ssize_t i=0; i < DK_SIZE(keys); i++) {
- Py_ssize_t ix = dictkeys_get_index(keys, i);
- CHECK(DKIX_DUMMY <= ix && ix <= usable);
- }
- if (keys->dk_kind == DICT_KEYS_GENERAL) {
- PyDictKeyEntry *entries = DK_ENTRIES(keys);
- for (Py_ssize_t i=0; i < usable; i++) {
- PyDictKeyEntry *entry = &entries[i];
- PyObject *key = entry->me_key;
- if (key != NULL) {
- /* test_dict fails if PyObject_Hash() is called again */
- CHECK(entry->me_hash != -1);
- CHECK(entry->me_value != NULL);
- if (PyUnicode_CheckExact(key)) {
- Py_hash_t hash = unicode_get_hash(key);
- CHECK(entry->me_hash == hash);
- }
- }
- }
- }
- else {
- PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(keys);
- for (Py_ssize_t i=0; i < usable; i++) {
- PyDictUnicodeEntry *entry = &entries[i];
- PyObject *key = entry->me_key;
- if (key != NULL) {
- CHECK(PyUnicode_CheckExact(key));
- Py_hash_t hash = unicode_get_hash(key);
- CHECK(hash != -1);
- if (!splitted) {
- CHECK(entry->me_value != NULL);
- }
- }
- if (splitted) {
- CHECK(entry->me_value == NULL);
- }
- }
- }
- if (splitted) {
- CHECK(mp->ma_used <= SHARED_KEYS_MAX_SIZE);
- /* splitted table */
- int duplicate_check = 0;
- for (Py_ssize_t i=0; i < mp->ma_used; i++) {
- int index = get_index_from_order(mp, i);
- CHECK((duplicate_check & (1<<index)) == 0);
- duplicate_check |= (1<<index);
- CHECK(mp->ma_values->values[index] != NULL);
- }
- }
- }
- return 1;
- #undef CHECK
- }
- static PyDictKeysObject*
- new_keys_object(PyInterpreterState *interp, uint8_t log2_size, bool unicode)
- {
- PyDictKeysObject *dk;
- Py_ssize_t usable;
- int log2_bytes;
- size_t entry_size = unicode ? sizeof(PyDictUnicodeEntry) : sizeof(PyDictKeyEntry);
- assert(log2_size >= PyDict_LOG_MINSIZE);
- usable = USABLE_FRACTION((size_t)1<<log2_size);
- if (log2_size < 8) {
- log2_bytes = log2_size;
- }
- else if (log2_size < 16) {
- log2_bytes = log2_size + 1;
- }
- #if SIZEOF_VOID_P > 4
- else if (log2_size >= 32) {
- log2_bytes = log2_size + 3;
- }
- #endif
- else {
- log2_bytes = log2_size + 2;
- }
- #if PyDict_MAXFREELIST > 0
- struct _Py_dict_state *state = get_dict_state(interp);
- #ifdef Py_DEBUG
- // new_keys_object() must not be called after _PyDict_Fini()
- assert(state->keys_numfree != -1);
- #endif
- if (log2_size == PyDict_LOG_MINSIZE && unicode && state->keys_numfree > 0) {
- dk = state->keys_free_list[--state->keys_numfree];
- OBJECT_STAT_INC(from_freelist);
- }
- else
- #endif
- {
- dk = PyObject_Malloc(sizeof(PyDictKeysObject)
- + ((size_t)1 << log2_bytes)
- + entry_size * usable);
- if (dk == NULL) {
- PyErr_NoMemory();
- return NULL;
- }
- }
- #ifdef Py_REF_DEBUG
- _Py_IncRefTotal(_PyInterpreterState_GET());
- #endif
- dk->dk_refcnt = 1;
- dk->dk_log2_size = log2_size;
- dk->dk_log2_index_bytes = log2_bytes;
- dk->dk_kind = unicode ? DICT_KEYS_UNICODE : DICT_KEYS_GENERAL;
- dk->dk_nentries = 0;
- dk->dk_usable = usable;
- dk->dk_version = 0;
- memset(&dk->dk_indices[0], 0xff, ((size_t)1 << log2_bytes));
- memset(&dk->dk_indices[(size_t)1 << log2_bytes], 0, entry_size * usable);
- return dk;
- }
- static void
- free_keys_object(PyInterpreterState *interp, PyDictKeysObject *keys)
- {
- assert(keys != Py_EMPTY_KEYS);
- if (DK_IS_UNICODE(keys)) {
- PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(keys);
- Py_ssize_t i, n;
- for (i = 0, n = keys->dk_nentries; i < n; i++) {
- Py_XDECREF(entries[i].me_key);
- Py_XDECREF(entries[i].me_value);
- }
- }
- else {
- PyDictKeyEntry *entries = DK_ENTRIES(keys);
- Py_ssize_t i, n;
- for (i = 0, n = keys->dk_nentries; i < n; i++) {
- Py_XDECREF(entries[i].me_key);
- Py_XDECREF(entries[i].me_value);
- }
- }
- #if PyDict_MAXFREELIST > 0
- struct _Py_dict_state *state = get_dict_state(interp);
- #ifdef Py_DEBUG
- // free_keys_object() must not be called after _PyDict_Fini()
- assert(state->keys_numfree != -1);
- #endif
- if (DK_LOG_SIZE(keys) == PyDict_LOG_MINSIZE
- && state->keys_numfree < PyDict_MAXFREELIST
- && DK_IS_UNICODE(keys)) {
- state->keys_free_list[state->keys_numfree++] = keys;
- OBJECT_STAT_INC(to_freelist);
- return;
- }
- #endif
- PyObject_Free(keys);
- }
- static inline PyDictValues*
- new_values(size_t size)
- {
- assert(size >= 1);
- size_t prefix_size = _Py_SIZE_ROUND_UP(size+2, sizeof(PyObject *));
- assert(prefix_size < 256);
- size_t n = prefix_size + size * sizeof(PyObject *);
- uint8_t *mem = PyMem_Malloc(n);
- if (mem == NULL) {
- return NULL;
- }
- assert(prefix_size % sizeof(PyObject *) == 0);
- mem[prefix_size-1] = (uint8_t)prefix_size;
- return (PyDictValues*)(mem + prefix_size);
- }
- static inline void
- free_values(PyDictValues *values)
- {
- int prefix_size = ((uint8_t *)values)[-1];
- PyMem_Free(((char *)values)-prefix_size);
- }
- /* Consumes a reference to the keys object */
- static PyObject *
- new_dict(PyInterpreterState *interp,
- PyDictKeysObject *keys, PyDictValues *values,
- Py_ssize_t used, int free_values_on_failure)
- {
- PyDictObject *mp;
- assert(keys != NULL);
- #if PyDict_MAXFREELIST > 0
- struct _Py_dict_state *state = get_dict_state(interp);
- #ifdef Py_DEBUG
- // new_dict() must not be called after _PyDict_Fini()
- assert(state->numfree != -1);
- #endif
- if (state->numfree) {
- mp = state->free_list[--state->numfree];
- assert (mp != NULL);
- assert (Py_IS_TYPE(mp, &PyDict_Type));
- OBJECT_STAT_INC(from_freelist);
- _Py_NewReference((PyObject *)mp);
- }
- else
- #endif
- {
- mp = PyObject_GC_New(PyDictObject, &PyDict_Type);
- if (mp == NULL) {
- dictkeys_decref(interp, keys);
- if (free_values_on_failure) {
- free_values(values);
- }
- return NULL;
- }
- }
- mp->ma_keys = keys;
- mp->ma_values = values;
- mp->ma_used = used;
- mp->ma_version_tag = DICT_NEXT_VERSION(interp);
- ASSERT_CONSISTENT(mp);
- return (PyObject *)mp;
- }
- static inline size_t
- shared_keys_usable_size(PyDictKeysObject *keys)
- {
- return (size_t)keys->dk_nentries + (size_t)keys->dk_usable;
- }
- /* Consumes a reference to the keys object */
- static PyObject *
- new_dict_with_shared_keys(PyInterpreterState *interp, PyDictKeysObject *keys)
- {
- size_t size = shared_keys_usable_size(keys);
- PyDictValues *values = new_values(size);
- if (values == NULL) {
- dictkeys_decref(interp, keys);
- return PyErr_NoMemory();
- }
- ((char *)values)[-2] = 0;
- for (size_t i = 0; i < size; i++) {
- values->values[i] = NULL;
- }
- return new_dict(interp, keys, values, 0, 1);
- }
- static PyDictKeysObject *
- clone_combined_dict_keys(PyDictObject *orig)
- {
- assert(PyDict_Check(orig));
- assert(Py_TYPE(orig)->tp_iter == (getiterfunc)dict_iter);
- assert(orig->ma_values == NULL);
- assert(orig->ma_keys != Py_EMPTY_KEYS);
- assert(orig->ma_keys->dk_refcnt == 1);
- size_t keys_size = _PyDict_KeysSize(orig->ma_keys);
- PyDictKeysObject *keys = PyObject_Malloc(keys_size);
- if (keys == NULL) {
- PyErr_NoMemory();
- return NULL;
- }
- memcpy(keys, orig->ma_keys, keys_size);
- /* After copying key/value pairs, we need to incref all
- keys and values and they are about to be co-owned by a
- new dict object. */
- PyObject **pkey, **pvalue;
- size_t offs;
- if (DK_IS_UNICODE(orig->ma_keys)) {
- PyDictUnicodeEntry *ep0 = DK_UNICODE_ENTRIES(keys);
- pkey = &ep0->me_key;
- pvalue = &ep0->me_value;
- offs = sizeof(PyDictUnicodeEntry) / sizeof(PyObject*);
- }
- else {
- PyDictKeyEntry *ep0 = DK_ENTRIES(keys);
- pkey = &ep0->me_key;
- pvalue = &ep0->me_value;
- offs = sizeof(PyDictKeyEntry) / sizeof(PyObject*);
- }
- Py_ssize_t n = keys->dk_nentries;
- for (Py_ssize_t i = 0; i < n; i++) {
- PyObject *value = *pvalue;
- if (value != NULL) {
- Py_INCREF(value);
- Py_INCREF(*pkey);
- }
- pvalue += offs;
- pkey += offs;
- }
- /* Since we copied the keys table we now have an extra reference
- in the system. Manually call increment _Py_RefTotal to signal that
- we have it now; calling dictkeys_incref would be an error as
- keys->dk_refcnt is already set to 1 (after memcpy). */
- #ifdef Py_REF_DEBUG
- _Py_IncRefTotal(_PyInterpreterState_GET());
- #endif
- return keys;
- }
- PyObject *
- PyDict_New(void)
- {
- PyInterpreterState *interp = _PyInterpreterState_GET();
- /* We don't incref Py_EMPTY_KEYS here because it is immortal. */
- return new_dict(interp, Py_EMPTY_KEYS, NULL, 0, 0);
- }
- /* Search index of hash table from offset of entry table */
- static Py_ssize_t
- lookdict_index(PyDictKeysObject *k, Py_hash_t hash, Py_ssize_t index)
- {
- size_t mask = DK_MASK(k);
- size_t perturb = (size_t)hash;
- size_t i = (size_t)hash & mask;
- for (;;) {
- Py_ssize_t ix = dictkeys_get_index(k, i);
- if (ix == index) {
- return i;
- }
- if (ix == DKIX_EMPTY) {
- return DKIX_EMPTY;
- }
- perturb >>= PERTURB_SHIFT;
- i = mask & (i*5 + perturb + 1);
- }
- Py_UNREACHABLE();
- }
- // Search non-Unicode key from Unicode table
- static Py_ssize_t
- unicodekeys_lookup_generic(PyDictObject *mp, PyDictKeysObject* dk, PyObject *key, Py_hash_t hash)
- {
- PyDictUnicodeEntry *ep0 = DK_UNICODE_ENTRIES(dk);
- size_t mask = DK_MASK(dk);
- size_t perturb = hash;
- size_t i = (size_t)hash & mask;
- Py_ssize_t ix;
- for (;;) {
- ix = dictkeys_get_index(dk, i);
- if (ix >= 0) {
- PyDictUnicodeEntry *ep = &ep0[ix];
- assert(ep->me_key != NULL);
- assert(PyUnicode_CheckExact(ep->me_key));
- if (ep->me_key == key) {
- return ix;
- }
- if (unicode_get_hash(ep->me_key) == hash) {
- PyObject *startkey = ep->me_key;
- Py_INCREF(startkey);
- int cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
- Py_DECREF(startkey);
- if (cmp < 0) {
- return DKIX_ERROR;
- }
- if (dk == mp->ma_keys && ep->me_key == startkey) {
- if (cmp > 0) {
- return ix;
- }
- }
- else {
- /* The dict was mutated, restart */
- return DKIX_KEY_CHANGED;
- }
- }
- }
- else if (ix == DKIX_EMPTY) {
- return DKIX_EMPTY;
- }
- perturb >>= PERTURB_SHIFT;
- i = mask & (i*5 + perturb + 1);
- }
- Py_UNREACHABLE();
- }
- // Search Unicode key from Unicode table.
- static Py_ssize_t _Py_HOT_FUNCTION
- unicodekeys_lookup_unicode(PyDictKeysObject* dk, PyObject *key, Py_hash_t hash)
- {
- PyDictUnicodeEntry *ep0 = DK_UNICODE_ENTRIES(dk);
- size_t mask = DK_MASK(dk);
- size_t perturb = hash;
- size_t i = (size_t)hash & mask;
- Py_ssize_t ix;
- for (;;) {
- ix = dictkeys_get_index(dk, i);
- if (ix >= 0) {
- PyDictUnicodeEntry *ep = &ep0[ix];
- assert(ep->me_key != NULL);
- assert(PyUnicode_CheckExact(ep->me_key));
- if (ep->me_key == key ||
- (unicode_get_hash(ep->me_key) == hash && unicode_eq(ep->me_key, key))) {
- return ix;
- }
- }
- else if (ix == DKIX_EMPTY) {
- return DKIX_EMPTY;
- }
- perturb >>= PERTURB_SHIFT;
- i = mask & (i*5 + perturb + 1);
- // Manual loop unrolling
- ix = dictkeys_get_index(dk, i);
- if (ix >= 0) {
- PyDictUnicodeEntry *ep = &ep0[ix];
- assert(ep->me_key != NULL);
- assert(PyUnicode_CheckExact(ep->me_key));
- if (ep->me_key == key ||
- (unicode_get_hash(ep->me_key) == hash && unicode_eq(ep->me_key, key))) {
- return ix;
- }
- }
- else if (ix == DKIX_EMPTY) {
- return DKIX_EMPTY;
- }
- perturb >>= PERTURB_SHIFT;
- i = mask & (i*5 + perturb + 1);
- }
- Py_UNREACHABLE();
- }
- // Search key from Generic table.
- static Py_ssize_t
- dictkeys_generic_lookup(PyDictObject *mp, PyDictKeysObject* dk, PyObject *key, Py_hash_t hash)
- {
- PyDictKeyEntry *ep0 = DK_ENTRIES(dk);
- size_t mask = DK_MASK(dk);
- size_t perturb = hash;
- size_t i = (size_t)hash & mask;
- Py_ssize_t ix;
- for (;;) {
- ix = dictkeys_get_index(dk, i);
- if (ix >= 0) {
- PyDictKeyEntry *ep = &ep0[ix];
- assert(ep->me_key != NULL);
- if (ep->me_key == key) {
- return ix;
- }
- if (ep->me_hash == hash) {
- PyObject *startkey = ep->me_key;
- Py_INCREF(startkey);
- int cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
- Py_DECREF(startkey);
- if (cmp < 0) {
- return DKIX_ERROR;
- }
- if (dk == mp->ma_keys && ep->me_key == startkey) {
- if (cmp > 0) {
- return ix;
- }
- }
- else {
- /* The dict was mutated, restart */
- return DKIX_KEY_CHANGED;
- }
- }
- }
- else if (ix == DKIX_EMPTY) {
- return DKIX_EMPTY;
- }
- perturb >>= PERTURB_SHIFT;
- i = mask & (i*5 + perturb + 1);
- }
- Py_UNREACHABLE();
- }
- /* Lookup a string in a (all unicode) dict keys.
- * Returns DKIX_ERROR if key is not a string,
- * or if the dict keys is not all strings.
- * If the keys is present then return the index of key.
- * If the key is not present then return DKIX_EMPTY.
- */
- Py_ssize_t
- _PyDictKeys_StringLookup(PyDictKeysObject* dk, PyObject *key)
- {
- DictKeysKind kind = dk->dk_kind;
- if (!PyUnicode_CheckExact(key) || kind == DICT_KEYS_GENERAL) {
- return DKIX_ERROR;
- }
- Py_hash_t hash = unicode_get_hash(key);
- if (hash == -1) {
- hash = PyUnicode_Type.tp_hash(key);
- if (hash == -1) {
- PyErr_Clear();
- return DKIX_ERROR;
- }
- }
- return unicodekeys_lookup_unicode(dk, key, hash);
- }
- /*
- The basic lookup function used by all operations.
- This is based on Algorithm D from Knuth Vol. 3, Sec. 6.4.
- Open addressing is preferred over chaining since the link overhead for
- chaining would be substantial (100% with typical malloc overhead).
- The initial probe index is computed as hash mod the table size. Subsequent
- probe indices are computed as explained earlier.
- All arithmetic on hash should ignore overflow.
- _Py_dict_lookup() is general-purpose, and may return DKIX_ERROR if (and only if) a
- comparison raises an exception.
- When the key isn't found a DKIX_EMPTY is returned.
- */
- Py_ssize_t
- _Py_dict_lookup(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject **value_addr)
- {
- PyDictKeysObject *dk;
- DictKeysKind kind;
- Py_ssize_t ix;
- start:
- dk = mp->ma_keys;
- kind = dk->dk_kind;
- if (kind != DICT_KEYS_GENERAL) {
- if (PyUnicode_CheckExact(key)) {
- ix = unicodekeys_lookup_unicode(dk, key, hash);
- }
- else {
- ix = unicodekeys_lookup_generic(mp, dk, key, hash);
- if (ix == DKIX_KEY_CHANGED) {
- goto start;
- }
- }
- if (ix >= 0) {
- if (kind == DICT_KEYS_SPLIT) {
- *value_addr = mp->ma_values->values[ix];
- }
- else {
- *value_addr = DK_UNICODE_ENTRIES(dk)[ix].me_value;
- }
- }
- else {
- *value_addr = NULL;
- }
- }
- else {
- ix = dictkeys_generic_lookup(mp, dk, key, hash);
- if (ix == DKIX_KEY_CHANGED) {
- goto start;
- }
- if (ix >= 0) {
- *value_addr = DK_ENTRIES(dk)[ix].me_value;
- }
- else {
- *value_addr = NULL;
- }
- }
- return ix;
- }
- int
- _PyDict_HasOnlyStringKeys(PyObject *dict)
- {
- Py_ssize_t pos = 0;
- PyObject *key, *value;
- assert(PyDict_Check(dict));
- /* Shortcut */
- if (((PyDictObject *)dict)->ma_keys->dk_kind != DICT_KEYS_GENERAL)
- return 1;
- while (PyDict_Next(dict, &pos, &key, &value))
- if (!PyUnicode_Check(key))
- return 0;
- return 1;
- }
- #define MAINTAIN_TRACKING(mp, key, value) \
- do { \
- if (!_PyObject_GC_IS_TRACKED(mp)) { \
- if (_PyObject_GC_MAY_BE_TRACKED(key) || \
- _PyObject_GC_MAY_BE_TRACKED(value)) { \
- _PyObject_GC_TRACK(mp); \
- } \
- } \
- } while(0)
- void
- _PyDict_MaybeUntrack(PyObject *op)
- {
- PyDictObject *mp;
- PyObject *value;
- Py_ssize_t i, numentries;
- if (!PyDict_CheckExact(op) || !_PyObject_GC_IS_TRACKED(op))
- return;
- mp = (PyDictObject *) op;
- numentries = mp->ma_keys->dk_nentries;
- if (_PyDict_HasSplitTable(mp)) {
- for (i = 0; i < numentries; i++) {
- if ((value = mp->ma_values->values[i]) == NULL)
- continue;
- if (_PyObject_GC_MAY_BE_TRACKED(value)) {
- return;
- }
- }
- }
- else {
- if (DK_IS_UNICODE(mp->ma_keys)) {
- PyDictUnicodeEntry *ep0 = DK_UNICODE_ENTRIES(mp->ma_keys);
- for (i = 0; i < numentries; i++) {
- if ((value = ep0[i].me_value) == NULL)
- continue;
- if (_PyObject_GC_MAY_BE_TRACKED(value))
- return;
- }
- }
- else {
- PyDictKeyEntry *ep0 = DK_ENTRIES(mp->ma_keys);
- for (i = 0; i < numentries; i++) {
- if ((value = ep0[i].me_value) == NULL)
- continue;
- if (_PyObject_GC_MAY_BE_TRACKED(value) ||
- _PyObject_GC_MAY_BE_TRACKED(ep0[i].me_key))
- return;
- }
- }
- }
- _PyObject_GC_UNTRACK(op);
- }
- /* Internal function to find slot for an item from its hash
- when it is known that the key is not present in the dict.
- The dict must be combined. */
- static Py_ssize_t
- find_empty_slot(PyDictKeysObject *keys, Py_hash_t hash)
- {
- assert(keys != NULL);
- const size_t mask = DK_MASK(keys);
- size_t i = hash & mask;
- Py_ssize_t ix = dictkeys_get_index(keys, i);
- for (size_t perturb = hash; ix >= 0;) {
- perturb >>= PERTURB_SHIFT;
- i = (i*5 + perturb + 1) & mask;
- ix = dictkeys_get_index(keys, i);
- }
- return i;
- }
- static int
- insertion_resize(PyInterpreterState *interp, PyDictObject *mp, int unicode)
- {
- return dictresize(interp, mp, calculate_log2_keysize(GROWTH_RATE(mp)), unicode);
- }
- static Py_ssize_t
- insert_into_dictkeys(PyDictKeysObject *keys, PyObject *name)
- {
- assert(PyUnicode_CheckExact(name));
- Py_hash_t hash = unicode_get_hash(name);
- if (hash == -1) {
- hash = PyUnicode_Type.tp_hash(name);
- if (hash == -1) {
- PyErr_Clear();
- return DKIX_EMPTY;
- }
- }
- Py_ssize_t ix = unicodekeys_lookup_unicode(keys, name, hash);
- if (ix == DKIX_EMPTY) {
- if (keys->dk_usable <= 0) {
- return DKIX_EMPTY;
- }
- /* Insert into new slot. */
- keys->dk_version = 0;
- Py_ssize_t hashpos = find_empty_slot(keys, hash);
- ix = keys->dk_nentries;
- PyDictUnicodeEntry *ep = &DK_UNICODE_ENTRIES(keys)[ix];
- dictkeys_set_index(keys, hashpos, ix);
- assert(ep->me_key == NULL);
- ep->me_key = Py_NewRef(name);
- keys->dk_usable--;
- keys->dk_nentries++;
- }
- assert (ix < SHARED_KEYS_MAX_SIZE);
- return ix;
- }
- /*
- Internal routine to insert a new item into the table.
- Used both by the internal resize routine and by the public insert routine.
- Returns -1 if an error occurred, or 0 on success.
- Consumes key and value references.
- */
- static int
- insertdict(PyInterpreterState *interp, PyDictObject *mp,
- PyObject *key, Py_hash_t hash, PyObject *value)
- {
- PyObject *old_value;
- if (DK_IS_UNICODE(mp->ma_keys) && !PyUnicode_CheckExact(key)) {
- if (insertion_resize(interp, mp, 0) < 0)
- goto Fail;
- assert(mp->ma_keys->dk_kind == DICT_KEYS_GENERAL);
- }
- Py_ssize_t ix = _Py_dict_lookup(mp, key, hash, &old_value);
- if (ix == DKIX_ERROR)
- goto Fail;
- MAINTAIN_TRACKING(mp, key, value);
- if (ix == DKIX_EMPTY) {
- uint64_t new_version = _PyDict_NotifyEvent(
- interp, PyDict_EVENT_ADDED, mp, key, value);
- /* Insert into new slot. */
- mp->ma_keys->dk_version = 0;
- assert(old_value == NULL);
- if (mp->ma_keys->dk_usable <= 0) {
- /* Need to resize. */
- if (insertion_resize(interp, mp, 1) < 0)
- goto Fail;
- }
- Py_ssize_t hashpos = find_empty_slot(mp->ma_keys, hash);
- dictkeys_set_index(mp->ma_keys, hashpos, mp->ma_keys->dk_nentries);
- if (DK_IS_UNICODE(mp->ma_keys)) {
- PyDictUnicodeEntry *ep;
- ep = &DK_UNICODE_ENTRIES(mp->ma_keys)[mp->ma_keys->dk_nentries];
- ep->me_key = key;
- if (mp->ma_values) {
- Py_ssize_t index = mp->ma_keys->dk_nentries;
- _PyDictValues_AddToInsertionOrder(mp->ma_values, index);
- assert (mp->ma_values->values[index] == NULL);
- mp->ma_values->values[index] = value;
- }
- else {
- ep->me_value = value;
- }
- }
- else {
- PyDictKeyEntry *ep;
- ep = &DK_ENTRIES(mp->ma_keys)[mp->ma_keys->dk_nentries];
- ep->me_key = key;
- ep->me_hash = hash;
- ep->me_value = value;
- }
- mp->ma_used++;
- mp->ma_version_tag = new_version;
- mp->ma_keys->dk_usable--;
- mp->ma_keys->dk_nentries++;
- assert(mp->ma_keys->dk_usable >= 0);
- ASSERT_CONSISTENT(mp);
- return 0;
- }
- if (old_value != value) {
- uint64_t new_version = _PyDict_NotifyEvent(
- interp, PyDict_EVENT_MODIFIED, mp, key, value);
- if (_PyDict_HasSplitTable(mp)) {
- mp->ma_values->values[ix] = value;
- if (old_value == NULL) {
- _PyDictValues_AddToInsertionOrder(mp->ma_values, ix);
- mp->ma_used++;
- }
- }
- else {
- assert(old_value != NULL);
- if (DK_IS_UNICODE(mp->ma_keys)) {
- DK_UNICODE_ENTRIES(mp->ma_keys)[ix].me_value = value;
- }
- else {
- DK_ENTRIES(mp->ma_keys)[ix].me_value = value;
- }
- }
- mp->ma_version_tag = new_version;
- }
- Py_XDECREF(old_value); /* which **CAN** re-enter (see issue #22653) */
- ASSERT_CONSISTENT(mp);
- Py_DECREF(key);
- return 0;
- Fail:
- Py_DECREF(value);
- Py_DECREF(key);
- return -1;
- }
- // Same to insertdict but specialized for ma_keys = Py_EMPTY_KEYS.
- // Consumes key and value references.
- static int
- insert_to_emptydict(PyInterpreterState *interp, PyDictObject *mp,
- PyObject *key, Py_hash_t hash, PyObject *value)
- {
- assert(mp->ma_keys == Py_EMPTY_KEYS);
- uint64_t new_version = _PyDict_NotifyEvent(
- interp, PyDict_EVENT_ADDED, mp, key, value);
- int unicode = PyUnicode_CheckExact(key);
- PyDictKeysObject *newkeys = new_keys_object(
- interp, PyDict_LOG_MINSIZE, unicode);
- if (newkeys == NULL) {
- Py_DECREF(key);
- Py_DECREF(value);
- return -1;
- }
- /* We don't decref Py_EMPTY_KEYS here because it is immortal. */
- mp->ma_keys = newkeys;
- mp->ma_values = NULL;
- MAINTAIN_TRACKING(mp, key, value);
- size_t hashpos = (size_t)hash & (PyDict_MINSIZE-1);
- dictkeys_set_index(mp->ma_keys, hashpos, 0);
- if (unicode) {
- PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(mp->ma_keys);
- ep->me_key = key;
- ep->me_value = value;
- }
- else {
- PyDictKeyEntry *ep = DK_ENTRIES(mp->ma_keys);
- ep->me_key = key;
- ep->me_hash = hash;
- ep->me_value = value;
- }
- mp->ma_used++;
- mp->ma_version_tag = new_version;
- mp->ma_keys->dk_usable--;
- mp->ma_keys->dk_nentries++;
- return 0;
- }
- /*
- Internal routine used by dictresize() to build a hashtable of entries.
- */
- static void
- build_indices_generic(PyDictKeysObject *keys, PyDictKeyEntry *ep, Py_ssize_t n)
- {
- size_t mask = DK_MASK(keys);
- for (Py_ssize_t ix = 0; ix != n; ix++, ep++) {
- Py_hash_t hash = ep->me_hash;
- size_t i = hash & mask;
- for (size_t perturb = hash; dictkeys_get_index(keys, i) != DKIX_EMPTY;) {
- perturb >>= PERTURB_SHIFT;
- i = mask & (i*5 + perturb + 1);
- }
- dictkeys_set_index(keys, i, ix);
- }
- }
- static void
- build_indices_unicode(PyDictKeysObject *keys, PyDictUnicodeEntry *ep, Py_ssize_t n)
- {
- size_t mask = DK_MASK(keys);
- for (Py_ssize_t ix = 0; ix != n; ix++, ep++) {
- Py_hash_t hash = unicode_get_hash(ep->me_key);
- assert(hash != -1);
- size_t i = hash & mask;
- for (size_t perturb = hash; dictkeys_get_index(keys, i) != DKIX_EMPTY;) {
- perturb >>= PERTURB_SHIFT;
- i = mask & (i*5 + perturb + 1);
- }
- dictkeys_set_index(keys, i, ix);
- }
- }
- /*
- Restructure the table by allocating a new table and reinserting all
- items again. When entries have been deleted, the new table may
- actually be smaller than the old one.
- If a table is split (its keys and hashes are shared, its values are not),
- then the values are temporarily copied into the table, it is resized as
- a combined table, then the me_value slots in the old table are NULLed out.
- After resizing a table is always combined.
- This function supports:
- - Unicode split -> Unicode combined or Generic
- - Unicode combined -> Unicode combined or Generic
- - Generic -> Generic
- */
- static int
- dictresize(PyInterpreterState *interp, PyDictObject *mp,
- uint8_t log2_newsize, int unicode)
- {
- PyDictKeysObject *oldkeys;
- PyDictValues *oldvalues;
- if (log2_newsize >= SIZEOF_SIZE_T*8) {
- PyErr_NoMemory();
- return -1;
- }
- assert(log2_newsize >= PyDict_LOG_MINSIZE);
- oldkeys = mp->ma_keys;
- oldvalues = mp->ma_values;
- if (!DK_IS_UNICODE(oldkeys)) {
- unicode = 0;
- }
- /* NOTE: Current odict checks mp->ma_keys to detect resize happen.
- * So we can't reuse oldkeys even if oldkeys->dk_size == newsize.
- * TODO: Try reusing oldkeys when reimplement odict.
- */
- /* Allocate a new table. */
- mp->ma_keys = new_keys_object(interp, log2_newsize, unicode);
- if (mp->ma_keys == NULL) {
- mp->ma_keys = oldkeys;
- return -1;
- }
- // New table must be large enough.
- assert(mp->ma_keys->dk_usable >= mp->ma_used);
- Py_ssize_t numentries = mp->ma_used;
- if (oldvalues != NULL) {
- PyDictUnicodeEntry *oldentries = DK_UNICODE_ENTRIES(oldkeys);
- /* Convert split table into new combined table.
- * We must incref keys; we can transfer values.
- */
- if (mp->ma_keys->dk_kind == DICT_KEYS_GENERAL) {
- // split -> generic
- PyDictKeyEntry *newentries = DK_ENTRIES(mp->ma_keys);
- for (Py_ssize_t i = 0; i < numentries; i++) {
- int index = get_index_from_order(mp, i);
- PyDictUnicodeEntry *ep = &oldentries[index];
- assert(oldvalues->values[index] != NULL);
- newentries[i].me_key = Py_NewRef(ep->me_key);
- newentries[i].me_hash = unicode_get_hash(ep->me_key);
- newentries[i].me_value = oldvalues->values[index];
- }
- build_indices_generic(mp->ma_keys, newentries, numentries);
- }
- else { // split -> combined unicode
- PyDictUnicodeEntry *newentries = DK_UNICODE_ENTRIES(mp->ma_keys);
- for (Py_ssize_t i = 0; i < numentries; i++) {
- int index = get_index_from_order(mp, i);
- PyDictUnicodeEntry *ep = &oldentries[index];
- assert(oldvalues->values[index] != NULL);
- newentries[i].me_key = Py_NewRef(ep->me_key);
- newentries[i].me_value = oldvalues->values[index];
- }
- build_indices_unicode(mp->ma_keys, newentries, numentries);
- }
- dictkeys_decref(interp, oldkeys);
- mp->ma_values = NULL;
- free_values(oldvalues);
- }
- else { // oldkeys is combined.
- if (oldkeys->dk_kind == DICT_KEYS_GENERAL) {
- // generic -> generic
- assert(mp->ma_keys->dk_kind == DICT_KEYS_GENERAL);
- PyDictKeyEntry *oldentries = DK_ENTRIES(oldkeys);
- PyDictKeyEntry *newentries = DK_ENTRIES(mp->ma_keys);
- if (oldkeys->dk_nentries == numentries) {
- memcpy(newentries, oldentries, numentries * sizeof(PyDictKeyEntry));
- }
- else {
- PyDictKeyEntry *ep = oldentries;
- for (Py_ssize_t i = 0; i < numentries; i++) {
- while (ep->me_value == NULL)
- ep++;
- newentries[i] = *ep++;
- }
- }
- build_indices_generic(mp->ma_keys, newentries, numentries);
- }
- else { // oldkeys is combined unicode
- PyDictUnicodeEntry *oldentries = DK_UNICODE_ENTRIES(oldkeys);
- if (unicode) { // combined unicode -> combined unicode
- PyDictUnicodeEntry *newentries = DK_UNICODE_ENTRIES(mp->ma_keys);
- if (oldkeys->dk_nentries == numentries && mp->ma_keys->dk_kind == DICT_KEYS_UNICODE) {
- memcpy(newentries, oldentries, numentries * sizeof(PyDictUnicodeEntry));
- }
- else {
- PyDictUnicodeEntry *ep = oldentries;
- for (Py_ssize_t i = 0; i < numentries; i++) {
- while (ep->me_value == NULL)
- ep++;
- newentries[i] = *ep++;
- }
- }
- build_indices_unicode(mp->ma_keys, newentries, numentries);
- }
- else { // combined unicode -> generic
- PyDictKeyEntry *newentries = DK_ENTRIES(mp->ma_keys);
- PyDictUnicodeEntry *ep = oldentries;
- for (Py_ssize_t i = 0; i < numentries; i++) {
- while (ep->me_value == NULL)
- ep++;
- newentries[i].me_key = ep->me_key;
- newentries[i].me_hash = unicode_get_hash(ep->me_key);
- newentries[i].me_value = ep->me_value;
- ep++;
- }
- build_indices_generic(mp->ma_keys, newentries, numentries);
- }
- }
- // We can not use free_keys_object here because key's reference
- // are moved already.
- if (oldkeys != Py_EMPTY_KEYS) {
- #ifdef Py_REF_DEBUG
- _Py_DecRefTotal(_PyInterpreterState_GET());
- #endif
- assert(oldkeys->dk_kind != DICT_KEYS_SPLIT);
- assert(oldkeys->dk_refcnt == 1);
- #if PyDict_MAXFREELIST > 0
- struct _Py_dict_state *state = get_dict_state(interp);
- #ifdef Py_DEBUG
- // dictresize() must not be called after _PyDict_Fini()
- assert(state->keys_numfree != -1);
- #endif
- if (DK_LOG_SIZE(oldkeys) == PyDict_LOG_MINSIZE &&
- DK_IS_UNICODE(oldkeys) &&
- state->keys_numfree < PyDict_MAXFREELIST)
- {
- state->keys_free_list[state->keys_numfree++] = oldkeys;
- OBJECT_STAT_INC(to_freelist);
- }
- else
- #endif
- {
- PyObject_Free(oldkeys);
- }
- }
- }
- mp->ma_keys->dk_usable -= numentries;
- mp->ma_keys->dk_nentries = numentries;
- ASSERT_CONSISTENT(mp);
- return 0;
- }
- static PyObject *
- dict_new_presized(PyInterpreterState *interp, Py_ssize_t minused, bool unicode)
- {
- const uint8_t log2_max_presize = 17;
- const Py_ssize_t max_presize = ((Py_ssize_t)1) << log2_max_presize;
- uint8_t log2_newsize;
- PyDictKeysObject *new_keys;
- if (minused <= USABLE_FRACTION(PyDict_MINSIZE)) {
- return PyDict_New();
- }
- /* There are no strict guarantee that returned dict can contain minused
- * items without resize. So we create medium size dict instead of very
- * large dict or MemoryError.
- */
- if (minused > USABLE_FRACTION(max_presize)) {
- log2_newsize = log2_max_presize;
- }
- else {
- log2_newsize = estimate_log2_keysize(minused);
- }
- new_keys = new_keys_object(interp, log2_newsize, unicode);
- if (new_keys == NULL)
- return NULL;
- return new_dict(interp, new_keys, NULL, 0, 0);
- }
- PyObject *
- _PyDict_NewPresized(Py_ssize_t minused)
- {
- PyInterpreterState *interp = _PyInterpreterState_GET();
- return dict_new_presized(interp, minused, false);
- }
- PyObject *
- _PyDict_FromItems(PyObject *const *keys, Py_ssize_t keys_offset,
- PyObject *const *values, Py_ssize_t values_offset,
- Py_ssize_t length)
- {
- bool unicode = true;
- PyObject *const *ks = keys;
- PyInterpreterState *interp = _PyInterpreterState_GET();
- for (Py_ssize_t i = 0; i < length; i++) {
- if (!PyUnicode_CheckExact(*ks)) {
- unicode = false;
- break;
- }
- ks += keys_offset;
- }
- PyObject *dict = dict_new_presized(interp, length, unicode);
- if (dict == NULL) {
- return NULL;
- }
- ks = keys;
- PyObject *const *vs = values;
- for (Py_ssize_t i = 0; i < length; i++) {
- PyObject *key = *ks;
- PyObject *value = *vs;
- if (PyDict_SetItem(dict, key, value) < 0) {
- Py_DECREF(dict);
- return NULL;
- }
- ks += keys_offset;
- vs += values_offset;
- }
- return dict;
- }
- /* Note that, for historical reasons, PyDict_GetItem() suppresses all errors
- * that may occur (originally dicts supported only string keys, and exceptions
- * weren't possible). So, while the original intent was that a NULL return
- * meant the key wasn't present, in reality it can mean that, or that an error
- * (suppressed) occurred while computing the key's hash, or that some error
- * (suppressed) occurred when comparing keys in the dict's internal probe
- * sequence. A nasty example of the latter is when a Python-coded comparison
- * function hits a stack-depth error, which can cause this to return NULL
- * even if the key is present.
- */
- PyObject *
- PyDict_GetItem(PyObject *op, PyObject *key)
- {
- if (!PyDict_Check(op)) {
- return NULL;
- }
- PyDictObject *mp = (PyDictObject *)op;
- Py_hash_t hash;
- if (!PyUnicode_CheckExact(key) || (hash = unicode_get_hash(key)) == -1) {
- hash = PyObject_Hash(key);
- if (hash == -1) {
- PyErr_Clear();
- return NULL;
- }
- }
- PyThreadState *tstate = _PyThreadState_GET();
- #ifdef Py_DEBUG
- // bpo-40839: Before Python 3.10, it was possible to call PyDict_GetItem()
- // with the GIL released.
- _Py_EnsureTstateNotNULL(tstate);
- #endif
- /* Preserve the existing exception */
- PyObject *value;
- Py_ssize_t ix; (void)ix;
- PyObject *exc = _PyErr_GetRaisedException(tstate);
- ix = _Py_dict_lookup(mp, key, hash, &value);
- /* Ignore any exception raised by the lookup */
- _PyErr_SetRaisedException(tstate, exc);
- assert(ix >= 0 || value == NULL);
- return value;
- }
- Py_ssize_t
- _PyDict_LookupIndex(PyDictObject *mp, PyObject *key)
- {
- PyObject *value;
- assert(PyDict_CheckExact((PyObject*)mp));
- assert(PyUnicode_CheckExact(key));
- Py_hash_t hash = unicode_get_hash(key);
- if (hash == -1) {
- hash = PyObject_Hash(key);
- if (hash == -1) {
- return -1;
- }
- }
- return _Py_dict_lookup(mp, key, hash, &value);
- }
- /* Same as PyDict_GetItemWithError() but with hash supplied by caller.
- This returns NULL *with* an exception set if an exception occurred.
- It returns NULL *without* an exception set if the key wasn't present.
- */
- PyObject *
- _PyDict_GetItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash)
- {
- Py_ssize_t ix; (void)ix;
- PyDictObject *mp = (PyDictObject *)op;
- PyObject *value;
- if (!PyDict_Check(op)) {
- PyErr_BadInternalCall();
- return NULL;
- }
- ix = _Py_dict_lookup(mp, key, hash, &value);
- assert(ix >= 0 || value == NULL);
- return value;
- }
- /* Variant of PyDict_GetItem() that doesn't suppress exceptions.
- This returns NULL *with* an exception set if an exception occurred.
- It returns NULL *without* an exception set if the key wasn't present.
- */
- PyObject *
- PyDict_GetItemWithError(PyObject *op, PyObject *key)
- {
- Py_ssize_t ix; (void)ix;
- Py_hash_t hash;
- PyDictObject*mp = (PyDictObject *)op;
- PyObject *value;
- if (!PyDict_Check(op)) {
- PyErr_BadInternalCall();
- return NULL;
- }
- if (!PyUnicode_CheckExact(key) || (hash = unicode_get_hash(key)) == -1)
- {
- hash = PyObject_Hash(key);
- if (hash == -1) {
- return NULL;
- }
- }
- ix = _Py_dict_lookup(mp, key, hash, &value);
- assert(ix >= 0 || value == NULL);
- return value;
- }
- PyObject *
- _PyDict_GetItemWithError(PyObject *dp, PyObject *kv)
- {
- assert(PyUnicode_CheckExact(kv));
- Py_hash_t hash = kv->ob_type->tp_hash(kv);
- if (hash == -1) {
- return NULL;
- }
- return _PyDict_GetItem_KnownHash(dp, kv, hash);
- }
- PyObject *
- _PyDict_GetItemIdWithError(PyObject *dp, _Py_Identifier *key)
- {
- PyObject *kv;
- kv = _PyUnicode_FromId(key); /* borrowed */
- if (kv == NULL)
- return NULL;
- Py_hash_t hash = unicode_get_hash(kv);
- assert (hash != -1); /* interned strings have their hash value initialised */
- return _PyDict_GetItem_KnownHash(dp, kv, hash);
- }
- PyObject *
- _PyDict_GetItemStringWithError(PyObject *v, const char *key)
- {
- PyObject *kv, *rv;
- kv = PyUnicode_FromString(key);
- if (kv == NULL) {
- return NULL;
- }
- rv = PyDict_GetItemWithError(v, kv);
- Py_DECREF(kv);
- return rv;
- }
- /* Fast version of global value lookup (LOAD_GLOBAL).
- * Lookup in globals, then builtins.
- *
- *
- *
- *
- * Raise an exception and return NULL if an error occurred (ex: computing the
- * key hash failed, key comparison failed, ...). Return NULL if the key doesn't
- * exist. Return the value if the key exists.
- */
- PyObject *
- _PyDict_LoadGlobal(PyDictObject *globals, PyDictObject *builtins, PyObject *key)
- {
- Py_ssize_t ix;
- Py_hash_t hash;
- PyObject *value;
- if (!PyUnicode_CheckExact(key) || (hash = unicode_get_hash(key)) == -1) {
- hash = PyObject_Hash(key);
- if (hash == -1)
- return NULL;
- }
- /* namespace 1: globals */
- ix = _Py_dict_lookup(globals, key, hash, &value);
- if (ix == DKIX_ERROR)
- return NULL;
- if (ix != DKIX_EMPTY && value != NULL)
- return value;
- /* namespace 2: builtins */
- ix = _Py_dict_lookup(builtins, key, hash, &value);
- assert(ix >= 0 || value == NULL);
- return value;
- }
- /* Consumes references to key and value */
- int
- _PyDict_SetItem_Take2(PyDictObject *mp, PyObject *key, PyObject *value)
- {
- assert(key);
- assert(value);
- assert(PyDict_Check(mp));
- Py_hash_t hash;
- if (!PyUnicode_CheckExact(key) || (hash = unicode_get_hash(key)) == -1) {
- hash = PyObject_Hash(key);
- if (hash == -1) {
- Py_DECREF(key);
- Py_DECREF(value);
- return -1;
- }
- }
- PyInterpreterState *interp = _PyInterpreterState_GET();
- if (mp->ma_keys == Py_EMPTY_KEYS) {
- return insert_to_emptydict(interp, mp, key, hash, value);
- }
- /* insertdict() handles any resizing that might be necessary */
- return insertdict(interp, mp, key, hash, value);
- }
- /* CAUTION: PyDict_SetItem() must guarantee that it won't resize the
- * dictionary if it's merely replacing the value for an existing key.
- * This means that it's safe to loop over a dictionary with PyDict_Next()
- * and occasionally replace a value -- but you can't insert new keys or
- * remove them.
- */
- int
- PyDict_SetItem(PyObject *op, PyObject *key, PyObject *value)
- {
- if (!PyDict_Check(op)) {
- PyErr_BadInternalCall();
- return -1;
- }
- assert(key);
- assert(value);
- return _PyDict_SetItem_Take2((PyDictObject *)op,
- Py_NewRef(key), Py_NewRef(value));
- }
- int
- _PyDict_SetItem_KnownHash(PyObject *op, PyObject *key, PyObject *value,
- Py_hash_t hash)
- {
- PyDictObject *mp;
- if (!PyDict_Check(op)) {
- PyErr_BadInternalCall();
- return -1;
- }
- assert(key);
- assert(value);
- assert(hash != -1);
- mp = (PyDictObject *)op;
- PyInterpreterState *interp = _PyInterpreterState_GET();
- if (mp->ma_keys == Py_EMPTY_KEYS) {
- return insert_to_emptydict(interp, mp, Py_NewRef(key), hash, Py_NewRef(value));
- }
- /* insertdict() handles any resizing that might be necessary */
- return insertdict(interp, mp, Py_NewRef(key), hash, Py_NewRef(value));
- }
- static void
- delete_index_from_values(PyDictValues *values, Py_ssize_t ix)
- {
- uint8_t *size_ptr = ((uint8_t *)values)-2;
- int size = *size_ptr;
- int i;
- for (i = 1; size_ptr[-i] != ix; i++) {
- assert(i <= size);
- }
- assert(i <= size);
- for (; i < size; i++) {
- size_ptr[-i] = size_ptr[-i-1];
- }
- *size_ptr = size -1;
- }
- static int
- delitem_common(PyDictObject *mp, Py_hash_t hash, Py_ssize_t ix,
- PyObject *old_value, uint64_t new_version)
- {
- PyObject *old_key;
- Py_ssize_t hashpos = lookdict_index(mp->ma_keys, hash, ix);
- assert(hashpos >= 0);
- mp->ma_used--;
- mp->ma_version_tag = new_version;
- if (mp->ma_values) {
- assert(old_value == mp->ma_values->values[ix]);
- mp->ma_values->values[ix] = NULL;
- assert(ix < SHARED_KEYS_MAX_SIZE);
- /* Update order */
- delete_index_from_values(mp->ma_values, ix);
- ASSERT_CONSISTENT(mp);
- }
- else {
- mp->ma_keys->dk_version = 0;
- dictkeys_set_index(mp->ma_keys, hashpos, DKIX_DUMMY);
- if (DK_IS_UNICODE(mp->ma_keys)) {
- PyDictUnicodeEntry *ep = &DK_UNICODE_ENTRIES(mp->ma_keys)[ix];
- old_key = ep->me_key;
- ep->me_key = NULL;
- ep->me_value = NULL;
- }
- else {
- PyDictKeyEntry *ep = &DK_ENTRIES(mp->ma_keys)[ix];
- old_key = ep->me_key;
- ep->me_key = NULL;
- ep->me_value = NULL;
- ep->me_hash = 0;
- }
- Py_DECREF(old_key);
- }
- Py_DECREF(old_value);
- ASSERT_CONSISTENT(mp);
- return 0;
- }
- int
- PyDict_DelItem(PyObject *op, PyObject *key)
- {
- Py_hash_t hash;
- assert(key);
- if (!PyUnicode_CheckExact(key) || (hash = unicode_get_hash(key)) == -1) {
- hash = PyObject_Hash(key);
- if (hash == -1)
- return -1;
- }
- return _PyDict_DelItem_KnownHash(op, key, hash);
- }
- int
- _PyDict_DelItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash)
- {
- Py_ssize_t ix;
- PyDictObject *mp;
- PyObject *old_value;
- if (!PyDict_Check(op)) {
- PyErr_BadInternalCall();
- return -1;
- }
- assert(key);
- assert(hash != -1);
- mp = (PyDictObject *)op;
- ix = _Py_dict_lookup(mp, key, hash, &old_value);
- if (ix == DKIX_ERROR)
- return -1;
- if (ix == DKIX_EMPTY || old_value == NULL) {
- _PyErr_SetKeyError(key);
- return -1;
- }
- PyInterpreterState *interp = _PyInterpreterState_GET();
- uint64_t new_version = _PyDict_NotifyEvent(
- interp, PyDict_EVENT_DELETED, mp, key, NULL);
- return delitem_common(mp, hash, ix, old_value, new_version);
- }
- /* This function promises that the predicate -> deletion sequence is atomic
- * (i.e. protected by the GIL), assuming the predicate itself doesn't
- * release the GIL.
- */
- int
- _PyDict_DelItemIf(PyObject *op, PyObject *key,
- int (*predicate)(PyObject *value))
- {
- Py_ssize_t hashpos, ix;
- PyDictObject *mp;
- Py_hash_t hash;
- PyObject *old_value;
- int res;
- if (!PyDict_Check(op)) {
- PyErr_BadInternalCall();
- return -1;
- }
- assert(key);
- hash = PyObject_Hash(key);
- if (hash == -1)
- return -1;
- mp = (PyDictObject *)op;
- ix = _Py_dict_lookup(mp, key, hash, &old_value);
- if (ix == DKIX_ERROR)
- return -1;
- if (ix == DKIX_EMPTY || old_value == NULL) {
- _PyErr_SetKeyError(key);
- return -1;
- }
- res = predicate(old_value);
- if (res == -1)
- return -1;
- hashpos = lookdict_index(mp->ma_keys, hash, ix);
- assert(hashpos >= 0);
- if (res > 0) {
- PyInterpreterState *interp = _PyInterpreterState_GET();
- uint64_t new_version = _PyDict_NotifyEvent(
- interp, PyDict_EVENT_DELETED, mp, key, NULL);
- return delitem_common(mp, hashpos, ix, old_value, new_version);
- } else {
- return 0;
- }
- }
- void
- PyDict_Clear(PyObject *op)
- {
- PyDictObject *mp;
- PyDictKeysObject *oldkeys;
- PyDictValues *oldvalues;
- Py_ssize_t i, n;
- if (!PyDict_Check(op))
- return;
- mp = ((PyDictObject *)op);
- oldkeys = mp->ma_keys;
- oldvalues = mp->ma_values;
- if (oldkeys == Py_EMPTY_KEYS) {
- return;
- }
- /* Empty the dict... */
- PyInterpreterState *interp = _PyInterpreterState_GET();
- uint64_t new_version = _PyDict_NotifyEvent(
- interp, PyDict_EVENT_CLEARED, mp, NULL, NULL);
- dictkeys_incref(Py_EMPTY_KEYS);
- mp->ma_keys = Py_EMPTY_KEYS;
- mp->ma_values = NULL;
- mp->ma_used = 0;
- mp->ma_version_tag = new_version;
- /* ...then clear the keys and values */
- if (oldvalues != NULL) {
- n = oldkeys->dk_nentries;
- for (i = 0; i < n; i++)
- Py_CLEAR(oldvalues->values[i]);
- free_values(oldvalues);
- dictkeys_decref(interp, oldkeys);
- }
- else {
- assert(oldkeys->dk_refcnt == 1);
- dictkeys_decref(interp, oldkeys);
- }
- ASSERT_CONSISTENT(mp);
- }
- /* Internal version of PyDict_Next that returns a hash value in addition
- * to the key and value.
- * Return 1 on success, return 0 when the reached the end of the dictionary
- * (or if op is not a dictionary)
- */
- int
- _PyDict_Next(PyObject *op, Py_ssize_t *ppos, PyObject **pkey,
- PyObject **pvalue, Py_hash_t *phash)
- {
- Py_ssize_t i;
- PyDictObject *mp;
- PyObject *key, *value;
- Py_hash_t hash;
- if (!PyDict_Check(op))
- return 0;
- mp = (PyDictObject *)op;
- i = *ppos;
- if (mp->ma_values) {
- assert(mp->ma_used <= SHARED_KEYS_MAX_SIZE);
- if (i < 0 || i >= mp->ma_used)
- return 0;
- int index = get_index_from_order(mp, i);
- value = mp->ma_values->values[index];
- key = DK_UNICODE_ENTRIES(mp->ma_keys)[index].me_key;
- hash = unicode_get_hash(key);
- assert(value != NULL);
- }
- else {
- Py_ssize_t n = mp->ma_keys->dk_nentries;
- if (i < 0 || i >= n)
- return 0;
- if (DK_IS_UNICODE(mp->ma_keys)) {
- PyDictUnicodeEntry *entry_ptr = &DK_UNICODE_ENTRIES(mp->ma_keys)[i];
- while (i < n && entry_ptr->me_value == NULL) {
- entry_ptr++;
- i++;
- }
- if (i >= n)
- return 0;
- key = entry_ptr->me_key;
- hash = unicode_get_hash(entry_ptr->me_key);
- value = entry_ptr->me_value;
- }
- else {
- PyDictKeyEntry *entry_ptr = &DK_ENTRIES(mp->ma_keys)[i];
- while (i < n && entry_ptr->me_value == NULL) {
- entry_ptr++;
- i++;
- }
- if (i >= n)
- return 0;
- key = entry_ptr->me_key;
- hash = entry_ptr->me_hash;
- value = entry_ptr->me_value;
- }
- }
- *ppos = i+1;
- if (pkey)
- *pkey = key;
- if (pvalue)
- *pvalue = value;
- if (phash)
- *phash = hash;
- return 1;
- }
- /*
- * Iterate over a dict. Use like so:
- *
- * Py_ssize_t i;
- * PyObject *key, *value;
- * i = 0; # important! i should not otherwise be changed by you
- * while (PyDict_Next(yourdict, &i, &key, &value)) {
- * Refer to borrowed references in key and value.
- * }
- *
- * Return 1 on success, return 0 when the reached the end of the dictionary
- * (or if op is not a dictionary)
- *
- * CAUTION: In general, it isn't safe to use PyDict_Next in a loop that
- * mutates the dict. One exception: it is safe if the loop merely changes
- * the values associated with the keys (but doesn't insert new keys or
- * delete keys), via PyDict_SetItem().
- */
- int
- PyDict_Next(PyObject *op, Py_ssize_t *ppos, PyObject **pkey, PyObject **pvalue)
- {
- return _PyDict_Next(op, ppos, pkey, pvalue, NULL);
- }
- /* Internal version of dict.pop(). */
- PyObject *
- _PyDict_Pop_KnownHash(PyObject *dict, PyObject *key, Py_hash_t hash, PyObject *deflt)
- {
- Py_ssize_t ix;
- PyObject *old_value;
- PyDictObject *mp;
- PyInterpreterState *interp = _PyInterpreterState_GET();
- assert(PyDict_Check(dict));
- mp = (PyDictObject *)dict;
- if (mp->ma_used == 0) {
- if (deflt) {
- return Py_NewRef(deflt);
- }
- _PyErr_SetKeyError(key);
- return NULL;
- }
- ix = _Py_dict_lookup(mp, key, hash, &old_value);
- if (ix == DKIX_ERROR)
- return NULL;
- if (ix == DKIX_EMPTY || old_value == NULL) {
- if (deflt) {
- return Py_NewRef(deflt);
- }
- _PyErr_SetKeyError(key);
- return NULL;
- }
- assert(old_value != NULL);
- uint64_t new_version = _PyDict_NotifyEvent(
- interp, PyDict_EVENT_DELETED, mp, key, NULL);
- delitem_common(mp, hash, ix, Py_NewRef(old_value), new_version);
- ASSERT_CONSISTENT(mp);
- return old_value;
- }
- PyObject *
- _PyDict_Pop(PyObject *dict, PyObject *key, PyObject *deflt)
- {
- Py_hash_t hash;
- if (((PyDictObject *)dict)->ma_used == 0) {
- if (deflt) {
- return Py_NewRef(deflt);
- }
- _PyErr_SetKeyError(key);
- return NULL;
- }
- if (!PyUnicode_CheckExact(key) || (hash = unicode_get_hash(key)) == -1) {
- hash = PyObject_Hash(key);
- if (hash == -1)
- return NULL;
- }
- return _PyDict_Pop_KnownHash(dict, key, hash, deflt);
- }
- /* Internal version of dict.from_keys(). It is subclass-friendly. */
- PyObject *
- _PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value)
- {
- PyObject *it; /* iter(iterable) */
- PyObject *key;
- PyObject *d;
- int status;
- PyInterpreterState *interp = _PyInterpreterState_GET();
- d = _PyObject_CallNoArgs(cls);
- if (d == NULL)
- return NULL;
- if (PyDict_CheckExact(d) && ((PyDictObject *)d)->ma_used == 0) {
- if (PyDict_CheckExact(iterable)) {
- PyDictObject *mp = (PyDictObject *)d;
- PyObject *oldvalue;
- Py_ssize_t pos = 0;
- PyObject *key;
- Py_hash_t hash;
- int unicode = DK_IS_UNICODE(((PyDictObject*)iterable)->ma_keys);
- if (dictresize(interp, mp,
- estimate_log2_keysize(PyDict_GET_SIZE(iterable)),
- unicode)) {
- Py_DECREF(d);
- return NULL;
- }
- while (_PyDict_Next(iterable, &pos, &key, &oldvalue, &hash)) {
- if (insertdict(interp, mp,
- Py_NewRef(key), hash, Py_NewRef(value))) {
- Py_DECREF(d);
- return NULL;
- }
- }
- return d;
- }
- if (PyAnySet_CheckExact(iterable)) {
- PyDictObject *mp = (PyDictObject *)d;
- Py_ssize_t pos = 0;
- PyObject *key;
- Py_hash_t hash;
- if (dictresize(interp, mp,
- estimate_log2_keysize(PySet_GET_SIZE(iterable)), 0)) {
- Py_DECREF(d);
- return NULL;
- }
- while (_PySet_NextEntry(iterable, &pos, &key, &hash)) {
- if (insertdict(interp, mp, Py_NewRef(key), hash, Py_NewRef(value))) {
- Py_DECREF(d);
- return NULL;
- }
- }
- return d;
- }
- }
- it = PyObject_GetIter(iterable);
- if (it == NULL){
- Py_DECREF(d);
- return NULL;
- }
- if (PyDict_CheckExact(d)) {
- while ((key = PyIter_Next(it)) != NULL) {
- status = PyDict_SetItem(d, key, value);
- Py_DECREF(key);
- if (status < 0)
- goto Fail;
- }
- } else {
- while ((key = PyIter_Next(it)) != NULL) {
- status = PyObject_SetItem(d, key, value);
- Py_DECREF(key);
- if (status < 0)
- goto Fail;
- }
- }
- if (PyErr_Occurred())
- goto Fail;
- Py_DECREF(it);
- return d;
- Fail:
- Py_DECREF(it);
- Py_DECREF(d);
- return NULL;
- }
- /* Methods */
- static void
- dict_dealloc(PyDictObject *mp)
- {
- PyInterpreterState *interp = _PyInterpreterState_GET();
- assert(Py_REFCNT(mp) == 0);
- Py_SET_REFCNT(mp, 1);
- _PyDict_NotifyEvent(interp, PyDict_EVENT_DEALLOCATED, mp, NULL, NULL);
- if (Py_REFCNT(mp) > 1) {
- Py_SET_REFCNT(mp, Py_REFCNT(mp) - 1);
- return;
- }
- Py_SET_REFCNT(mp, 0);
- PyDictValues *values = mp->ma_values;
- PyDictKeysObject *keys = mp->ma_keys;
- Py_ssize_t i, n;
- /* bpo-31095: UnTrack is needed before calling any callbacks */
- PyObject_GC_UnTrack(mp);
- Py_TRASHCAN_BEGIN(mp, dict_dealloc)
- if (values != NULL) {
- for (i = 0, n = mp->ma_keys->dk_nentries; i < n; i++) {
- Py_XDECREF(values->values[i]);
- }
- free_values(values);
- dictkeys_decref(interp, keys);
- }
- else if (keys != NULL) {
- assert(keys->dk_refcnt == 1 || keys == Py_EMPTY_KEYS);
- dictkeys_decref(interp, keys);
- }
- #if PyDict_MAXFREELIST > 0
- struct _Py_dict_state *state = get_dict_state(interp);
- #ifdef Py_DEBUG
- // new_dict() must not be called after _PyDict_Fini()
- assert(state->numfree != -1);
- #endif
- if (state->numfree < PyDict_MAXFREELIST && Py_IS_TYPE(mp, &PyDict_Type)) {
- state->free_list[state->numfree++] = mp;
- OBJECT_STAT_INC(to_freelist);
- }
- else
- #endif
- {
- Py_TYPE(mp)->tp_free((PyObject *)mp);
- }
- Py_TRASHCAN_END
- }
- static PyObject *
- dict_repr(PyDictObject *mp)
- {
- Py_ssize_t i;
- PyObject *key = NULL, *value = NULL;
- _PyUnicodeWriter writer;
- int first;
- i = Py_ReprEnter((PyObject *)mp);
- if (i != 0) {
- return i > 0 ? PyUnicode_FromString("{...}") : NULL;
- }
- if (mp->ma_used == 0) {
- Py_ReprLeave((PyObject *)mp);
- return PyUnicode_FromString("{}");
- }
- _PyUnicodeWriter_Init(&writer);
- writer.overallocate = 1;
- /* "{" + "1: 2" + ", 3: 4" * (len - 1) + "}" */
- writer.min_length = 1 + 4 + (2 + 4) * (mp->ma_used - 1) + 1;
- if (_PyUnicodeWriter_WriteChar(&writer, '{') < 0)
- goto error;
- /* Do repr() on each key+value pair, and insert ": " between them.
- Note that repr may mutate the dict. */
- i = 0;
- first = 1;
- while (PyDict_Next((PyObject *)mp, &i, &key, &value)) {
- PyObject *s;
- int res;
- /* Prevent repr from deleting key or value during key format. */
- Py_INCREF(key);
- Py_INCREF(value);
- if (!first) {
- if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ", 2) < 0)
- goto error;
- }
- first = 0;
- s = PyObject_Repr(key);
- if (s == NULL)
- goto error;
- res = _PyUnicodeWriter_WriteStr(&writer, s);
- Py_DECREF(s);
- if (res < 0)
- goto error;
- if (_PyUnicodeWriter_WriteASCIIString(&writer, ": ", 2) < 0)
- goto error;
- s = PyObject_Repr(value);
- if (s == NULL)
- goto error;
- res = _PyUnicodeWriter_WriteStr(&writer, s);
- Py_DECREF(s);
- if (res < 0)
- goto error;
- Py_CLEAR(key);
- Py_CLEAR(value);
- }
- writer.overallocate = 0;
- if (_PyUnicodeWriter_WriteChar(&writer, '}') < 0)
- goto error;
- Py_ReprLeave((PyObject *)mp);
- return _PyUnicodeWriter_Finish(&writer);
- error:
- Py_ReprLeave((PyObject *)mp);
- _PyUnicodeWriter_Dealloc(&writer);
- Py_XDECREF(key);
- Py_XDECREF(value);
- return NULL;
- }
- static Py_ssize_t
- dict_length(PyDictObject *mp)
- {
- return mp->ma_used;
- }
- static PyObject *
- dict_subscript(PyDictObject *mp, PyObject *key)
- {
- Py_ssize_t ix;
- Py_hash_t hash;
- PyObject *value;
- if (!PyUnicode_CheckExact(key) || (hash = unicode_get_hash(key)) == -1) {
- hash = PyObject_Hash(key);
- if (hash == -1)
- return NULL;
- }
- ix = _Py_dict_lookup(mp, key, hash, &value);
- if (ix == DKIX_ERROR)
- return NULL;
- if (ix == DKIX_EMPTY || value == NULL) {
- if (!PyDict_CheckExact(mp)) {
- /* Look up __missing__ method if we're a subclass. */
- PyObject *missing, *res;
- missing = _PyObject_LookupSpecial(
- (PyObject *)mp, &_Py_ID(__missing__));
- if (missing != NULL) {
- res = PyObject_CallOneArg(missing, key);
- Py_DECREF(missing);
- return res;
- }
- else if (PyErr_Occurred())
- return NULL;
- }
- _PyErr_SetKeyError(key);
- return NULL;
- }
- return Py_NewRef(value);
- }
- static int
- dict_ass_sub(PyDictObject *mp, PyObject *v, PyObject *w)
- {
- if (w == NULL)
- return PyDict_DelItem((PyObject *)mp, v);
- else
- return PyDict_SetItem((PyObject *)mp, v, w);
- }
- static PyMappingMethods dict_as_mapping = {
- (lenfunc)dict_length, /*mp_length*/
- (binaryfunc)dict_subscript, /*mp_subscript*/
- (objobjargproc)dict_ass_sub, /*mp_ass_subscript*/
- };
- static PyObject *
- dict_keys(PyDictObject *mp)
- {
- PyObject *v;
- Py_ssize_t n;
- again:
- n = mp->ma_used;
- v = PyList_New(n);
- if (v == NULL)
- return NULL;
- if (n != mp->ma_used) {
- /* Durnit. The allocations caused the dict to resize.
- * Just start over, this shouldn't normally happen.
- */
- Py_DECREF(v);
- goto again;
- }
- /* Nothing we do below makes any function calls. */
- Py_ssize_t j = 0, pos = 0;
- PyObject *key;
- while (_PyDict_Next((PyObject*)mp, &pos, &key, NULL, NULL)) {
- assert(j < n);
- PyList_SET_ITEM(v, j, Py_NewRef(key));
- j++;
- }
- assert(j == n);
- return v;
- }
- static PyObject *
- dict_values(PyDictObject *mp)
- {
- PyObject *v;
- Py_ssize_t n;
- again:
- n = mp->ma_used;
- v = PyList_New(n);
- if (v == NULL)
- return NULL;
- if (n != mp->ma_used) {
- /* Durnit. The allocations caused the dict to resize.
- * Just start over, this shouldn't normally happen.
- */
- Py_DECREF(v);
- goto again;
- }
- /* Nothing we do below makes any function calls. */
- Py_ssize_t j = 0, pos = 0;
- PyObject *value;
- while (_PyDict_Next((PyObject*)mp, &pos, NULL, &value, NULL)) {
- assert(j < n);
- PyList_SET_ITEM(v, j, Py_NewRef(value));
- j++;
- }
- assert(j == n);
- return v;
- }
- static PyObject *
- dict_items(PyDictObject *mp)
- {
- PyObject *v;
- Py_ssize_t i, n;
- PyObject *item;
- /* Preallocate the list of tuples, to avoid allocations during
- * the loop over the items, which could trigger GC, which
- * could resize the dict. :-(
- */
- again:
- n = mp->ma_used;
- v = PyList_New(n);
- if (v == NULL)
- return NULL;
- for (i = 0; i < n; i++) {
- item = PyTuple_New(2);
- if (item == NULL) {
- Py_DECREF(v);
- return NULL;
- }
- PyList_SET_ITEM(v, i, item);
- }
- if (n != mp->ma_used) {
- /* Durnit. The allocations caused the dict to resize.
- * Just start over, this shouldn't normally happen.
- */
- Py_DECREF(v);
- goto again;
- }
- /* Nothing we do below makes any function calls. */
- Py_ssize_t j = 0, pos = 0;
- PyObject *key, *value;
- while (_PyDict_Next((PyObject*)mp, &pos, &key, &value, NULL)) {
- assert(j < n);
- PyObject *item = PyList_GET_ITEM(v, j);
- PyTuple_SET_ITEM(item, 0, Py_NewRef(key));
- PyTuple_SET_ITEM(item, 1, Py_NewRef(value));
- j++;
- }
- assert(j == n);
- return v;
- }
- /*[clinic input]
- @classmethod
- dict.fromkeys
- iterable: object
- value: object=None
- /
- Create a new dictionary with keys from iterable and values set to value.
- [clinic start generated code]*/
- static PyObject *
- dict_fromkeys_impl(PyTypeObject *type, PyObject *iterable, PyObject *value)
- /*[clinic end generated code: output=8fb98e4b10384999 input=382ba4855d0f74c3]*/
- {
- return _PyDict_FromKeys((PyObject *)type, iterable, value);
- }
- /* Single-arg dict update; used by dict_update_common and operators. */
- static int
- dict_update_arg(PyObject *self, PyObject *arg)
- {
- if (PyDict_CheckExact(arg)) {
- return PyDict_Merge(self, arg, 1);
- }
- PyObject *func;
- if (_PyObject_LookupAttr(arg, &_Py_ID(keys), &func) < 0) {
- return -1;
- }
- if (func != NULL) {
- Py_DECREF(func);
- return PyDict_Merge(self, arg, 1);
- }
- return PyDict_MergeFromSeq2(self, arg, 1);
- }
- static int
- dict_update_common(PyObject *self, PyObject *args, PyObject *kwds,
- const char *methname)
- {
- PyObject *arg = NULL;
- int result = 0;
- if (!PyArg_UnpackTuple(args, methname, 0, 1, &arg)) {
- result = -1;
- }
- else if (arg != NULL) {
- result = dict_update_arg(self, arg);
- }
- if (result == 0 && kwds != NULL) {
- if (PyArg_ValidateKeywordArguments(kwds))
- result = PyDict_Merge(self, kwds, 1);
- else
- result = -1;
- }
- return result;
- }
- /* Note: dict.update() uses the METH_VARARGS|METH_KEYWORDS calling convention.
- Using METH_FASTCALL|METH_KEYWORDS would make dict.update(**dict2) calls
- slower, see the issue #29312. */
- static PyObject *
- dict_update(PyObject *self, PyObject *args, PyObject *kwds)
- {
- if (dict_update_common(self, args, kwds, "update") != -1)
- Py_RETURN_NONE;
- return NULL;
- }
- /* Update unconditionally replaces existing items.
- Merge has a 3rd argument 'override'; if set, it acts like Update,
- otherwise it leaves existing items unchanged.
- PyDict_{Update,Merge} update/merge from a mapping object.
- PyDict_MergeFromSeq2 updates/merges from any iterable object
- producing iterable objects of length 2.
- */
- int
- PyDict_MergeFromSeq2(PyObject *d, PyObject *seq2, int override)
- {
- PyObject *it; /* iter(seq2) */
- Py_ssize_t i; /* index into seq2 of current element */
- PyObject *item; /* seq2[i] */
- PyObject *fast; /* item as a 2-tuple or 2-list */
- assert(d != NULL);
- assert(PyDict_Check(d));
- assert(seq2 != NULL);
- it = PyObject_GetIter(seq2);
- if (it == NULL)
- return -1;
- for (i = 0; ; ++i) {
- PyObject *key, *value;
- Py_ssize_t n;
- fast = NULL;
- item = PyIter_Next(it);
- if (item == NULL) {
- if (PyErr_Occurred())
- goto Fail;
- break;
- }
- /* Convert item to sequence, and verify length 2. */
- fast = PySequence_Fast(item, "");
- if (fast == NULL) {
- if (PyErr_ExceptionMatches(PyExc_TypeError))
- PyErr_Format(PyExc_TypeError,
- "cannot convert dictionary update "
- "sequence element #%zd to a sequence",
- i);
- goto Fail;
- }
- n = PySequence_Fast_GET_SIZE(fast);
- if (n != 2) {
- PyErr_Format(PyExc_ValueError,
- "dictionary update sequence element #%zd "
- "has length %zd; 2 is required",
- i, n);
- goto Fail;
- }
- /* Update/merge with this (key, value) pair. */
- key = PySequence_Fast_GET_ITEM(fast, 0);
- value = PySequence_Fast_GET_ITEM(fast, 1);
- Py_INCREF(key);
- Py_INCREF(value);
- if (override) {
- if (PyDict_SetItem(d, key, value) < 0) {
- Py_DECREF(key);
- Py_DECREF(value);
- goto Fail;
- }
- }
- else {
- if (PyDict_SetDefault(d, key, value) == NULL) {
- Py_DECREF(key);
- Py_DECREF(value);
- goto Fail;
- }
- }
- Py_DECREF(key);
- Py_DECREF(value);
- Py_DECREF(fast);
- Py_DECREF(item);
- }
- i = 0;
- ASSERT_CONSISTENT(d);
- goto Return;
- Fail:
- Py_XDECREF(item);
- Py_XDECREF(fast);
- i = -1;
- Return:
- Py_DECREF(it);
- return Py_SAFE_DOWNCAST(i, Py_ssize_t, int);
- }
- static int
- dict_merge(PyInterpreterState *interp, PyObject *a, PyObject *b, int override)
- {
- PyDictObject *mp, *other;
- assert(0 <= override && override <= 2);
- /* We accept for the argument either a concrete dictionary object,
- * or an abstract "mapping" object. For the former, we can do
- * things quite efficiently. For the latter, we only require that
- * PyMapping_Keys() and PyObject_GetItem() be supported.
- */
- if (a == NULL || !PyDict_Check(a) || b == NULL) {
- PyErr_BadInternalCall();
- return -1;
- }
- mp = (PyDictObject*)a;
- if (PyDict_Check(b) && (Py_TYPE(b)->tp_iter == (getiterfunc)dict_iter)) {
- other = (PyDictObject*)b;
- if (other == mp || other->ma_used == 0)
- /* a.update(a) or a.update({}); nothing to do */
- return 0;
- if (mp->ma_used == 0) {
- /* Since the target dict is empty, PyDict_GetItem()
- * always returns NULL. Setting override to 1
- * skips the unnecessary test.
- */
- override = 1;
- PyDictKeysObject *okeys = other->ma_keys;
- // If other is clean, combined, and just allocated, just clone it.
- if (other->ma_values == NULL &&
- other->ma_used == okeys->dk_nentries &&
- (DK_LOG_SIZE(okeys) == PyDict_LOG_MINSIZE ||
- USABLE_FRACTION(DK_SIZE(okeys)/2) < other->ma_used)) {
- uint64_t new_version = _PyDict_NotifyEvent(
- interp, PyDict_EVENT_CLONED, mp, b, NULL);
- PyDictKeysObject *keys = clone_combined_dict_keys(other);
- if (keys == NULL) {
- return -1;
- }
- dictkeys_decref(interp, mp->ma_keys);
- mp->ma_keys = keys;
- if (mp->ma_values != NULL) {
- free_values(mp->ma_values);
- mp->ma_values = NULL;
- }
- mp->ma_used = other->ma_used;
- mp->ma_version_tag = new_version;
- ASSERT_CONSISTENT(mp);
- if (_PyObject_GC_IS_TRACKED(other) && !_PyObject_GC_IS_TRACKED(mp)) {
- /* Maintain tracking. */
- _PyObject_GC_TRACK(mp);
- }
- return 0;
- }
- }
- /* Do one big resize at the start, rather than
- * incrementally resizing as we insert new items. Expect
- * that there will be no (or few) overlapping keys.
- */
- if (USABLE_FRACTION(DK_SIZE(mp->ma_keys)) < other->ma_used) {
- int unicode = DK_IS_UNICODE(other->ma_keys);
- if (dictresize(interp, mp,
- estimate_log2_keysize(mp->ma_used + other->ma_used),
- unicode)) {
- return -1;
- }
- }
- Py_ssize_t orig_size = other->ma_keys->dk_nentries;
- Py_ssize_t pos = 0;
- Py_hash_t hash;
- PyObject *key, *value;
- while (_PyDict_Next((PyObject*)other, &pos, &key, &value, &hash)) {
- int err = 0;
- Py_INCREF(key);
- Py_INCREF(value);
- if (override == 1) {
- err = insertdict(interp, mp,
- Py_NewRef(key), hash, Py_NewRef(value));
- }
- else {
- err = _PyDict_Contains_KnownHash(a, key, hash);
- if (err == 0) {
- err = insertdict(interp, mp,
- Py_NewRef(key), hash, Py_NewRef(value));
- }
- else if (err > 0) {
- if (override != 0) {
- _PyErr_SetKeyError(key);
- Py_DECREF(value);
- Py_DECREF(key);
- return -1;
- }
- err = 0;
- }
- }
- Py_DECREF(value);
- Py_DECREF(key);
- if (err != 0)
- return -1;
- if (orig_size != other->ma_keys->dk_nentries) {
- PyErr_SetString(PyExc_RuntimeError,
- "dict mutated during update");
- return -1;
- }
- }
- }
- else {
- /* Do it the generic, slower way */
- PyObject *keys = PyMapping_Keys(b);
- PyObject *iter;
- PyObject *key, *value;
- int status;
- if (keys == NULL)
- /* Docstring says this is equivalent to E.keys() so
- * if E doesn't have a .keys() method we want
- * AttributeError to percolate up. Might as well
- * do the same for any other error.
- */
- return -1;
- iter = PyObject_GetIter(keys);
- Py_DECREF(keys);
- if (iter == NULL)
- return -1;
- for (key = PyIter_Next(iter); key; key = PyIter_Next(iter)) {
- if (override != 1) {
- status = PyDict_Contains(a, key);
- if (status != 0) {
- if (status > 0) {
- if (override == 0) {
- Py_DECREF(key);
- continue;
- }
- _PyErr_SetKeyError(key);
- }
- Py_DECREF(key);
- Py_DECREF(iter);
- return -1;
- }
- }
- value = PyObject_GetItem(b, key);
- if (value == NULL) {
- Py_DECREF(iter);
- Py_DECREF(key);
- return -1;
- }
- status = PyDict_SetItem(a, key, value);
- Py_DECREF(key);
- Py_DECREF(value);
- if (status < 0) {
- Py_DECREF(iter);
- return -1;
- }
- }
- Py_DECREF(iter);
- if (PyErr_Occurred())
- /* Iterator completed, via error */
- return -1;
- }
- ASSERT_CONSISTENT(a);
- return 0;
- }
- int
- PyDict_Update(PyObject *a, PyObject *b)
- {
- PyInterpreterState *interp = _PyInterpreterState_GET();
- return dict_merge(interp, a, b, 1);
- }
- int
- PyDict_Merge(PyObject *a, PyObject *b, int override)
- {
- PyInterpreterState *interp = _PyInterpreterState_GET();
- /* XXX Deprecate override not in (0, 1). */
- return dict_merge(interp, a, b, override != 0);
- }
- int
- _PyDict_MergeEx(PyObject *a, PyObject *b, int override)
- {
- PyInterpreterState *interp = _PyInterpreterState_GET();
- return dict_merge(interp, a, b, override);
- }
- static PyObject *
- dict_copy(PyDictObject *mp, PyObject *Py_UNUSED(ignored))
- {
- return PyDict_Copy((PyObject*)mp);
- }
- PyObject *
- PyDict_Copy(PyObject *o)
- {
- PyObject *copy;
- PyDictObject *mp;
- PyInterpreterState *interp = _PyInterpreterState_GET();
- if (o == NULL || !PyDict_Check(o)) {
- PyErr_BadInternalCall();
- return NULL;
- }
- mp = (PyDictObject *)o;
- if (mp->ma_used == 0) {
- /* The dict is empty; just return a new dict. */
- return PyDict_New();
- }
- if (_PyDict_HasSplitTable(mp)) {
- PyDictObject *split_copy;
- size_t size = shared_keys_usable_size(mp->ma_keys);
- PyDictValues *newvalues = new_values(size);
- if (newvalues == NULL)
- return PyErr_NoMemory();
- split_copy = PyObject_GC_New(PyDictObject, &PyDict_Type);
- if (split_copy == NULL) {
- free_values(newvalues);
- return NULL;
- }
- size_t prefix_size = ((uint8_t *)newvalues)[-1];
- memcpy(((char *)newvalues)-prefix_size, ((char *)mp->ma_values)-prefix_size, prefix_size-1);
- split_copy->ma_values = newvalues;
- split_copy->ma_keys = mp->ma_keys;
- split_copy->ma_used = mp->ma_used;
- split_copy->ma_version_tag = DICT_NEXT_VERSION(interp);
- dictkeys_incref(mp->ma_keys);
- for (size_t i = 0; i < size; i++) {
- PyObject *value = mp->ma_values->values[i];
- split_copy->ma_values->values[i] = Py_XNewRef(value);
- }
- if (_PyObject_GC_IS_TRACKED(mp))
- _PyObject_GC_TRACK(split_copy);
- return (PyObject *)split_copy;
- }
- if (Py_TYPE(mp)->tp_iter == (getiterfunc)dict_iter &&
- mp->ma_values == NULL &&
- (mp->ma_used >= (mp->ma_keys->dk_nentries * 2) / 3))
- {
- /* Use fast-copy if:
- (1) type(mp) doesn't override tp_iter; and
- (2) 'mp' is not a split-dict; and
- (3) if 'mp' is non-compact ('del' operation does not resize dicts),
- do fast-copy only if it has at most 1/3 non-used keys.
- The last condition (3) is important to guard against a pathological
- case when a large dict is almost emptied with multiple del/pop
- operations and copied after that. In cases like this, we defer to
- PyDict_Merge, which produces a compacted copy.
- */
- PyDictKeysObject *keys = clone_combined_dict_keys(mp);
- if (keys == NULL) {
- return NULL;
- }
- PyDictObject *new = (PyDictObject *)new_dict(interp, keys, NULL, 0, 0);
- if (new == NULL) {
- /* In case of an error, `new_dict()` takes care of
- cleaning up `keys`. */
- return NULL;
- }
- new->ma_used = mp->ma_used;
- ASSERT_CONSISTENT(new);
- if (_PyObject_GC_IS_TRACKED(mp)) {
- /* Maintain tracking. */
- _PyObject_GC_TRACK(new);
- }
- return (PyObject *)new;
- }
- copy = PyDict_New();
- if (copy == NULL)
- return NULL;
- if (dict_merge(interp, copy, o, 1) == 0)
- return copy;
- Py_DECREF(copy);
- return NULL;
- }
- Py_ssize_t
- PyDict_Size(PyObject *mp)
- {
- if (mp == NULL || !PyDict_Check(mp)) {
- PyErr_BadInternalCall();
- return -1;
- }
- return ((PyDictObject *)mp)->ma_used;
- }
- PyObject *
- PyDict_Keys(PyObject *mp)
- {
- if (mp == NULL || !PyDict_Check(mp)) {
- PyErr_BadInternalCall();
- return NULL;
- }
- return dict_keys((PyDictObject *)mp);
- }
- PyObject *
- PyDict_Values(PyObject *mp)
- {
- if (mp == NULL || !PyDict_Check(mp)) {
- PyErr_BadInternalCall();
- return NULL;
- }
- return dict_values((PyDictObject *)mp);
- }
- PyObject *
- PyDict_Items(PyObject *mp)
- {
- if (mp == NULL || !PyDict_Check(mp)) {
- PyErr_BadInternalCall();
- return NULL;
- }
- return dict_items((PyDictObject *)mp);
- }
- /* Return 1 if dicts equal, 0 if not, -1 if error.
- * Gets out as soon as any difference is detected.
- * Uses only Py_EQ comparison.
- */
- static int
- dict_equal(PyDictObject *a, PyDictObject *b)
- {
- Py_ssize_t i;
- if (a->ma_used != b->ma_used)
- /* can't be equal if # of entries differ */
- return 0;
- /* Same # of entries -- check all of 'em. Exit early on any diff. */
- for (i = 0; i < a->ma_keys->dk_nentries; i++) {
- PyObject *key, *aval;
- Py_hash_t hash;
- if (DK_IS_UNICODE(a->ma_keys)) {
- PyDictUnicodeEntry *ep = &DK_UNICODE_ENTRIES(a->ma_keys)[i];
- key = ep->me_key;
- if (key == NULL) {
- continue;
- }
- hash = unicode_get_hash(key);
- if (a->ma_values)
- aval = a->ma_values->values[i];
- else
- aval = ep->me_value;
- }
- else {
- PyDictKeyEntry *ep = &DK_ENTRIES(a->ma_keys)[i];
- key = ep->me_key;
- aval = ep->me_value;
- hash = ep->me_hash;
- }
- if (aval != NULL) {
- int cmp;
- PyObject *bval;
- /* temporarily bump aval's refcount to ensure it stays
- alive until we're done with it */
- Py_INCREF(aval);
- /* ditto for key */
- Py_INCREF(key);
- /* reuse the known hash value */
- _Py_dict_lookup(b, key, hash, &bval);
- if (bval == NULL) {
- Py_DECREF(key);
- Py_DECREF(aval);
- if (PyErr_Occurred())
- return -1;
- return 0;
- }
- Py_INCREF(bval);
- cmp = PyObject_RichCompareBool(aval, bval, Py_EQ);
- Py_DECREF(key);
- Py_DECREF(aval);
- Py_DECREF(bval);
- if (cmp <= 0) /* error or not equal */
- return cmp;
- }
- }
- return 1;
- }
- static PyObject *
- dict_richcompare(PyObject *v, PyObject *w, int op)
- {
- int cmp;
- PyObject *res;
- if (!PyDict_Check(v) || !PyDict_Check(w)) {
- res = Py_NotImplemented;
- }
- else if (op == Py_EQ || op == Py_NE) {
- cmp = dict_equal((PyDictObject *)v, (PyDictObject *)w);
- if (cmp < 0)
- return NULL;
- res = (cmp == (op == Py_EQ)) ? Py_True : Py_False;
- }
- else
- res = Py_NotImplemented;
- return Py_NewRef(res);
- }
- /*[clinic input]
- @coexist
- dict.__contains__
- key: object
- /
- True if the dictionary has the specified key, else False.
- [clinic start generated code]*/
- static PyObject *
- dict___contains__(PyDictObject *self, PyObject *key)
- /*[clinic end generated code: output=a3d03db709ed6e6b input=fe1cb42ad831e820]*/
- {
- register PyDictObject *mp = self;
- Py_hash_t hash;
- Py_ssize_t ix;
- PyObject *value;
- if (!PyUnicode_CheckExact(key) || (hash = unicode_get_hash(key)) == -1) {
- hash = PyObject_Hash(key);
- if (hash == -1)
- return NULL;
- }
- ix = _Py_dict_lookup(mp, key, hash, &value);
- if (ix == DKIX_ERROR)
- return NULL;
- if (ix == DKIX_EMPTY || value == NULL)
- Py_RETURN_FALSE;
- Py_RETURN_TRUE;
- }
- /*[clinic input]
- dict.get
- key: object
- default: object = None
- /
- Return the value for key if key is in the dictionary, else default.
- [clinic start generated code]*/
- static PyObject *
- dict_get_impl(PyDictObject *self, PyObject *key, PyObject *default_value)
- /*[clinic end generated code: output=bba707729dee05bf input=279ddb5790b6b107]*/
- {
- PyObject *val = NULL;
- Py_hash_t hash;
- Py_ssize_t ix;
- if (!PyUnicode_CheckExact(key) || (hash = unicode_get_hash(key)) == -1) {
- hash = PyObject_Hash(key);
- if (hash == -1)
- return NULL;
- }
- ix = _Py_dict_lookup(self, key, hash, &val);
- if (ix == DKIX_ERROR)
- return NULL;
- if (ix == DKIX_EMPTY || val == NULL) {
- val = default_value;
- }
- return Py_NewRef(val);
- }
- PyObject *
- PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj)
- {
- PyDictObject *mp = (PyDictObject *)d;
- PyObject *value;
- Py_hash_t hash;
- PyInterpreterState *interp = _PyInterpreterState_GET();
- if (!PyDict_Check(d)) {
- PyErr_BadInternalCall();
- return NULL;
- }
- if (!PyUnicode_CheckExact(key) || (hash = unicode_get_hash(key)) == -1) {
- hash = PyObject_Hash(key);
- if (hash == -1)
- return NULL;
- }
- if (mp->ma_keys == Py_EMPTY_KEYS) {
- if (insert_to_emptydict(interp, mp, Py_NewRef(key), hash,
- Py_NewRef(defaultobj)) < 0) {
- return NULL;
- }
- return defaultobj;
- }
- if (!PyUnicode_CheckExact(key) && DK_IS_UNICODE(mp->ma_keys)) {
- if (insertion_resize(interp, mp, 0) < 0) {
- return NULL;
- }
- }
- Py_ssize_t ix = _Py_dict_lookup(mp, key, hash, &value);
- if (ix == DKIX_ERROR)
- return NULL;
- if (ix == DKIX_EMPTY) {
- uint64_t new_version = _PyDict_NotifyEvent(
- interp, PyDict_EVENT_ADDED, mp, key, defaultobj);
- mp->ma_keys->dk_version = 0;
- value = defaultobj;
- if (mp->ma_keys->dk_usable <= 0) {
- if (insertion_resize(interp, mp, 1) < 0) {
- return NULL;
- }
- }
- Py_ssize_t hashpos = find_empty_slot(mp->ma_keys, hash);
- dictkeys_set_index(mp->ma_keys, hashpos, mp->ma_keys->dk_nentries);
- if (DK_IS_UNICODE(mp->ma_keys)) {
- assert(PyUnicode_CheckExact(key));
- PyDictUnicodeEntry *ep = &DK_UNICODE_ENTRIES(mp->ma_keys)[mp->ma_keys->dk_nentries];
- ep->me_key = Py_NewRef(key);
- if (_PyDict_HasSplitTable(mp)) {
- Py_ssize_t index = (int)mp->ma_keys->dk_nentries;
- assert(index < SHARED_KEYS_MAX_SIZE);
- assert(mp->ma_values->values[index] == NULL);
- mp->ma_values->values[index] = Py_NewRef(value);
- _PyDictValues_AddToInsertionOrder(mp->ma_values, index);
- }
- else {
- ep->me_value = Py_NewRef(value);
- }
- }
- else {
- PyDictKeyEntry *ep = &DK_ENTRIES(mp->ma_keys)[mp->ma_keys->dk_nentries];
- ep->me_key = Py_NewRef(key);
- ep->me_hash = hash;
- ep->me_value = Py_NewRef(value);
- }
- MAINTAIN_TRACKING(mp, key, value);
- mp->ma_used++;
- mp->ma_version_tag = new_version;
- mp->ma_keys->dk_usable--;
- mp->ma_keys->dk_nentries++;
- assert(mp->ma_keys->dk_usable >= 0);
- }
- else if (value == NULL) {
- uint64_t new_version = _PyDict_NotifyEvent(
- interp, PyDict_EVENT_ADDED, mp, key, defaultobj);
- value = defaultobj;
- assert(_PyDict_HasSplitTable(mp));
- assert(mp->ma_values->values[ix] == NULL);
- MAINTAIN_TRACKING(mp, key, value);
- mp->ma_values->values[ix] = Py_NewRef(value);
- _PyDictValues_AddToInsertionOrder(mp->ma_values, ix);
- mp->ma_used++;
- mp->ma_version_tag = new_version;
- }
- ASSERT_CONSISTENT(mp);
- return value;
- }
- /*[clinic input]
- dict.setdefault
- key: object
- default: object = None
- /
- Insert key with a value of default if key is not in the dictionary.
- Return the value for key if key is in the dictionary, else default.
- [clinic start generated code]*/
- static PyObject *
- dict_setdefault_impl(PyDictObject *self, PyObject *key,
- PyObject *default_value)
- /*[clinic end generated code: output=f8c1101ebf69e220 input=0f063756e815fd9d]*/
- {
- PyObject *val;
- val = PyDict_SetDefault((PyObject *)self, key, default_value);
- return Py_XNewRef(val);
- }
- static PyObject *
- dict_clear(PyDictObject *mp, PyObject *Py_UNUSED(ignored))
- {
- PyDict_Clear((PyObject *)mp);
- Py_RETURN_NONE;
- }
- /*[clinic input]
- dict.pop
- key: object
- default: object = NULL
- /
- D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
- If the key is not found, return the default if given; otherwise,
- raise a KeyError.
- [clinic start generated code]*/
- static PyObject *
- dict_pop_impl(PyDictObject *self, PyObject *key, PyObject *default_value)
- /*[clinic end generated code: output=3abb47b89f24c21c input=e221baa01044c44c]*/
- {
- return _PyDict_Pop((PyObject*)self, key, default_value);
- }
- /*[clinic input]
- dict.popitem
- Remove and return a (key, value) pair as a 2-tuple.
- Pairs are returned in LIFO (last-in, first-out) order.
- Raises KeyError if the dict is empty.
- [clinic start generated code]*/
- static PyObject *
- dict_popitem_impl(PyDictObject *self)
- /*[clinic end generated code: output=e65fcb04420d230d input=1c38a49f21f64941]*/
- {
- Py_ssize_t i, j;
- PyObject *res;
- uint64_t new_version;
- PyInterpreterState *interp = _PyInterpreterState_GET();
- /* Allocate the result tuple before checking the size. Believe it
- * or not, this allocation could trigger a garbage collection which
- * could empty the dict, so if we checked the size first and that
- * happened, the result would be an infinite loop (searching for an
- * entry that no longer exists). Note that the usual popitem()
- * idiom is "while d: k, v = d.popitem()". so needing to throw the
- * tuple away if the dict *is* empty isn't a significant
- * inefficiency -- possible, but unlikely in practice.
- */
- res = PyTuple_New(2);
- if (res == NULL)
- return NULL;
- if (self->ma_used == 0) {
- Py_DECREF(res);
- PyErr_SetString(PyExc_KeyError, "popitem(): dictionary is empty");
- return NULL;
- }
- /* Convert split table to combined table */
- if (self->ma_keys->dk_kind == DICT_KEYS_SPLIT) {
- if (dictresize(interp, self, DK_LOG_SIZE(self->ma_keys), 1)) {
- Py_DECREF(res);
- return NULL;
- }
- }
- self->ma_keys->dk_version = 0;
- /* Pop last item */
- PyObject *key, *value;
- Py_hash_t hash;
- if (DK_IS_UNICODE(self->ma_keys)) {
- PyDictUnicodeEntry *ep0 = DK_UNICODE_ENTRIES(self->ma_keys);
- i = self->ma_keys->dk_nentries - 1;
- while (i >= 0 && ep0[i].me_value == NULL) {
- i--;
- }
- assert(i >= 0);
- key = ep0[i].me_key;
- new_version = _PyDict_NotifyEvent(
- interp, PyDict_EVENT_DELETED, self, key, NULL);
- hash = unicode_get_hash(key);
- value = ep0[i].me_value;
- ep0[i].me_key = NULL;
- ep0[i].me_value = NULL;
- }
- else {
- PyDictKeyEntry *ep0 = DK_ENTRIES(self->ma_keys);
- i = self->ma_keys->dk_nentries - 1;
- while (i >= 0 && ep0[i].me_value == NULL) {
- i--;
- }
- assert(i >= 0);
- key = ep0[i].me_key;
- new_version = _PyDict_NotifyEvent(
- interp, PyDict_EVENT_DELETED, self, key, NULL);
- hash = ep0[i].me_hash;
- value = ep0[i].me_value;
- ep0[i].me_key = NULL;
- ep0[i].me_hash = -1;
- ep0[i].me_value = NULL;
- }
- j = lookdict_index(self->ma_keys, hash, i);
- assert(j >= 0);
- assert(dictkeys_get_index(self->ma_keys, j) == i);
- dictkeys_set_index(self->ma_keys, j, DKIX_DUMMY);
- PyTuple_SET_ITEM(res, 0, key);
- PyTuple_SET_ITEM(res, 1, value);
- /* We can't dk_usable++ since there is DKIX_DUMMY in indices */
- self->ma_keys->dk_nentries = i;
- self->ma_used--;
- self->ma_version_tag = new_version;
- ASSERT_CONSISTENT(self);
- return res;
- }
- static int
- dict_traverse(PyObject *op, visitproc visit, void *arg)
- {
- PyDictObject *mp = (PyDictObject *)op;
- PyDictKeysObject *keys = mp->ma_keys;
- Py_ssize_t i, n = keys->dk_nentries;
- if (DK_IS_UNICODE(keys)) {
- if (mp->ma_values != NULL) {
- for (i = 0; i < n; i++) {
- Py_VISIT(mp->ma_values->values[i]);
- }
- }
- else {
- PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(keys);
- for (i = 0; i < n; i++) {
- Py_VISIT(entries[i].me_value);
- }
- }
- }
- else {
- PyDictKeyEntry *entries = DK_ENTRIES(keys);
- for (i = 0; i < n; i++) {
- if (entries[i].me_value != NULL) {
- Py_VISIT(entries[i].me_value);
- Py_VISIT(entries[i].me_key);
- }
- }
- }
- return 0;
- }
- static int
- dict_tp_clear(PyObject *op)
- {
- PyDict_Clear(op);
- return 0;
- }
- static PyObject *dictiter_new(PyDictObject *, PyTypeObject *);
- Py_ssize_t
- _PyDict_SizeOf(PyDictObject *mp)
- {
- size_t res = _PyObject_SIZE(Py_TYPE(mp));
- if (mp->ma_values) {
- res += shared_keys_usable_size(mp->ma_keys) * sizeof(PyObject*);
- }
- /* If the dictionary is split, the keys portion is accounted-for
- in the type object. */
- if (mp->ma_keys->dk_refcnt == 1) {
- res += _PyDict_KeysSize(mp->ma_keys);
- }
- assert(res <= (size_t)PY_SSIZE_T_MAX);
- return (Py_ssize_t)res;
- }
- size_t
- _PyDict_KeysSize(PyDictKeysObject *keys)
- {
- size_t es = (keys->dk_kind == DICT_KEYS_GENERAL
- ? sizeof(PyDictKeyEntry) : sizeof(PyDictUnicodeEntry));
- size_t size = sizeof(PyDictKeysObject);
- size += (size_t)1 << keys->dk_log2_index_bytes;
- size += USABLE_FRACTION((size_t)DK_SIZE(keys)) * es;
- return size;
- }
- static PyObject *
- dict_sizeof(PyDictObject *mp, PyObject *Py_UNUSED(ignored))
- {
- return PyLong_FromSsize_t(_PyDict_SizeOf(mp));
- }
- static PyObject *
- dict_or(PyObject *self, PyObject *other)
- {
- if (!PyDict_Check(self) || !PyDict_Check(other)) {
- Py_RETURN_NOTIMPLEMENTED;
- }
- PyObject *new = PyDict_Copy(self);
- if (new == NULL) {
- return NULL;
- }
- if (dict_update_arg(new, other)) {
- Py_DECREF(new);
- return NULL;
- }
- return new;
- }
- static PyObject *
- dict_ior(PyObject *self, PyObject *other)
- {
- if (dict_update_arg(self, other)) {
- return NULL;
- }
- return Py_NewRef(self);
- }
- PyDoc_STRVAR(getitem__doc__,
- "__getitem__($self, key, /)\n--\n\nReturn self[key].");
- PyDoc_STRVAR(sizeof__doc__,
- "D.__sizeof__() -> size of D in memory, in bytes");
- PyDoc_STRVAR(update__doc__,
- "D.update([E, ]**F) -> None. Update D from dict/iterable E and F.\n\
- If E is present and has a .keys() method, then does: for k in E: D[k] = E[k]\n\
- If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = v\n\
- In either case, this is followed by: for k in F: D[k] = F[k]");
- PyDoc_STRVAR(clear__doc__,
- "D.clear() -> None. Remove all items from D.");
- PyDoc_STRVAR(copy__doc__,
- "D.copy() -> a shallow copy of D");
- /* Forward */
- static PyObject *dictkeys_new(PyObject *, PyObject *);
- static PyObject *dictitems_new(PyObject *, PyObject *);
- static PyObject *dictvalues_new(PyObject *, PyObject *);
- PyDoc_STRVAR(keys__doc__,
- "D.keys() -> a set-like object providing a view on D's keys");
- PyDoc_STRVAR(items__doc__,
- "D.items() -> a set-like object providing a view on D's items");
- PyDoc_STRVAR(values__doc__,
- "D.values() -> an object providing a view on D's values");
- static PyMethodDef mapp_methods[] = {
- DICT___CONTAINS___METHODDEF
- {"__getitem__", _PyCFunction_CAST(dict_subscript), METH_O | METH_COEXIST,
- getitem__doc__},
- {"__sizeof__", _PyCFunction_CAST(dict_sizeof), METH_NOARGS,
- sizeof__doc__},
- DICT_GET_METHODDEF
- DICT_SETDEFAULT_METHODDEF
- DICT_POP_METHODDEF
- DICT_POPITEM_METHODDEF
- {"keys", dictkeys_new, METH_NOARGS,
- keys__doc__},
- {"items", dictitems_new, METH_NOARGS,
- items__doc__},
- {"values", dictvalues_new, METH_NOARGS,
- values__doc__},
- {"update", _PyCFunction_CAST(dict_update), METH_VARARGS | METH_KEYWORDS,
- update__doc__},
- DICT_FROMKEYS_METHODDEF
- {"clear", (PyCFunction)dict_clear, METH_NOARGS,
- clear__doc__},
- {"copy", (PyCFunction)dict_copy, METH_NOARGS,
- copy__doc__},
- DICT___REVERSED___METHODDEF
- {"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")},
- {NULL, NULL} /* sentinel */
- };
- /* Return 1 if `key` is in dict `op`, 0 if not, and -1 on error. */
- int
- PyDict_Contains(PyObject *op, PyObject *key)
- {
- Py_hash_t hash;
- Py_ssize_t ix;
- PyDictObject *mp = (PyDictObject *)op;
- PyObject *value;
- if (!PyUnicode_CheckExact(key) || (hash = unicode_get_hash(key)) == -1) {
- hash = PyObject_Hash(key);
- if (hash == -1)
- return -1;
- }
- ix = _Py_dict_lookup(mp, key, hash, &value);
- if (ix == DKIX_ERROR)
- return -1;
- return (ix != DKIX_EMPTY && value != NULL);
- }
- /* Internal version of PyDict_Contains used when the hash value is already known */
- int
- _PyDict_Contains_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash)
- {
- PyDictObject *mp = (PyDictObject *)op;
- PyObject *value;
- Py_ssize_t ix;
- ix = _Py_dict_lookup(mp, key, hash, &value);
- if (ix == DKIX_ERROR)
- return -1;
- return (ix != DKIX_EMPTY && value != NULL);
- }
- int
- _PyDict_ContainsId(PyObject *op, _Py_Identifier *key)
- {
- PyObject *kv = _PyUnicode_FromId(key); /* borrowed */
- if (kv == NULL) {
- return -1;
- }
- return PyDict_Contains(op, kv);
- }
- /* Hack to implement "key in dict" */
- static PySequenceMethods dict_as_sequence = {
- 0, /* sq_length */
- 0, /* sq_concat */
- 0, /* sq_repeat */
- 0, /* sq_item */
- 0, /* sq_slice */
- 0, /* sq_ass_item */
- 0, /* sq_ass_slice */
- PyDict_Contains, /* sq_contains */
- 0, /* sq_inplace_concat */
- 0, /* sq_inplace_repeat */
- };
- static PyNumberMethods dict_as_number = {
- .nb_or = dict_or,
- .nb_inplace_or = dict_ior,
- };
- static PyObject *
- dict_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
- {
- assert(type != NULL);
- assert(type->tp_alloc != NULL);
- // dict subclasses must implement the GC protocol
- assert(_PyType_IS_GC(type));
- PyObject *self = type->tp_alloc(type, 0);
- if (self == NULL) {
- return NULL;
- }
- PyDictObject *d = (PyDictObject *)self;
- d->ma_used = 0;
- d->ma_version_tag = DICT_NEXT_VERSION(
- _PyInterpreterState_GET());
- dictkeys_incref(Py_EMPTY_KEYS);
- d->ma_keys = Py_EMPTY_KEYS;
- d->ma_values = NULL;
- ASSERT_CONSISTENT(d);
- if (type != &PyDict_Type) {
- // Don't track if a subclass tp_alloc is PyType_GenericAlloc()
- if (!_PyObject_GC_IS_TRACKED(d)) {
- _PyObject_GC_TRACK(d);
- }
- }
- else {
- // _PyType_AllocNoTrack() does not track the created object
- assert(!_PyObject_GC_IS_TRACKED(d));
- }
- return self;
- }
- static int
- dict_init(PyObject *self, PyObject *args, PyObject *kwds)
- {
- return dict_update_common(self, args, kwds, "dict");
- }
- static PyObject *
- dict_vectorcall(PyObject *type, PyObject * const*args,
- size_t nargsf, PyObject *kwnames)
- {
- Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
- if (!_PyArg_CheckPositional("dict", nargs, 0, 1)) {
- return NULL;
- }
- PyObject *self = dict_new(_PyType_CAST(type), NULL, NULL);
- if (self == NULL) {
- return NULL;
- }
- if (nargs == 1) {
- if (dict_update_arg(self, args[0]) < 0) {
- Py_DECREF(self);
- return NULL;
- }
- args++;
- }
- if (kwnames != NULL) {
- for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(kwnames); i++) {
- if (PyDict_SetItem(self, PyTuple_GET_ITEM(kwnames, i), args[i]) < 0) {
- Py_DECREF(self);
- return NULL;
- }
- }
- }
- return self;
- }
- static PyObject *
- dict_iter(PyDictObject *dict)
- {
- return dictiter_new(dict, &PyDictIterKey_Type);
- }
- PyDoc_STRVAR(dictionary_doc,
- "dict() -> new empty dictionary\n"
- "dict(mapping) -> new dictionary initialized from a mapping object's\n"
- " (key, value) pairs\n"
- "dict(iterable) -> new dictionary initialized as if via:\n"
- " d = {}\n"
- " for k, v in iterable:\n"
- " d[k] = v\n"
- "dict(**kwargs) -> new dictionary initialized with the name=value pairs\n"
- " in the keyword argument list. For example: dict(one=1, two=2)");
- PyTypeObject PyDict_Type = {
- PyVarObject_HEAD_INIT(&PyType_Type, 0)
- "dict",
- sizeof(PyDictObject),
- 0,
- (destructor)dict_dealloc, /* tp_dealloc */
- 0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_as_async */
- (reprfunc)dict_repr, /* tp_repr */
- &dict_as_number, /* tp_as_number */
- &dict_as_sequence, /* tp_as_sequence */
- &dict_as_mapping, /* tp_as_mapping */
- PyObject_HashNotImplemented, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- PyObject_GenericGetAttr, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
- Py_TPFLAGS_BASETYPE | Py_TPFLAGS_DICT_SUBCLASS |
- _Py_TPFLAGS_MATCH_SELF | Py_TPFLAGS_MAPPING, /* tp_flags */
- dictionary_doc, /* tp_doc */
- dict_traverse, /* tp_traverse */
- dict_tp_clear, /* tp_clear */
- dict_richcompare, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- (getiterfunc)dict_iter, /* tp_iter */
- 0, /* tp_iternext */
- mapp_methods, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- dict_init, /* tp_init */
- _PyType_AllocNoTrack, /* tp_alloc */
- dict_new, /* tp_new */
- PyObject_GC_Del, /* tp_free */
- .tp_vectorcall = dict_vectorcall,
- };
- /* For backward compatibility with old dictionary interface */
- PyObject *
- PyDict_GetItemString(PyObject *v, const char *key)
- {
- PyObject *kv, *rv;
- kv = PyUnicode_FromString(key);
- if (kv == NULL) {
- PyErr_Clear();
- return NULL;
- }
- rv = PyDict_GetItem(v, kv);
- Py_DECREF(kv);
- return rv;
- }
- int
- _PyDict_SetItemId(PyObject *v, _Py_Identifier *key, PyObject *item)
- {
- PyObject *kv;
- kv = _PyUnicode_FromId(key); /* borrowed */
- if (kv == NULL)
- return -1;
- return PyDict_SetItem(v, kv, item);
- }
- int
- PyDict_SetItemString(PyObject *v, const char *key, PyObject *item)
- {
- PyObject *kv;
- int err;
- kv = PyUnicode_FromString(key);
- if (kv == NULL)
- return -1;
- PyUnicode_InternInPlace(&kv); /* XXX Should we really? */
- err = PyDict_SetItem(v, kv, item);
- Py_DECREF(kv);
- return err;
- }
- int
- _PyDict_DelItemId(PyObject *v, _Py_Identifier *key)
- {
- PyObject *kv = _PyUnicode_FromId(key); /* borrowed */
- if (kv == NULL)
- return -1;
- return PyDict_DelItem(v, kv);
- }
- int
- PyDict_DelItemString(PyObject *v, const char *key)
- {
- PyObject *kv;
- int err;
- kv = PyUnicode_FromString(key);
- if (kv == NULL)
- return -1;
- err = PyDict_DelItem(v, kv);
- Py_DECREF(kv);
- return err;
- }
- /* Dictionary iterator types */
- typedef struct {
- PyObject_HEAD
- PyDictObject *di_dict; /* Set to NULL when iterator is exhausted */
- Py_ssize_t di_used;
- Py_ssize_t di_pos;
- PyObject* di_result; /* reusable result tuple for iteritems */
- Py_ssize_t len;
- } dictiterobject;
- static PyObject *
- dictiter_new(PyDictObject *dict, PyTypeObject *itertype)
- {
- dictiterobject *di;
- di = PyObject_GC_New(dictiterobject, itertype);
- if (di == NULL) {
- return NULL;
- }
- di->di_dict = (PyDictObject*)Py_NewRef(dict);
- di->di_used = dict->ma_used;
- di->len = dict->ma_used;
- if (itertype == &PyDictRevIterKey_Type ||
- itertype == &PyDictRevIterItem_Type ||
- itertype == &PyDictRevIterValue_Type) {
- if (dict->ma_values) {
- di->di_pos = dict->ma_used - 1;
- }
- else {
- di->di_pos = dict->ma_keys->dk_nentries - 1;
- }
- }
- else {
- di->di_pos = 0;
- }
- if (itertype == &PyDictIterItem_Type ||
- itertype == &PyDictRevIterItem_Type) {
- di->di_result = PyTuple_Pack(2, Py_None, Py_None);
- if (di->di_result == NULL) {
- Py_DECREF(di);
- return NULL;
- }
- }
- else {
- di->di_result = NULL;
- }
- _PyObject_GC_TRACK(di);
- return (PyObject *)di;
- }
- static void
- dictiter_dealloc(dictiterobject *di)
- {
- /* bpo-31095: UnTrack is needed before calling any callbacks */
- _PyObject_GC_UNTRACK(di);
- Py_XDECREF(di->di_dict);
- Py_XDECREF(di->di_result);
- PyObject_GC_Del(di);
- }
- static int
- dictiter_traverse(dictiterobject *di, visitproc visit, void *arg)
- {
- Py_VISIT(di->di_dict);
- Py_VISIT(di->di_result);
- return 0;
- }
- static PyObject *
- dictiter_len(dictiterobject *di, PyObject *Py_UNUSED(ignored))
- {
- Py_ssize_t len = 0;
- if (di->di_dict != NULL && di->di_used == di->di_dict->ma_used)
- len = di->len;
- return PyLong_FromSize_t(len);
- }
- PyDoc_STRVAR(length_hint_doc,
- "Private method returning an estimate of len(list(it)).");
- static PyObject *
- dictiter_reduce(dictiterobject *di, PyObject *Py_UNUSED(ignored));
- PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
- static PyMethodDef dictiter_methods[] = {
- {"__length_hint__", _PyCFunction_CAST(dictiter_len), METH_NOARGS,
- length_hint_doc},
- {"__reduce__", _PyCFunction_CAST(dictiter_reduce), METH_NOARGS,
- reduce_doc},
- {NULL, NULL} /* sentinel */
- };
- static PyObject*
- dictiter_iternextkey(dictiterobject *di)
- {
- PyObject *key;
- Py_ssize_t i;
- PyDictKeysObject *k;
- PyDictObject *d = di->di_dict;
- if (d == NULL)
- return NULL;
- assert (PyDict_Check(d));
- if (di->di_used != d->ma_used) {
- PyErr_SetString(PyExc_RuntimeError,
- "dictionary changed size during iteration");
- di->di_used = -1; /* Make this state sticky */
- return NULL;
- }
- i = di->di_pos;
- k = d->ma_keys;
- assert(i >= 0);
- if (d->ma_values) {
- if (i >= d->ma_used)
- goto fail;
- int index = get_index_from_order(d, i);
- key = DK_UNICODE_ENTRIES(k)[index].me_key;
- assert(d->ma_values->values[index] != NULL);
- }
- else {
- Py_ssize_t n = k->dk_nentries;
- if (DK_IS_UNICODE(k)) {
- PyDictUnicodeEntry *entry_ptr = &DK_UNICODE_ENTRIES(k)[i];
- while (i < n && entry_ptr->me_value == NULL) {
- entry_ptr++;
- i++;
- }
- if (i >= n)
- goto fail;
- key = entry_ptr->me_key;
- }
- else {
- PyDictKeyEntry *entry_ptr = &DK_ENTRIES(k)[i];
- while (i < n && entry_ptr->me_value == NULL) {
- entry_ptr++;
- i++;
- }
- if (i >= n)
- goto fail;
- key = entry_ptr->me_key;
- }
- }
- // We found an element (key), but did not expect it
- if (di->len == 0) {
- PyErr_SetString(PyExc_RuntimeError,
- "dictionary keys changed during iteration");
- goto fail;
- }
- di->di_pos = i+1;
- di->len--;
- return Py_NewRef(key);
- fail:
- di->di_dict = NULL;
- Py_DECREF(d);
- return NULL;
- }
- PyTypeObject PyDictIterKey_Type = {
- PyVarObject_HEAD_INIT(&PyType_Type, 0)
- "dict_keyiterator", /* tp_name */
- sizeof(dictiterobject), /* tp_basicsize */
- 0, /* tp_itemsize */
- /* methods */
- (destructor)dictiter_dealloc, /* tp_dealloc */
- 0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_as_async */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- PyObject_GenericGetAttr, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
- 0, /* tp_doc */
- (traverseproc)dictiter_traverse, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- PyObject_SelfIter, /* tp_iter */
- (iternextfunc)dictiter_iternextkey, /* tp_iternext */
- dictiter_methods, /* tp_methods */
- 0,
- };
- static PyObject *
- dictiter_iternextvalue(dictiterobject *di)
- {
- PyObject *value;
- Py_ssize_t i;
- PyDictObject *d = di->di_dict;
- if (d == NULL)
- return NULL;
- assert (PyDict_Check(d));
- if (di->di_used != d->ma_used) {
- PyErr_SetString(PyExc_RuntimeError,
- "dictionary changed size during iteration");
- di->di_used = -1; /* Make this state sticky */
- return NULL;
- }
- i = di->di_pos;
- assert(i >= 0);
- if (d->ma_values) {
- if (i >= d->ma_used)
- goto fail;
- int index = get_index_from_order(d, i);
- value = d->ma_values->values[index];
- assert(value != NULL);
- }
- else {
- Py_ssize_t n = d->ma_keys->dk_nentries;
- if (DK_IS_UNICODE(d->ma_keys)) {
- PyDictUnicodeEntry *entry_ptr = &DK_UNICODE_ENTRIES(d->ma_keys)[i];
- while (i < n && entry_ptr->me_value == NULL) {
- entry_ptr++;
- i++;
- }
- if (i >= n)
- goto fail;
- value = entry_ptr->me_value;
- }
- else {
- PyDictKeyEntry *entry_ptr = &DK_ENTRIES(d->ma_keys)[i];
- while (i < n && entry_ptr->me_value == NULL) {
- entry_ptr++;
- i++;
- }
- if (i >= n)
- goto fail;
- value = entry_ptr->me_value;
- }
- }
- // We found an element, but did not expect it
- if (di->len == 0) {
- PyErr_SetString(PyExc_RuntimeError,
- "dictionary keys changed during iteration");
- goto fail;
- }
- di->di_pos = i+1;
- di->len--;
- return Py_NewRef(value);
- fail:
- di->di_dict = NULL;
- Py_DECREF(d);
- return NULL;
- }
- PyTypeObject PyDictIterValue_Type = {
- PyVarObject_HEAD_INIT(&PyType_Type, 0)
- "dict_valueiterator", /* tp_name */
- sizeof(dictiterobject), /* tp_basicsize */
- 0, /* tp_itemsize */
- /* methods */
- (destructor)dictiter_dealloc, /* tp_dealloc */
- 0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_as_async */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- PyObject_GenericGetAttr, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
- 0, /* tp_doc */
- (traverseproc)dictiter_traverse, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- PyObject_SelfIter, /* tp_iter */
- (iternextfunc)dictiter_iternextvalue, /* tp_iternext */
- dictiter_methods, /* tp_methods */
- 0,
- };
- static PyObject *
- dictiter_iternextitem(dictiterobject *di)
- {
- PyObject *key, *value, *result;
- Py_ssize_t i;
- PyDictObject *d = di->di_dict;
- if (d == NULL)
- return NULL;
- assert (PyDict_Check(d));
- if (di->di_used != d->ma_used) {
- PyErr_SetString(PyExc_RuntimeError,
- "dictionary changed size during iteration");
- di->di_used = -1; /* Make this state sticky */
- return NULL;
- }
- i = di->di_pos;
- assert(i >= 0);
- if (d->ma_values) {
- if (i >= d->ma_used)
- goto fail;
- int index = get_index_from_order(d, i);
- key = DK_UNICODE_ENTRIES(d->ma_keys)[index].me_key;
- value = d->ma_values->values[index];
- assert(value != NULL);
- }
- else {
- Py_ssize_t n = d->ma_keys->dk_nentries;
- if (DK_IS_UNICODE(d->ma_keys)) {
- PyDictUnicodeEntry *entry_ptr = &DK_UNICODE_ENTRIES(d->ma_keys)[i];
- while (i < n && entry_ptr->me_value == NULL) {
- entry_ptr++;
- i++;
- }
- if (i >= n)
- goto fail;
- key = entry_ptr->me_key;
- value = entry_ptr->me_value;
- }
- else {
- PyDictKeyEntry *entry_ptr = &DK_ENTRIES(d->ma_keys)[i];
- while (i < n && entry_ptr->me_value == NULL) {
- entry_ptr++;
- i++;
- }
- if (i >= n)
- goto fail;
- key = entry_ptr->me_key;
- value = entry_ptr->me_value;
- }
- }
- // We found an element, but did not expect it
- if (di->len == 0) {
- PyErr_SetString(PyExc_RuntimeError,
- "dictionary keys changed during iteration");
- goto fail;
- }
- di->di_pos = i+1;
- di->len--;
- result = di->di_result;
- if (Py_REFCNT(result) == 1) {
- PyObject *oldkey = PyTuple_GET_ITEM(result, 0);
- PyObject *oldvalue = PyTuple_GET_ITEM(result, 1);
- PyTuple_SET_ITEM(result, 0, Py_NewRef(key));
- PyTuple_SET_ITEM(result, 1, Py_NewRef(value));
- Py_INCREF(result);
- Py_DECREF(oldkey);
- Py_DECREF(oldvalue);
- // bpo-42536: The GC may have untracked this result tuple. Since we're
- // recycling it, make sure it's tracked again:
- if (!_PyObject_GC_IS_TRACKED(result)) {
- _PyObject_GC_TRACK(result);
- }
- }
- else {
- result = PyTuple_New(2);
- if (result == NULL)
- return NULL;
- PyTuple_SET_ITEM(result, 0, Py_NewRef(key));
- PyTuple_SET_ITEM(result, 1, Py_NewRef(value));
- }
- return result;
- fail:
- di->di_dict = NULL;
- Py_DECREF(d);
- return NULL;
- }
- PyTypeObject PyDictIterItem_Type = {
- PyVarObject_HEAD_INIT(&PyType_Type, 0)
- "dict_itemiterator", /* tp_name */
- sizeof(dictiterobject), /* tp_basicsize */
- 0, /* tp_itemsize */
- /* methods */
- (destructor)dictiter_dealloc, /* tp_dealloc */
- 0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_as_async */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- PyObject_GenericGetAttr, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
- 0, /* tp_doc */
- (traverseproc)dictiter_traverse, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- PyObject_SelfIter, /* tp_iter */
- (iternextfunc)dictiter_iternextitem, /* tp_iternext */
- dictiter_methods, /* tp_methods */
- 0,
- };
- /* dictreviter */
- static PyObject *
- dictreviter_iternext(dictiterobject *di)
- {
- PyDictObject *d = di->di_dict;
- if (d == NULL) {
- return NULL;
- }
- assert (PyDict_Check(d));
- if (di->di_used != d->ma_used) {
- PyErr_SetString(PyExc_RuntimeError,
- "dictionary changed size during iteration");
- di->di_used = -1; /* Make this state sticky */
- return NULL;
- }
- Py_ssize_t i = di->di_pos;
- PyDictKeysObject *k = d->ma_keys;
- PyObject *key, *value, *result;
- if (i < 0) {
- goto fail;
- }
- if (d->ma_values) {
- int index = get_index_from_order(d, i);
- key = DK_UNICODE_ENTRIES(k)[index].me_key;
- value = d->ma_values->values[index];
- assert (value != NULL);
- }
- else {
- if (DK_IS_UNICODE(k)) {
- PyDictUnicodeEntry *entry_ptr = &DK_UNICODE_ENTRIES(k)[i];
- while (entry_ptr->me_value == NULL) {
- if (--i < 0) {
- goto fail;
- }
- entry_ptr--;
- }
- key = entry_ptr->me_key;
- value = entry_ptr->me_value;
- }
- else {
- PyDictKeyEntry *entry_ptr = &DK_ENTRIES(k)[i];
- while (entry_ptr->me_value == NULL) {
- if (--i < 0) {
- goto fail;
- }
- entry_ptr--;
- }
- key = entry_ptr->me_key;
- value = entry_ptr->me_value;
- }
- }
- di->di_pos = i-1;
- di->len--;
- if (Py_IS_TYPE(di, &PyDictRevIterKey_Type)) {
- return Py_NewRef(key);
- }
- else if (Py_IS_TYPE(di, &PyDictRevIterValue_Type)) {
- return Py_NewRef(value);
- }
- else if (Py_IS_TYPE(di, &PyDictRevIterItem_Type)) {
- result = di->di_result;
- if (Py_REFCNT(result) == 1) {
- PyObject *oldkey = PyTuple_GET_ITEM(result, 0);
- PyObject *oldvalue = PyTuple_GET_ITEM(result, 1);
- PyTuple_SET_ITEM(result, 0, Py_NewRef(key));
- PyTuple_SET_ITEM(result, 1, Py_NewRef(value));
- Py_INCREF(result);
- Py_DECREF(oldkey);
- Py_DECREF(oldvalue);
- // bpo-42536: The GC may have untracked this result tuple. Since
- // we're recycling it, make sure it's tracked again:
- if (!_PyObject_GC_IS_TRACKED(result)) {
- _PyObject_GC_TRACK(result);
- }
- }
- else {
- result = PyTuple_New(2);
- if (result == NULL) {
- return NULL;
- }
- PyTuple_SET_ITEM(result, 0, Py_NewRef(key));
- PyTuple_SET_ITEM(result, 1, Py_NewRef(value));
- }
- return result;
- }
- else {
- Py_UNREACHABLE();
- }
- fail:
- di->di_dict = NULL;
- Py_DECREF(d);
- return NULL;
- }
- PyTypeObject PyDictRevIterKey_Type = {
- PyVarObject_HEAD_INIT(&PyType_Type, 0)
- "dict_reversekeyiterator",
- sizeof(dictiterobject),
- .tp_dealloc = (destructor)dictiter_dealloc,
- .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
- .tp_traverse = (traverseproc)dictiter_traverse,
- .tp_iter = PyObject_SelfIter,
- .tp_iternext = (iternextfunc)dictreviter_iternext,
- .tp_methods = dictiter_methods
- };
- /*[clinic input]
- dict.__reversed__
- Return a reverse iterator over the dict keys.
- [clinic start generated code]*/
- static PyObject *
- dict___reversed___impl(PyDictObject *self)
- /*[clinic end generated code: output=e674483336d1ed51 input=23210ef3477d8c4d]*/
- {
- assert (PyDict_Check(self));
- return dictiter_new(self, &PyDictRevIterKey_Type);
- }
- static PyObject *
- dictiter_reduce(dictiterobject *di, PyObject *Py_UNUSED(ignored))
- {
- /* copy the iterator state */
- dictiterobject tmp = *di;
- Py_XINCREF(tmp.di_dict);
- PyObject *list = PySequence_List((PyObject*)&tmp);
- Py_XDECREF(tmp.di_dict);
- if (list == NULL) {
- return NULL;
- }
- return Py_BuildValue("N(N)", _PyEval_GetBuiltin(&_Py_ID(iter)), list);
- }
- PyTypeObject PyDictRevIterItem_Type = {
- PyVarObject_HEAD_INIT(&PyType_Type, 0)
- "dict_reverseitemiterator",
- sizeof(dictiterobject),
- .tp_dealloc = (destructor)dictiter_dealloc,
- .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
- .tp_traverse = (traverseproc)dictiter_traverse,
- .tp_iter = PyObject_SelfIter,
- .tp_iternext = (iternextfunc)dictreviter_iternext,
- .tp_methods = dictiter_methods
- };
- PyTypeObject PyDictRevIterValue_Type = {
- PyVarObject_HEAD_INIT(&PyType_Type, 0)
- "dict_reversevalueiterator",
- sizeof(dictiterobject),
- .tp_dealloc = (destructor)dictiter_dealloc,
- .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
- .tp_traverse = (traverseproc)dictiter_traverse,
- .tp_iter = PyObject_SelfIter,
- .tp_iternext = (iternextfunc)dictreviter_iternext,
- .tp_methods = dictiter_methods
- };
- /***********************************************/
- /* View objects for keys(), items(), values(). */
- /***********************************************/
- /* The instance lay-out is the same for all three; but the type differs. */
- static void
- dictview_dealloc(_PyDictViewObject *dv)
- {
- /* bpo-31095: UnTrack is needed before calling any callbacks */
- _PyObject_GC_UNTRACK(dv);
- Py_XDECREF(dv->dv_dict);
- PyObject_GC_Del(dv);
- }
- static int
- dictview_traverse(_PyDictViewObject *dv, visitproc visit, void *arg)
- {
- Py_VISIT(dv->dv_dict);
- return 0;
- }
- static Py_ssize_t
- dictview_len(_PyDictViewObject *dv)
- {
- Py_ssize_t len = 0;
- if (dv->dv_dict != NULL)
- len = dv->dv_dict->ma_used;
- return len;
- }
- PyObject *
- _PyDictView_New(PyObject *dict, PyTypeObject *type)
- {
- _PyDictViewObject *dv;
- if (dict == NULL) {
- PyErr_BadInternalCall();
- return NULL;
- }
- if (!PyDict_Check(dict)) {
- /* XXX Get rid of this restriction later */
- PyErr_Format(PyExc_TypeError,
- "%s() requires a dict argument, not '%s'",
- type->tp_name, Py_TYPE(dict)->tp_name);
- return NULL;
- }
- dv = PyObject_GC_New(_PyDictViewObject, type);
- if (dv == NULL)
- return NULL;
- dv->dv_dict = (PyDictObject *)Py_NewRef(dict);
- _PyObject_GC_TRACK(dv);
- return (PyObject *)dv;
- }
- static PyObject *
- dictview_mapping(PyObject *view, void *Py_UNUSED(ignored)) {
- assert(view != NULL);
- assert(PyDictKeys_Check(view)
- || PyDictValues_Check(view)
- || PyDictItems_Check(view));
- PyObject *mapping = (PyObject *)((_PyDictViewObject *)view)->dv_dict;
- return PyDictProxy_New(mapping);
- }
- static PyGetSetDef dictview_getset[] = {
- {"mapping", dictview_mapping, (setter)NULL,
- "dictionary that this view refers to", NULL},
- {0}
- };
- /* TODO(guido): The views objects are not complete:
- * support more set operations
- * support arbitrary mappings?
- - either these should be static or exported in dictobject.h
- - if public then they should probably be in builtins
- */
- /* Return 1 if self is a subset of other, iterating over self;
- 0 if not; -1 if an error occurred. */
- static int
- all_contained_in(PyObject *self, PyObject *other)
- {
- PyObject *iter = PyObject_GetIter(self);
- int ok = 1;
- if (iter == NULL)
- return -1;
- for (;;) {
- PyObject *next = PyIter_Next(iter);
- if (next == NULL) {
- if (PyErr_Occurred())
- ok = -1;
- break;
- }
- ok = PySequence_Contains(other, next);
- Py_DECREF(next);
- if (ok <= 0)
- break;
- }
- Py_DECREF(iter);
- return ok;
- }
- static PyObject *
- dictview_richcompare(PyObject *self, PyObject *other, int op)
- {
- Py_ssize_t len_self, len_other;
- int ok;
- PyObject *result;
- assert(self != NULL);
- assert(PyDictViewSet_Check(self));
- assert(other != NULL);
- if (!PyAnySet_Check(other) && !PyDictViewSet_Check(other))
- Py_RETURN_NOTIMPLEMENTED;
- len_self = PyObject_Size(self);
- if (len_self < 0)
- return NULL;
- len_other = PyObject_Size(other);
- if (len_other < 0)
- return NULL;
- ok = 0;
- switch(op) {
- case Py_NE:
- case Py_EQ:
- if (len_self == len_other)
- ok = all_contained_in(self, other);
- if (op == Py_NE && ok >= 0)
- ok = !ok;
- break;
- case Py_LT:
- if (len_self < len_other)
- ok = all_contained_in(self, other);
- break;
- case Py_LE:
- if (len_self <= len_other)
- ok = all_contained_in(self, other);
- break;
- case Py_GT:
- if (len_self > len_other)
- ok = all_contained_in(other, self);
- break;
- case Py_GE:
- if (len_self >= len_other)
- ok = all_contained_in(other, self);
- break;
- }
- if (ok < 0)
- return NULL;
- result = ok ? Py_True : Py_False;
- return Py_NewRef(result);
- }
- static PyObject *
- dictview_repr(_PyDictViewObject *dv)
- {
- PyObject *seq;
- PyObject *result = NULL;
- Py_ssize_t rc;
- rc = Py_ReprEnter((PyObject *)dv);
- if (rc != 0) {
- return rc > 0 ? PyUnicode_FromString("...") : NULL;
- }
- seq = PySequence_List((PyObject *)dv);
- if (seq == NULL) {
- goto Done;
- }
- result = PyUnicode_FromFormat("%s(%R)", Py_TYPE(dv)->tp_name, seq);
- Py_DECREF(seq);
- Done:
- Py_ReprLeave((PyObject *)dv);
- return result;
- }
- /*** dict_keys ***/
- static PyObject *
- dictkeys_iter(_PyDictViewObject *dv)
- {
- if (dv->dv_dict == NULL) {
- Py_RETURN_NONE;
- }
- return dictiter_new(dv->dv_dict, &PyDictIterKey_Type);
- }
- static int
- dictkeys_contains(_PyDictViewObject *dv, PyObject *obj)
- {
- if (dv->dv_dict == NULL)
- return 0;
- return PyDict_Contains((PyObject *)dv->dv_dict, obj);
- }
- static PySequenceMethods dictkeys_as_sequence = {
- (lenfunc)dictview_len, /* sq_length */
- 0, /* sq_concat */
- 0, /* sq_repeat */
- 0, /* sq_item */
- 0, /* sq_slice */
- 0, /* sq_ass_item */
- 0, /* sq_ass_slice */
- (objobjproc)dictkeys_contains, /* sq_contains */
- };
- // Create a set object from dictviews object.
- // Returns a new reference.
- // This utility function is used by set operations.
- static PyObject*
- dictviews_to_set(PyObject *self)
- {
- PyObject *left = self;
- if (PyDictKeys_Check(self)) {
- // PySet_New() has fast path for the dict object.
- PyObject *dict = (PyObject *)((_PyDictViewObject *)self)->dv_dict;
- if (PyDict_CheckExact(dict)) {
- left = dict;
- }
- }
- return PySet_New(left);
- }
- static PyObject*
- dictviews_sub(PyObject *self, PyObject *other)
- {
- PyObject *result = dictviews_to_set(self);
- if (result == NULL) {
- return NULL;
- }
- PyObject *tmp = PyObject_CallMethodOneArg(
- result, &_Py_ID(difference_update), other);
- if (tmp == NULL) {
- Py_DECREF(result);
- return NULL;
- }
- Py_DECREF(tmp);
- return result;
- }
- static int
- dictitems_contains(_PyDictViewObject *dv, PyObject *obj);
- PyObject *
- _PyDictView_Intersect(PyObject* self, PyObject *other)
- {
- PyObject *result;
- PyObject *it;
- PyObject *key;
- Py_ssize_t len_self;
- int rv;
- int (*dict_contains)(_PyDictViewObject *, PyObject *);
- /* Python interpreter swaps parameters when dict view
- is on right side of & */
- if (!PyDictViewSet_Check(self)) {
- PyObject *tmp = other;
- other = self;
- self = tmp;
- }
- len_self = dictview_len((_PyDictViewObject *)self);
- /* if other is a set and self is smaller than other,
- reuse set intersection logic */
- if (PySet_CheckExact(other) && len_self <= PyObject_Size(other)) {
- return PyObject_CallMethodObjArgs(
- other, &_Py_ID(intersection), self, NULL);
- }
- /* if other is another dict view, and it is bigger than self,
- swap them */
- if (PyDictViewSet_Check(other)) {
- Py_ssize_t len_other = dictview_len((_PyDictViewObject *)other);
- if (len_other > len_self) {
- PyObject *tmp = other;
- other = self;
- self = tmp;
- }
- }
- /* at this point, two things should be true
- 1. self is a dictview
- 2. if other is a dictview then it is smaller than self */
- result = PySet_New(NULL);
- if (result == NULL)
- return NULL;
- it = PyObject_GetIter(other);
- if (it == NULL) {
- Py_DECREF(result);
- return NULL;
- }
- if (PyDictKeys_Check(self)) {
- dict_contains = dictkeys_contains;
- }
- /* else PyDictItems_Check(self) */
- else {
- dict_contains = dictitems_contains;
- }
- while ((key = PyIter_Next(it)) != NULL) {
- rv = dict_contains((_PyDictViewObject *)self, key);
- if (rv < 0) {
- goto error;
- }
- if (rv) {
- if (PySet_Add(result, key)) {
- goto error;
- }
- }
- Py_DECREF(key);
- }
- Py_DECREF(it);
- if (PyErr_Occurred()) {
- Py_DECREF(result);
- return NULL;
- }
- return result;
- error:
- Py_DECREF(it);
- Py_DECREF(result);
- Py_DECREF(key);
- return NULL;
- }
- static PyObject*
- dictviews_or(PyObject* self, PyObject *other)
- {
- PyObject *result = dictviews_to_set(self);
- if (result == NULL) {
- return NULL;
- }
- if (_PySet_Update(result, other) < 0) {
- Py_DECREF(result);
- return NULL;
- }
- return result;
- }
- static PyObject *
- dictitems_xor(PyObject *self, PyObject *other)
- {
- assert(PyDictItems_Check(self));
- assert(PyDictItems_Check(other));
- PyObject *d1 = (PyObject *)((_PyDictViewObject *)self)->dv_dict;
- PyObject *d2 = (PyObject *)((_PyDictViewObject *)other)->dv_dict;
- PyObject *temp_dict = PyDict_Copy(d1);
- if (temp_dict == NULL) {
- return NULL;
- }
- PyObject *result_set = PySet_New(NULL);
- if (result_set == NULL) {
- Py_CLEAR(temp_dict);
- return NULL;
- }
- PyObject *key = NULL, *val1 = NULL, *val2 = NULL;
- Py_ssize_t pos = 0;
- Py_hash_t hash;
- while (_PyDict_Next(d2, &pos, &key, &val2, &hash)) {
- Py_INCREF(key);
- Py_INCREF(val2);
- val1 = _PyDict_GetItem_KnownHash(temp_dict, key, hash);
- int to_delete;
- if (val1 == NULL) {
- if (PyErr_Occurred()) {
- goto error;
- }
- to_delete = 0;
- }
- else {
- Py_INCREF(val1);
- to_delete = PyObject_RichCompareBool(val1, val2, Py_EQ);
- if (to_delete < 0) {
- goto error;
- }
- }
- if (to_delete) {
- if (_PyDict_DelItem_KnownHash(temp_dict, key, hash) < 0) {
- goto error;
- }
- }
- else {
- PyObject *pair = PyTuple_Pack(2, key, val2);
- if (pair == NULL) {
- goto error;
- }
- if (PySet_Add(result_set, pair) < 0) {
- Py_DECREF(pair);
- goto error;
- }
- Py_DECREF(pair);
- }
- Py_DECREF(key);
- Py_XDECREF(val1);
- Py_DECREF(val2);
- }
- key = val1 = val2 = NULL;
- PyObject *remaining_pairs = PyObject_CallMethodNoArgs(
- temp_dict, &_Py_ID(items));
- if (remaining_pairs == NULL) {
- goto error;
- }
- if (_PySet_Update(result_set, remaining_pairs) < 0) {
- Py_DECREF(remaining_pairs);
- goto error;
- }
- Py_DECREF(temp_dict);
- Py_DECREF(remaining_pairs);
- return result_set;
- error:
- Py_XDECREF(temp_dict);
- Py_XDECREF(result_set);
- Py_XDECREF(key);
- Py_XDECREF(val1);
- Py_XDECREF(val2);
- return NULL;
- }
- static PyObject*
- dictviews_xor(PyObject* self, PyObject *other)
- {
- if (PyDictItems_Check(self) && PyDictItems_Check(other)) {
- return dictitems_xor(self, other);
- }
- PyObject *result = dictviews_to_set(self);
- if (result == NULL) {
- return NULL;
- }
- PyObject *tmp = PyObject_CallMethodOneArg(
- result, &_Py_ID(symmetric_difference_update), other);
- if (tmp == NULL) {
- Py_DECREF(result);
- return NULL;
- }
- Py_DECREF(tmp);
- return result;
- }
- static PyNumberMethods dictviews_as_number = {
- 0, /*nb_add*/
- (binaryfunc)dictviews_sub, /*nb_subtract*/
- 0, /*nb_multiply*/
- 0, /*nb_remainder*/
- 0, /*nb_divmod*/
- 0, /*nb_power*/
- 0, /*nb_negative*/
- 0, /*nb_positive*/
- 0, /*nb_absolute*/
- 0, /*nb_bool*/
- 0, /*nb_invert*/
- 0, /*nb_lshift*/
- 0, /*nb_rshift*/
- (binaryfunc)_PyDictView_Intersect, /*nb_and*/
- (binaryfunc)dictviews_xor, /*nb_xor*/
- (binaryfunc)dictviews_or, /*nb_or*/
- };
- static PyObject*
- dictviews_isdisjoint(PyObject *self, PyObject *other)
- {
- PyObject *it;
- PyObject *item = NULL;
- if (self == other) {
- if (dictview_len((_PyDictViewObject *)self) == 0)
- Py_RETURN_TRUE;
- else
- Py_RETURN_FALSE;
- }
- /* Iterate over the shorter object (only if other is a set,
- * because PySequence_Contains may be expensive otherwise): */
- if (PyAnySet_Check(other) || PyDictViewSet_Check(other)) {
- Py_ssize_t len_self = dictview_len((_PyDictViewObject *)self);
- Py_ssize_t len_other = PyObject_Size(other);
- if (len_other == -1)
- return NULL;
- if ((len_other > len_self)) {
- PyObject *tmp = other;
- other = self;
- self = tmp;
- }
- }
- it = PyObject_GetIter(other);
- if (it == NULL)
- return NULL;
- while ((item = PyIter_Next(it)) != NULL) {
- int contains = PySequence_Contains(self, item);
- Py_DECREF(item);
- if (contains == -1) {
- Py_DECREF(it);
- return NULL;
- }
- if (contains) {
- Py_DECREF(it);
- Py_RETURN_FALSE;
- }
- }
- Py_DECREF(it);
- if (PyErr_Occurred())
- return NULL; /* PyIter_Next raised an exception. */
- Py_RETURN_TRUE;
- }
- PyDoc_STRVAR(isdisjoint_doc,
- "Return True if the view and the given iterable have a null intersection.");
- static PyObject* dictkeys_reversed(_PyDictViewObject *dv, PyObject *Py_UNUSED(ignored));
- PyDoc_STRVAR(reversed_keys_doc,
- "Return a reverse iterator over the dict keys.");
- static PyMethodDef dictkeys_methods[] = {
- {"isdisjoint", (PyCFunction)dictviews_isdisjoint, METH_O,
- isdisjoint_doc},
- {"__reversed__", _PyCFunction_CAST(dictkeys_reversed), METH_NOARGS,
- reversed_keys_doc},
- {NULL, NULL} /* sentinel */
- };
- PyTypeObject PyDictKeys_Type = {
- PyVarObject_HEAD_INIT(&PyType_Type, 0)
- "dict_keys", /* tp_name */
- sizeof(_PyDictViewObject), /* tp_basicsize */
- 0, /* tp_itemsize */
- /* methods */
- (destructor)dictview_dealloc, /* tp_dealloc */
- 0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_as_async */
- (reprfunc)dictview_repr, /* tp_repr */
- &dictviews_as_number, /* tp_as_number */
- &dictkeys_as_sequence, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- PyObject_GenericGetAttr, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
- 0, /* tp_doc */
- (traverseproc)dictview_traverse, /* tp_traverse */
- 0, /* tp_clear */
- dictview_richcompare, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- (getiterfunc)dictkeys_iter, /* tp_iter */
- 0, /* tp_iternext */
- dictkeys_methods, /* tp_methods */
- .tp_getset = dictview_getset,
- };
- static PyObject *
- dictkeys_new(PyObject *dict, PyObject *Py_UNUSED(ignored))
- {
- return _PyDictView_New(dict, &PyDictKeys_Type);
- }
- static PyObject *
- dictkeys_reversed(_PyDictViewObject *dv, PyObject *Py_UNUSED(ignored))
- {
- if (dv->dv_dict == NULL) {
- Py_RETURN_NONE;
- }
- return dictiter_new(dv->dv_dict, &PyDictRevIterKey_Type);
- }
- /*** dict_items ***/
- static PyObject *
- dictitems_iter(_PyDictViewObject *dv)
- {
- if (dv->dv_dict == NULL) {
- Py_RETURN_NONE;
- }
- return dictiter_new(dv->dv_dict, &PyDictIterItem_Type);
- }
- static int
- dictitems_contains(_PyDictViewObject *dv, PyObject *obj)
- {
- int result;
- PyObject *key, *value, *found;
- if (dv->dv_dict == NULL)
- return 0;
- if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 2)
- return 0;
- key = PyTuple_GET_ITEM(obj, 0);
- value = PyTuple_GET_ITEM(obj, 1);
- found = PyDict_GetItemWithError((PyObject *)dv->dv_dict, key);
- if (found == NULL) {
- if (PyErr_Occurred())
- return -1;
- return 0;
- }
- Py_INCREF(found);
- result = PyObject_RichCompareBool(found, value, Py_EQ);
- Py_DECREF(found);
- return result;
- }
- static PySequenceMethods dictitems_as_sequence = {
- (lenfunc)dictview_len, /* sq_length */
- 0, /* sq_concat */
- 0, /* sq_repeat */
- 0, /* sq_item */
- 0, /* sq_slice */
- 0, /* sq_ass_item */
- 0, /* sq_ass_slice */
- (objobjproc)dictitems_contains, /* sq_contains */
- };
- static PyObject* dictitems_reversed(_PyDictViewObject *dv, PyObject *Py_UNUSED(ignored));
- PyDoc_STRVAR(reversed_items_doc,
- "Return a reverse iterator over the dict items.");
- static PyMethodDef dictitems_methods[] = {
- {"isdisjoint", (PyCFunction)dictviews_isdisjoint, METH_O,
- isdisjoint_doc},
- {"__reversed__", (PyCFunction)dictitems_reversed, METH_NOARGS,
- reversed_items_doc},
- {NULL, NULL} /* sentinel */
- };
- PyTypeObject PyDictItems_Type = {
- PyVarObject_HEAD_INIT(&PyType_Type, 0)
- "dict_items", /* tp_name */
- sizeof(_PyDictViewObject), /* tp_basicsize */
- 0, /* tp_itemsize */
- /* methods */
- (destructor)dictview_dealloc, /* tp_dealloc */
- 0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_as_async */
- (reprfunc)dictview_repr, /* tp_repr */
- &dictviews_as_number, /* tp_as_number */
- &dictitems_as_sequence, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- PyObject_GenericGetAttr, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
- 0, /* tp_doc */
- (traverseproc)dictview_traverse, /* tp_traverse */
- 0, /* tp_clear */
- dictview_richcompare, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- (getiterfunc)dictitems_iter, /* tp_iter */
- 0, /* tp_iternext */
- dictitems_methods, /* tp_methods */
- .tp_getset = dictview_getset,
- };
- static PyObject *
- dictitems_new(PyObject *dict, PyObject *Py_UNUSED(ignored))
- {
- return _PyDictView_New(dict, &PyDictItems_Type);
- }
- static PyObject *
- dictitems_reversed(_PyDictViewObject *dv, PyObject *Py_UNUSED(ignored))
- {
- if (dv->dv_dict == NULL) {
- Py_RETURN_NONE;
- }
- return dictiter_new(dv->dv_dict, &PyDictRevIterItem_Type);
- }
- /*** dict_values ***/
- static PyObject *
- dictvalues_iter(_PyDictViewObject *dv)
- {
- if (dv->dv_dict == NULL) {
- Py_RETURN_NONE;
- }
- return dictiter_new(dv->dv_dict, &PyDictIterValue_Type);
- }
- static PySequenceMethods dictvalues_as_sequence = {
- (lenfunc)dictview_len, /* sq_length */
- 0, /* sq_concat */
- 0, /* sq_repeat */
- 0, /* sq_item */
- 0, /* sq_slice */
- 0, /* sq_ass_item */
- 0, /* sq_ass_slice */
- (objobjproc)0, /* sq_contains */
- };
- static PyObject* dictvalues_reversed(_PyDictViewObject *dv, PyObject *Py_UNUSED(ignored));
- PyDoc_STRVAR(reversed_values_doc,
- "Return a reverse iterator over the dict values.");
- static PyMethodDef dictvalues_methods[] = {
- {"__reversed__", (PyCFunction)dictvalues_reversed, METH_NOARGS,
- reversed_values_doc},
- {NULL, NULL} /* sentinel */
- };
- PyTypeObject PyDictValues_Type = {
- PyVarObject_HEAD_INIT(&PyType_Type, 0)
- "dict_values", /* tp_name */
- sizeof(_PyDictViewObject), /* tp_basicsize */
- 0, /* tp_itemsize */
- /* methods */
- (destructor)dictview_dealloc, /* tp_dealloc */
- 0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_as_async */
- (reprfunc)dictview_repr, /* tp_repr */
- 0, /* tp_as_number */
- &dictvalues_as_sequence, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- PyObject_GenericGetAttr, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */
- 0, /* tp_doc */
- (traverseproc)dictview_traverse, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- (getiterfunc)dictvalues_iter, /* tp_iter */
- 0, /* tp_iternext */
- dictvalues_methods, /* tp_methods */
- .tp_getset = dictview_getset,
- };
- static PyObject *
- dictvalues_new(PyObject *dict, PyObject *Py_UNUSED(ignored))
- {
- return _PyDictView_New(dict, &PyDictValues_Type);
- }
- static PyObject *
- dictvalues_reversed(_PyDictViewObject *dv, PyObject *Py_UNUSED(ignored))
- {
- if (dv->dv_dict == NULL) {
- Py_RETURN_NONE;
- }
- return dictiter_new(dv->dv_dict, &PyDictRevIterValue_Type);
- }
- /* Returns NULL if cannot allocate a new PyDictKeysObject,
- but does not set an error */
- PyDictKeysObject *
- _PyDict_NewKeysForClass(void)
- {
- PyInterpreterState *interp = _PyInterpreterState_GET();
- PyDictKeysObject *keys = new_keys_object(
- interp, NEXT_LOG2_SHARED_KEYS_MAX_SIZE, 1);
- if (keys == NULL) {
- PyErr_Clear();
- }
- else {
- assert(keys->dk_nentries == 0);
- /* Set to max size+1 as it will shrink by one before each new object */
- keys->dk_usable = SHARED_KEYS_MAX_SIZE;
- keys->dk_kind = DICT_KEYS_SPLIT;
- }
- return keys;
- }
- #define CACHED_KEYS(tp) (((PyHeapTypeObject*)tp)->ht_cached_keys)
- static int
- init_inline_values(PyObject *obj, PyTypeObject *tp)
- {
- assert(tp->tp_flags & Py_TPFLAGS_HEAPTYPE);
- // assert(type->tp_dictoffset > 0); -- TO DO Update this assert.
- assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT);
- PyDictKeysObject *keys = CACHED_KEYS(tp);
- assert(keys != NULL);
- if (keys->dk_usable > 1) {
- keys->dk_usable--;
- }
- size_t size = shared_keys_usable_size(keys);
- PyDictValues *values = new_values(size);
- if (values == NULL) {
- PyErr_NoMemory();
- return -1;
- }
- assert(((uint8_t *)values)[-1] >= (size + 2));
- ((uint8_t *)values)[-2] = 0;
- for (size_t i = 0; i < size; i++) {
- values->values[i] = NULL;
- }
- _PyDictOrValues_SetValues(_PyObject_DictOrValuesPointer(obj), values);
- return 0;
- }
- int
- _PyObject_InitializeDict(PyObject *obj)
- {
- PyInterpreterState *interp = _PyInterpreterState_GET();
- PyTypeObject *tp = Py_TYPE(obj);
- if (tp->tp_dictoffset == 0) {
- return 0;
- }
- if (tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
- OBJECT_STAT_INC(new_values);
- return init_inline_values(obj, tp);
- }
- PyObject *dict;
- if (_PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE) && CACHED_KEYS(tp)) {
- dictkeys_incref(CACHED_KEYS(tp));
- dict = new_dict_with_shared_keys(interp, CACHED_KEYS(tp));
- }
- else {
- dict = PyDict_New();
- }
- if (dict == NULL) {
- return -1;
- }
- PyObject **dictptr = _PyObject_ComputedDictPointer(obj);
- *dictptr = dict;
- return 0;
- }
- static PyObject *
- make_dict_from_instance_attributes(PyInterpreterState *interp,
- PyDictKeysObject *keys, PyDictValues *values)
- {
- dictkeys_incref(keys);
- Py_ssize_t used = 0;
- Py_ssize_t track = 0;
- size_t size = shared_keys_usable_size(keys);
- for (size_t i = 0; i < size; i++) {
- PyObject *val = values->values[i];
- if (val != NULL) {
- used += 1;
- track += _PyObject_GC_MAY_BE_TRACKED(val);
- }
- }
- PyObject *res = new_dict(interp, keys, values, used, 0);
- if (track && res) {
- _PyObject_GC_TRACK(res);
- }
- return res;
- }
- PyObject *
- _PyObject_MakeDictFromInstanceAttributes(PyObject *obj, PyDictValues *values)
- {
- PyInterpreterState *interp = _PyInterpreterState_GET();
- PyDictKeysObject *keys = CACHED_KEYS(Py_TYPE(obj));
- OBJECT_STAT_INC(dict_materialized_on_request);
- return make_dict_from_instance_attributes(interp, keys, values);
- }
- int
- _PyObject_StoreInstanceAttribute(PyObject *obj, PyDictValues *values,
- PyObject *name, PyObject *value)
- {
- PyInterpreterState *interp = _PyInterpreterState_GET();
- PyDictKeysObject *keys = CACHED_KEYS(Py_TYPE(obj));
- assert(keys != NULL);
- assert(values != NULL);
- assert(Py_TYPE(obj)->tp_flags & Py_TPFLAGS_MANAGED_DICT);
- Py_ssize_t ix = DKIX_EMPTY;
- if (PyUnicode_CheckExact(name)) {
- ix = insert_into_dictkeys(keys, name);
- }
- if (ix == DKIX_EMPTY) {
- #ifdef Py_STATS
- if (PyUnicode_CheckExact(name)) {
- if (shared_keys_usable_size(keys) == SHARED_KEYS_MAX_SIZE) {
- OBJECT_STAT_INC(dict_materialized_too_big);
- }
- else {
- OBJECT_STAT_INC(dict_materialized_new_key);
- }
- }
- else {
- OBJECT_STAT_INC(dict_materialized_str_subclass);
- }
- #endif
- PyObject *dict = make_dict_from_instance_attributes(
- interp, keys, values);
- if (dict == NULL) {
- return -1;
- }
- _PyObject_DictOrValuesPointer(obj)->dict = dict;
- if (value == NULL) {
- return PyDict_DelItem(dict, name);
- }
- else {
- return PyDict_SetItem(dict, name, value);
- }
- }
- PyObject *old_value = values->values[ix];
- values->values[ix] = Py_XNewRef(value);
- if (old_value == NULL) {
- if (value == NULL) {
- PyErr_Format(PyExc_AttributeError,
- "'%.100s' object has no attribute '%U'",
- Py_TYPE(obj)->tp_name, name);
- return -1;
- }
- _PyDictValues_AddToInsertionOrder(values, ix);
- }
- else {
- if (value == NULL) {
- delete_index_from_values(values, ix);
- }
- Py_DECREF(old_value);
- }
- return 0;
- }
- /* Sanity check for managed dicts */
- #if 0
- #define CHECK(val) assert(val); if (!(val)) { return 0; }
- int
- _PyObject_ManagedDictValidityCheck(PyObject *obj)
- {
- PyTypeObject *tp = Py_TYPE(obj);
- CHECK(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT);
- PyDictOrValues *dorv_ptr = _PyObject_DictOrValuesPointer(obj);
- if (_PyDictOrValues_IsValues(*dorv_ptr)) {
- PyDictValues *values = _PyDictOrValues_GetValues(*dorv_ptr);
- int size = ((uint8_t *)values)[-2];
- int count = 0;
- PyDictKeysObject *keys = CACHED_KEYS(tp);
- for (Py_ssize_t i = 0; i < keys->dk_nentries; i++) {
- if (values->values[i] != NULL) {
- count++;
- }
- }
- CHECK(size == count);
- }
- else {
- if (dorv_ptr->dict != NULL) {
- CHECK(PyDict_Check(dorv_ptr->dict));
- }
- }
- return 1;
- }
- #endif
- PyObject *
- _PyObject_GetInstanceAttribute(PyObject *obj, PyDictValues *values,
- PyObject *name)
- {
- assert(PyUnicode_CheckExact(name));
- PyDictKeysObject *keys = CACHED_KEYS(Py_TYPE(obj));
- assert(keys != NULL);
- Py_ssize_t ix = _PyDictKeys_StringLookup(keys, name);
- if (ix == DKIX_EMPTY) {
- return NULL;
- }
- PyObject *value = values->values[ix];
- return Py_XNewRef(value);
- }
- int
- _PyObject_IsInstanceDictEmpty(PyObject *obj)
- {
- PyTypeObject *tp = Py_TYPE(obj);
- if (tp->tp_dictoffset == 0) {
- return 1;
- }
- PyObject *dict;
- if (tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
- PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(obj);
- if (_PyDictOrValues_IsValues(dorv)) {
- PyDictKeysObject *keys = CACHED_KEYS(tp);
- for (Py_ssize_t i = 0; i < keys->dk_nentries; i++) {
- if (_PyDictOrValues_GetValues(dorv)->values[i] != NULL) {
- return 0;
- }
- }
- return 1;
- }
- dict = _PyDictOrValues_GetDict(dorv);
- }
- else {
- PyObject **dictptr = _PyObject_ComputedDictPointer(obj);
- dict = *dictptr;
- }
- if (dict == NULL) {
- return 1;
- }
- return ((PyDictObject *)dict)->ma_used == 0;
- }
- void
- _PyObject_FreeInstanceAttributes(PyObject *self)
- {
- PyTypeObject *tp = Py_TYPE(self);
- assert(Py_TYPE(self)->tp_flags & Py_TPFLAGS_MANAGED_DICT);
- PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(self);
- if (!_PyDictOrValues_IsValues(dorv)) {
- return;
- }
- PyDictValues *values = _PyDictOrValues_GetValues(dorv);
- PyDictKeysObject *keys = CACHED_KEYS(tp);
- for (Py_ssize_t i = 0; i < keys->dk_nentries; i++) {
- Py_XDECREF(values->values[i]);
- }
- free_values(values);
- }
- int
- _PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg)
- {
- PyTypeObject *tp = Py_TYPE(obj);
- if((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) {
- return 0;
- }
- assert(tp->tp_dictoffset);
- PyDictOrValues dorv = *_PyObject_DictOrValuesPointer(obj);
- if (_PyDictOrValues_IsValues(dorv)) {
- PyDictValues *values = _PyDictOrValues_GetValues(dorv);
- PyDictKeysObject *keys = CACHED_KEYS(tp);
- for (Py_ssize_t i = 0; i < keys->dk_nentries; i++) {
- Py_VISIT(values->values[i]);
- }
- }
- else {
- PyObject *dict = _PyDictOrValues_GetDict(dorv);
- Py_VISIT(dict);
- }
- return 0;
- }
- void
- _PyObject_ClearManagedDict(PyObject *obj)
- {
- PyTypeObject *tp = Py_TYPE(obj);
- if((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT) == 0) {
- return;
- }
- PyDictOrValues *dorv_ptr = _PyObject_DictOrValuesPointer(obj);
- if (_PyDictOrValues_IsValues(*dorv_ptr)) {
- PyDictValues *values = _PyDictOrValues_GetValues(*dorv_ptr);
- PyDictKeysObject *keys = CACHED_KEYS(tp);
- for (Py_ssize_t i = 0; i < keys->dk_nentries; i++) {
- Py_CLEAR(values->values[i]);
- }
- dorv_ptr->dict = NULL;
- free_values(values);
- }
- else {
- PyObject *dict = dorv_ptr->dict;
- if (dict) {
- dorv_ptr->dict = NULL;
- Py_DECREF(dict);
- }
- }
- }
- PyObject *
- PyObject_GenericGetDict(PyObject *obj, void *context)
- {
- PyObject *dict;
- PyInterpreterState *interp = _PyInterpreterState_GET();
- PyTypeObject *tp = Py_TYPE(obj);
- if (_PyType_HasFeature(tp, Py_TPFLAGS_MANAGED_DICT)) {
- PyDictOrValues *dorv_ptr = _PyObject_DictOrValuesPointer(obj);
- if (_PyDictOrValues_IsValues(*dorv_ptr)) {
- PyDictValues *values = _PyDictOrValues_GetValues(*dorv_ptr);
- OBJECT_STAT_INC(dict_materialized_on_request);
- dict = make_dict_from_instance_attributes(
- interp, CACHED_KEYS(tp), values);
- if (dict != NULL) {
- dorv_ptr->dict = dict;
- }
- }
- else {
- dict = _PyDictOrValues_GetDict(*dorv_ptr);
- if (dict == NULL) {
- dictkeys_incref(CACHED_KEYS(tp));
- dict = new_dict_with_shared_keys(interp, CACHED_KEYS(tp));
- dorv_ptr->dict = dict;
- }
- }
- }
- else {
- PyObject **dictptr = _PyObject_ComputedDictPointer(obj);
- if (dictptr == NULL) {
- PyErr_SetString(PyExc_AttributeError,
- "This object has no __dict__");
- return NULL;
- }
- dict = *dictptr;
- if (dict == NULL) {
- PyTypeObject *tp = Py_TYPE(obj);
- if (_PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE) && CACHED_KEYS(tp)) {
- dictkeys_incref(CACHED_KEYS(tp));
- *dictptr = dict = new_dict_with_shared_keys(
- interp, CACHED_KEYS(tp));
- }
- else {
- *dictptr = dict = PyDict_New();
- }
- }
- }
- return Py_XNewRef(dict);
- }
- int
- _PyObjectDict_SetItem(PyTypeObject *tp, PyObject **dictptr,
- PyObject *key, PyObject *value)
- {
- PyObject *dict;
- int res;
- PyDictKeysObject *cached;
- PyInterpreterState *interp = _PyInterpreterState_GET();
- assert(dictptr != NULL);
- if ((tp->tp_flags & Py_TPFLAGS_HEAPTYPE) && (cached = CACHED_KEYS(tp))) {
- assert(dictptr != NULL);
- dict = *dictptr;
- if (dict == NULL) {
- dictkeys_incref(cached);
- dict = new_dict_with_shared_keys(interp, cached);
- if (dict == NULL)
- return -1;
- *dictptr = dict;
- }
- if (value == NULL) {
- res = PyDict_DelItem(dict, key);
- }
- else {
- res = PyDict_SetItem(dict, key, value);
- }
- } else {
- dict = *dictptr;
- if (dict == NULL) {
- dict = PyDict_New();
- if (dict == NULL)
- return -1;
- *dictptr = dict;
- }
- if (value == NULL) {
- res = PyDict_DelItem(dict, key);
- } else {
- res = PyDict_SetItem(dict, key, value);
- }
- }
- ASSERT_CONSISTENT(dict);
- return res;
- }
- void
- _PyDictKeys_DecRef(PyDictKeysObject *keys)
- {
- PyInterpreterState *interp = _PyInterpreterState_GET();
- dictkeys_decref(interp, keys);
- }
- uint32_t _PyDictKeys_GetVersionForCurrentState(PyInterpreterState *interp,
- PyDictKeysObject *dictkeys)
- {
- if (dictkeys->dk_version != 0) {
- return dictkeys->dk_version;
- }
- if (interp->dict_state.next_keys_version == 0) {
- return 0;
- }
- uint32_t v = interp->dict_state.next_keys_version++;
- dictkeys->dk_version = v;
- return v;
- }
- static inline int
- validate_watcher_id(PyInterpreterState *interp, int watcher_id)
- {
- if (watcher_id < 0 || watcher_id >= DICT_MAX_WATCHERS) {
- PyErr_Format(PyExc_ValueError, "Invalid dict watcher ID %d", watcher_id);
- return -1;
- }
- if (!interp->dict_state.watchers[watcher_id]) {
- PyErr_Format(PyExc_ValueError, "No dict watcher set for ID %d", watcher_id);
- return -1;
- }
- return 0;
- }
- int
- PyDict_Watch(int watcher_id, PyObject* dict)
- {
- if (!PyDict_Check(dict)) {
- PyErr_SetString(PyExc_ValueError, "Cannot watch non-dictionary");
- return -1;
- }
- PyInterpreterState *interp = _PyInterpreterState_GET();
- if (validate_watcher_id(interp, watcher_id)) {
- return -1;
- }
- ((PyDictObject*)dict)->ma_version_tag |= (1LL << watcher_id);
- return 0;
- }
- int
- PyDict_Unwatch(int watcher_id, PyObject* dict)
- {
- if (!PyDict_Check(dict)) {
- PyErr_SetString(PyExc_ValueError, "Cannot watch non-dictionary");
- return -1;
- }
- PyInterpreterState *interp = _PyInterpreterState_GET();
- if (validate_watcher_id(interp, watcher_id)) {
- return -1;
- }
- ((PyDictObject*)dict)->ma_version_tag &= ~(1LL << watcher_id);
- return 0;
- }
- int
- PyDict_AddWatcher(PyDict_WatchCallback callback)
- {
- PyInterpreterState *interp = _PyInterpreterState_GET();
- for (int i = 0; i < DICT_MAX_WATCHERS; i++) {
- if (!interp->dict_state.watchers[i]) {
- interp->dict_state.watchers[i] = callback;
- return i;
- }
- }
- PyErr_SetString(PyExc_RuntimeError, "no more dict watcher IDs available");
- return -1;
- }
- int
- PyDict_ClearWatcher(int watcher_id)
- {
- PyInterpreterState *interp = _PyInterpreterState_GET();
- if (validate_watcher_id(interp, watcher_id)) {
- return -1;
- }
- interp->dict_state.watchers[watcher_id] = NULL;
- return 0;
- }
- static const char *
- dict_event_name(PyDict_WatchEvent event) {
- switch (event) {
- #define CASE(op) \
- case PyDict_EVENT_##op: \
- return "PyDict_EVENT_" #op;
- PY_FOREACH_DICT_EVENT(CASE)
- #undef CASE
- }
- Py_UNREACHABLE();
- }
- void
- _PyDict_SendEvent(int watcher_bits,
- PyDict_WatchEvent event,
- PyDictObject *mp,
- PyObject *key,
- PyObject *value)
- {
- PyInterpreterState *interp = _PyInterpreterState_GET();
- for (int i = 0; i < DICT_MAX_WATCHERS; i++) {
- if (watcher_bits & 1) {
- PyDict_WatchCallback cb = interp->dict_state.watchers[i];
- if (cb && (cb(event, (PyObject*)mp, key, value) < 0)) {
- // We don't want to resurrect the dict by potentially having an
- // unraisablehook keep a reference to it, so we don't pass the
- // dict as context, just an informative string message. Dict
- // repr can call arbitrary code, so we invent a simpler version.
- PyObject *context = PyUnicode_FromFormat(
- "%s watcher callback for <dict at %p>",
- dict_event_name(event), mp);
- if (context == NULL) {
- context = Py_NewRef(Py_None);
- }
- PyErr_WriteUnraisable(context);
- Py_DECREF(context);
- }
- }
- watcher_bits >>= 1;
- }
- }
|