12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090 |
- /**
- * $(SCRIPT inhibitQuickIndex = 1;)
- * $(DIVC quickindex,
- * $(BOOKTABLE,
- * $(TR $(TH Category) $(TH Symbols))
- * $(TR $(TD Arrays) $(TD
- * $(MYREF assumeSafeAppend)
- * $(MYREF capacity)
- * $(MYREF idup)
- * $(MYREF reserve)
- * ))
- * $(TR $(TD Associative arrays) $(TD
- * $(MYREF byKey)
- * $(MYREF byKeyValue)
- * $(MYREF byValue)
- * $(MYREF clear)
- * $(MYREF get)
- * $(MYREF keys)
- * $(MYREF rehash)
- * $(MYREF require)
- * $(MYREF update)
- * $(MYREF values)
- * ))
- * $(TR $(TD General) $(TD
- * $(MYREF destroy)
- * $(MYREF dup)
- * $(MYREF hashOf)
- * $(MYREF opEquals)
- * ))
- * $(TR $(TD Types) $(TD
- * $(MYREF Error)
- * $(MYREF Exception)
- * $(MYREF noreturn)
- * $(MYREF Object)
- * $(MYREF Throwable)
- * ))
- * $(TR $(TD Type info) $(TD
- * $(MYREF Interface)
- * $(MYREF ModuleInfo)
- * $(MYREF OffsetTypeInfo)
- * $(MYREF RTInfoImpl)
- * $(MYREF rtinfoNoPointers)
- * $(MYREF TypeInfo)
- * $(MYREF TypeInfo_Class)
- * ))
- * ))
- *
- * Forms the symbols available to all D programs. Includes Object, which is
- * the root of the class object hierarchy. This module is implicitly
- * imported.
- *
- * Copyright: Copyright Digital Mars 2000 - 2011.
- * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
- * Authors: Walter Bright, Sean Kelly
- * Source: $(DRUNTIMESRC object.d)
- */
- module object;
- alias size_t = typeof(int.sizeof);
- alias ptrdiff_t = typeof(cast(void*)0 - cast(void*)0);
- alias sizediff_t = ptrdiff_t; // For backwards compatibility only.
- alias noreturn = typeof(*null); /// bottom type
- alias hash_t = size_t; // For backwards compatibility only.
- alias equals_t = bool; // For backwards compatibility only.
- alias string = immutable(char)[];
- alias wstring = immutable(wchar)[];
- alias dstring = immutable(dchar)[];
- version (D_ObjectiveC)
- {
- deprecated("explicitly import `selector` instead using: `import core.attribute : selector;`")
- public import core.attribute : selector;
- }
- version (Posix) public import core.attribute : gnuAbiTag;
- // Some ABIs use a complex varargs implementation requiring TypeInfo.argTypes().
- version (GNU)
- {
- // No TypeInfo-based core.vararg.va_arg().
- }
- else version (X86_64)
- {
- version (DigitalMars) version = WithArgTypes;
- else version (Windows) { /* no need for Win64 ABI */ }
- else version = WithArgTypes;
- }
- else version (AArch64)
- {
- // Apple uses a trivial varargs implementation
- version (OSX) {}
- else version (iOS) {}
- else version (TVOS) {}
- else version (WatchOS) {}
- else version = WithArgTypes;
- }
- /**
- * All D class objects inherit from Object.
- */
- class Object
- {
- /**
- * Convert Object to a human readable string.
- */
- string toString()
- {
- return typeid(this).name;
- }
- @system unittest
- {
- enum unittest_sym_name = __traits(identifier, __traits(parent, (){}));
- enum fqn_unittest = "object.Object." ~ unittest_sym_name; // object.__unittest_LX_CY
- class C {}
- Object obj = new Object;
- C c = new C;
- assert(obj.toString() == "object.Object");
- assert(c.toString() == fqn_unittest ~ ".C");
- }
- /**
- * Compute hash function for Object.
- */
- size_t toHash() @trusted nothrow
- {
- // BUG: this prevents a compacting GC from working, needs to be fixed
- size_t addr = cast(size_t) cast(void*) this;
- // The bottom log2((void*).alignof) bits of the address will always
- // be 0. Moreover it is likely that each Object is allocated with a
- // separate call to malloc. The alignment of malloc differs from
- // platform to platform, but rather than having special cases for
- // each platform it is safe to use a shift of 4. To minimize
- // collisions in the low bits it is more important for the shift to
- // not be too small than for the shift to not be too big.
- return addr ^ (addr >>> 4);
- }
- /**
- * Compare with another Object obj.
- * Returns:
- * $(TABLE
- * $(TR $(TD this < obj) $(TD < 0))
- * $(TR $(TD this == obj) $(TD 0))
- * $(TR $(TD this > obj) $(TD > 0))
- * )
- */
- int opCmp(Object o)
- {
- // BUG: this prevents a compacting GC from working, needs to be fixed
- //return cast(int)cast(void*)this - cast(int)cast(void*)o;
- throw new Exception("need opCmp for class " ~ typeid(this).name);
- //return this !is o;
- }
- @system unittest
- {
- Object obj = new Object;
- bool gotCaught;
- try
- {
- obj.opCmp(new Object);
- }
- catch (Exception e)
- {
- gotCaught = true;
- assert(e.msg == "need opCmp for class object.Object");
- }
- assert(gotCaught);
- }
- /**
- * Test whether $(D this) is equal to $(D o).
- * The default implementation only compares by identity (using the $(D is) operator).
- * Generally, overrides and overloads for $(D opEquals) should attempt to compare objects by their contents.
- * A class will most likely want to add an overload that takes your specific type as the argument
- * and does the content comparison. Then you can override this and forward it to your specific
- * typed overload with a cast. Remember to check for `null` on the typed overload.
- *
- * Examples:
- * ---
- * class Child {
- * int contents;
- * // the typed overload first. It can use all the attribute you want
- * bool opEquals(const Child c) const @safe pure nothrow @nogc
- * {
- * if (c is null)
- * return false;
- * return this.contents == c.contents;
- * }
- *
- * // and now the generic override forwards with a cast
- * override bool opEquals(Object o)
- * {
- * return this.opEquals(cast(Child) o);
- * }
- * }
- * ---
- */
- bool opEquals(Object o)
- {
- return this is o;
- }
- interface Monitor
- {
- void lock();
- void unlock();
- }
- /**
- * Create instance of class specified by the fully qualified name
- * classname.
- * The class must either have no constructors or have
- * a default constructor.
- * Returns:
- * null if failed
- * Example:
- * ---
- * module foo.bar;
- *
- * class C
- * {
- * this() { x = 10; }
- * int x;
- * }
- *
- * void main()
- * {
- * auto c = cast(C)Object.factory("foo.bar.C");
- * assert(c !is null && c.x == 10);
- * }
- * ---
- */
- static Object factory(string classname)
- {
- auto ci = TypeInfo_Class.find(classname);
- if (ci)
- {
- return ci.create();
- }
- return null;
- }
- @system unittest
- {
- Object valid_obj = Object.factory("object.Object");
- Object invalid_obj = Object.factory("object.__this_class_doesnt_exist__");
- assert(valid_obj !is null);
- assert(invalid_obj is null);
- }
- }
- /++
- Implementation for class opEquals override. Calls the class-defined methods after a null check.
- Please note this is not nogc right now, even if your implementation is, because of
- the typeinfo name string compare. This is because of dmd's dll implementation. However,
- it can infer to @safe if your class' opEquals is.
- +/
- bool opEquals(LHS, RHS)(LHS lhs, RHS rhs) if (is(LHS : const Object) && is(RHS : const Object))
- {
- static if (__traits(compiles, lhs.opEquals(rhs)) && __traits(compiles, rhs.opEquals(lhs)))
- {
- // If aliased to the same object or both null => equal
- if (lhs is rhs) return true;
- // If either is null => non-equal
- if (lhs is null || rhs is null) return false;
- if (!lhs.opEquals(rhs)) return false;
- // If same exact type => one call to method opEquals
- if (typeid(lhs) is typeid(rhs) ||
- !__ctfe && typeid(lhs).opEquals(typeid(rhs)))
- /* CTFE doesn't like typeid much. 'is' works, but opEquals doesn't
- (issue 7147). But CTFE also guarantees that equal TypeInfos are
- always identical. So, no opEquals needed during CTFE. */
- {
- return true;
- }
- // General case => symmetric calls to method opEquals
- return rhs.opEquals(lhs);
- }
- else
- {
- // this is a compatibility hack for the old const cast behavior
- // if none of the new overloads compile, we'll go back plain Object,
- // including casting away const. It does this through the pointer
- // to bypass any opCast that may be present on the original class.
- return .opEquals!(Object, Object)(*cast(Object*) &lhs, *cast(Object*) &rhs);
- }
- }
- /// If aliased to the same object or both null => equal
- @system unittest // this one is not @safe because it goes through the Object base method
- {
- class F { int flag; this(int flag) { this.flag = flag; } }
- F f;
- assert(f == f); // both null
- f = new F(1);
- assert(f == f); // both aliased to the same object
- }
- /// If either is null => non-equal
- @system unittest
- {
- class F { int flag; this(int flag) { this.flag = flag; } }
- F f;
- assert(!(new F(0) == f));
- assert(!(f == new F(0)));
- }
- /// If same exact type => one call to method opEquals
- /// This test passes `@safe` because it defines a new opEquals with `@safe`
- @safe unittest
- {
- class F
- {
- int flag;
- this(int flag)
- {
- this.flag = flag;
- }
- bool opEquals(const F o) const @safe nothrow pure
- {
- return flag == o.flag;
- }
- }
- F f;
- assert(new F(0) == new F(0));
- assert(!(new F(0) == new F(1)));
- }
- /// General case => symmetric calls to method opEquals
- @safe unittest
- {
- int fEquals, gEquals;
- class Base
- {
- int flag;
- this(int flag)
- {
- this.flag = flag;
- }
- }
- class F : Base
- {
- this(int flag) { super(flag); }
- bool opEquals(const Base o) @safe
- {
- fEquals++;
- return flag == o.flag;
- }
- }
- class G : Base
- {
- this(int flag) { super(flag); }
- bool opEquals(const Base o) @safe
- {
- gEquals++;
- return flag == o.flag;
- }
- }
- assert(new F(1) == new G(1));
- assert(fEquals == 1);
- assert(gEquals == 1);
- }
- /++
- This test shows an example for a comprehensive inheritance equality chain too.
- +/
- unittest
- {
- static class Base
- {
- int member;
- this(int member) pure @safe nothrow @nogc
- {
- this.member = member;
- }
- override bool opEquals(Object rhs) const
- {
- return this.opEquals(cast(Base) rhs);
- }
- bool opEquals(const Base rhs) const @nogc pure nothrow @safe
- {
- if (rhs is null)
- return false;
- return this.member == rhs.member;
- }
- }
- // works through the direct class with attributes enabled, except for pure and nogc in the current TypeInfo implementation
- bool testThroughBase() nothrow @safe
- {
- Base b1 = new Base(0);
- Base b2 = new Base(0);
- assert(b1 == b2);
- Base b3 = new Base(1);
- assert(b1 != b3);
- return true;
- }
- static assert(testThroughBase());
- // also works through the base class interface thanks to the override, but no more attributes
- bool testThroughObject()
- {
- Object o1 = new Base(0);
- Object o2 = new Base(0);
- assert(o1 == o2);
- Object o3 = new Base(1);
- assert(o1 != o3);
- return true;
- }
- static assert(testThroughObject());
- // Each time you make a child, you want to override all old opEquals
- // and add a new overload for the new child.
- static class Child : Base
- {
- int member2;
- this(int member, int member2) pure @safe nothrow @nogc
- {
- super(member);
- this.member2 = member2;
- }
- // override the whole chain so it works consistently though any base
- override bool opEquals(Object rhs) const
- {
- return this.opEquals(cast(Child) rhs);
- }
- override bool opEquals(const Base rhs) const
- {
- return this.opEquals(cast(const Child) rhs);
- }
- // and then add the new overload, if necessary, to handle new members
- bool opEquals(const Child rhs) const @nogc pure nothrow @safe
- {
- if (rhs is null)
- return false;
- // can call back to the devirtualized base test with implicit conversion
- // then compare the new member too. or we could have just compared the base
- // member directly here as well.
- return Base.opEquals(rhs) && this.member2 == rhs.member2;
- }
- // a mixin template, of course, could automate this.
- }
- bool testThroughChild()
- {
- Child a = new Child(0, 0);
- Child b = new Child(0, 1);
- assert(a != b);
- Base ba = a;
- Base bb = b;
- assert(ba != bb);
- Object oa = a;
- Object ob = b;
- assert(oa != ob);
- return true;
- }
- static assert(testThroughChild());
- }
- // To cover const Object opEquals
- @system unittest
- {
- const Object obj1 = new Object;
- const Object obj2 = new Object;
- assert(obj1 == obj1);
- assert(obj1 != obj2);
- }
- private extern(C) void _d_setSameMutex(shared Object ownee, shared Object owner) nothrow;
- void setSameMutex(shared Object ownee, shared Object owner)
- {
- _d_setSameMutex(ownee, owner);
- }
- @system unittest
- {
- shared Object obj1 = new Object;
- synchronized class C
- {
- void bar() {}
- }
- shared C obj2 = new shared(C);
- obj2.bar();
- assert(obj1.__monitor != obj2.__monitor);
- assert(obj1.__monitor is null);
- setSameMutex(obj1, obj2);
- assert(obj1.__monitor == obj2.__monitor);
- assert(obj1.__monitor !is null);
- }
- /**
- * Information about an interface.
- * When an object is accessed via an interface, an Interface* appears as the
- * first entry in its vtbl.
- */
- struct Interface
- {
- /// Class info returned by `typeid` for this interface (not for containing class)
- TypeInfo_Class classinfo;
- void*[] vtbl;
- size_t offset; /// offset to Interface 'this' from Object 'this'
- }
- /**
- * Array of pairs giving the offset and type information for each
- * member in an aggregate.
- */
- struct OffsetTypeInfo
- {
- size_t offset; /// Offset of member from start of object
- TypeInfo ti; /// TypeInfo for this member
- }
- /**
- * Runtime type information about a type.
- * Can be retrieved for any type using a
- * $(GLINK2 expression,TypeidExpression, TypeidExpression).
- */
- class TypeInfo
- {
- override string toString() const @safe nothrow
- {
- return typeid(this).name;
- }
- override size_t toHash() @trusted const nothrow
- {
- return hashOf(this.toString());
- }
- override int opCmp(Object rhs)
- {
- if (this is rhs)
- return 0;
- auto ti = cast(TypeInfo) rhs;
- if (ti is null)
- return 1;
- return __cmp(this.toString(), ti.toString());
- }
- @system unittest
- {
- assert(typeid(void) <= typeid(void));
- assert(typeid(void).opCmp(null));
- assert(!typeid(void).opCmp(typeid(void)));
- }
- override bool opEquals(Object o)
- {
- return opEquals(cast(TypeInfo) o);
- }
- bool opEquals(const TypeInfo ti) @safe nothrow const
- {
- /* TypeInfo instances are singletons, but duplicates can exist
- * across DLL's. Therefore, comparing for a name match is
- * sufficient.
- */
- if (this is ti)
- return true;
- return ti && this.toString() == ti.toString();
- }
- @system unittest
- {
- auto anotherObj = new Object();
- assert(typeid(void).opEquals(typeid(void)));
- assert(typeid(void) != anotherObj); // calling .opEquals here directly is a type mismatch
- }
- /**
- * Computes a hash of the instance of a type.
- * Params:
- * p = pointer to start of instance of the type
- * Returns:
- * the hash
- * Bugs:
- * fix https://issues.dlang.org/show_bug.cgi?id=12516 e.g. by changing this to a truly safe interface.
- */
- size_t getHash(scope const void* p) @trusted nothrow const
- {
- return hashOf(p);
- }
- /// Compares two instances for equality.
- bool equals(in void* p1, in void* p2) const { return p1 == p2; }
- /// Compares two instances for <, ==, or >.
- int compare(in void* p1, in void* p2) const { return _xopCmp(p1, p2); }
- /// Returns size of the type.
- @property size_t tsize() nothrow pure const @safe @nogc { return 0; }
- /// Swaps two instances of the type.
- void swap(void* p1, void* p2) const
- {
- size_t remaining = tsize;
- // If the type might contain pointers perform the swap in pointer-sized
- // chunks in case a garbage collection pass interrupts this function.
- if ((cast(size_t) p1 | cast(size_t) p2) % (void*).alignof == 0)
- {
- while (remaining >= (void*).sizeof)
- {
- void* tmp = *cast(void**) p1;
- *cast(void**) p1 = *cast(void**) p2;
- *cast(void**) p2 = tmp;
- p1 += (void*).sizeof;
- p2 += (void*).sizeof;
- remaining -= (void*).sizeof;
- }
- }
- for (size_t i = 0; i < remaining; i++)
- {
- byte t = (cast(byte *)p1)[i];
- (cast(byte*)p1)[i] = (cast(byte*)p2)[i];
- (cast(byte*)p2)[i] = t;
- }
- }
- @system unittest
- {
- class _TypeInfo_Dummy : TypeInfo
- {
- override const(void)[] initializer() const { return []; }
- @property override size_t tsize() nothrow pure const @safe @nogc { return tsize_val; }
- size_t tsize_val;
- }
- auto dummy = new _TypeInfo_Dummy();
- cast(void)dummy.initializer(); // For coverage completeness
- int a = 2, b = -2;
- dummy.swap(&a, &b);
- // does nothing because tsize is 0
- assert(a == 2);
- assert(b == -2);
- dummy.tsize_val = int.sizeof;
- dummy.swap(&a, &b);
- assert(a == -2);
- assert(b == 2);
- void* ptr_a = null, ptr_b = cast(void*)1;
- dummy.tsize_val = (void*).sizeof;
- dummy.swap(&ptr_a, &ptr_b);
- assert(ptr_a is cast(void*)1);
- assert(ptr_b is null);
- }
- /** Get TypeInfo for 'next' type, as defined by what kind of type this is,
- null if none. */
- @property inout(TypeInfo) next() nothrow pure inout @nogc { return null; }
- /**
- * Return default initializer. If the type should be initialized to all
- * zeros, an array with a null ptr and a length equal to the type size will
- * be returned. For static arrays, this returns the default initializer for
- * a single element of the array, use `tsize` to get the correct size.
- */
- abstract const(void)[] initializer() nothrow pure const @safe @nogc;
- /** Get flags for type: 1 means GC should scan for pointers,
- 2 means arg of this type is passed in SIMD register(s) if available */
- @property uint flags() nothrow pure const @safe @nogc { return 0; }
- /// Get type information on the contents of the type; null if not available
- const(OffsetTypeInfo)[] offTi() const { return null; }
- /// Run the destructor on the object and all its sub-objects
- void destroy(void* p) const {}
- /// Run the postblit on the object and all its sub-objects
- void postblit(void* p) const {}
- /// Return alignment of type
- @property size_t talign() nothrow pure const @safe @nogc { return tsize; }
- /** Return internal info on arguments fitting into 8byte.
- * See X86-64 ABI 3.2.3
- */
- version (WithArgTypes) int argTypes(out TypeInfo arg1, out TypeInfo arg2) @safe nothrow
- {
- arg1 = this;
- return 0;
- }
- /** Return info used by the garbage collector to do precise collection.
- */
- @property immutable(void)* rtInfo() nothrow pure const @safe @nogc { return rtinfoHasPointers; } // better safe than sorry
- }
- @system unittest
- {
- class _TypeInfo_Dummy : TypeInfo
- {
- override const(void)[] initializer() const { return []; }
- }
- auto dummy = new _TypeInfo_Dummy();
- cast(void)dummy.initializer(); // For coverage completeness
- assert(dummy.rtInfo() is rtinfoHasPointers);
- assert(typeid(void).rtInfo() is rtinfoNoPointers);
- assert(dummy.tsize() == 0);
- bool gotCaught;
- try
- {
- dummy.compare(null, null);
- } catch (Error e)
- {
- gotCaught = true;
- assert(e.msg == "TypeInfo.compare is not implemented");
- }
- assert(gotCaught);
- assert(dummy.equals(null, null));
- assert(!dummy.equals(cast(void*)1, null));
- }
- @system unittest
- {
- assert(typeid(void).next() is null);
- assert(typeid(void).offTi() is null);
- assert(typeid(void).tsize() == 1);
- version (WithArgTypes)
- {
- TypeInfo ti1;
- TypeInfo ti2;
- assert(typeid(void).argTypes(ti1, ti2) == 0);
- assert(typeid(void) is ti1);
- assert(ti1 !is null);
- assert(ti2 is null);
- }
- }
- @system unittest
- {
- class _ZypeInfo_Dummy : TypeInfo
- {
- override const(void)[] initializer() const { return []; }
- }
- auto dummy2 = new _ZypeInfo_Dummy();
- cast(void)dummy2.initializer(); // For coverage completeness
- assert(typeid(void) > dummy2);
- assert(dummy2 < typeid(void));
- }
- @safe unittest
- {
- enum unittest_sym_name = __traits(identifier, __traits(parent, (){}));
- enum fqn_unittest = "object." ~ unittest_sym_name; // object.__unittest_LX_CY
- class _TypeInfo_Dummy : TypeInfo
- {
- override const(void)[] initializer() const { return []; }
- }
- auto dummy = new _TypeInfo_Dummy();
- cast(void)dummy.initializer(); // For coverage completeness
- assert(dummy.toString() == fqn_unittest ~ "._TypeInfo_Dummy");
- assert(dummy.toHash() == hashOf(dummy.toString()));
- assert(dummy.getHash(null) == 0);
- }
- class TypeInfo_Enum : TypeInfo
- {
- override string toString() const pure { return name; }
- override bool opEquals(Object o)
- {
- if (this is o)
- return true;
- auto c = cast(const TypeInfo_Enum)o;
- return c && this.name == c.name &&
- this.base == c.base;
- }
- @system unittest
- {
- enum E { A, B, C }
- enum EE { A, B, C }
- assert(typeid(E).opEquals(typeid(E)));
- assert(!typeid(E).opEquals(typeid(EE)));
- }
- override size_t getHash(scope const void* p) const { return base.getHash(p); }
- @system unittest
- {
- enum E { A, B, C }
- E e1 = E.A;
- E e2 = E.B;
- assert(typeid(E).getHash(&e1) == hashOf(E.A));
- assert(typeid(E).getHash(&e2) == hashOf(E.B));
- enum ES : string { A = "foo", B = "bar" }
- ES es1 = ES.A;
- ES es2 = ES.B;
- assert(typeid(ES).getHash(&es1) == hashOf("foo"));
- assert(typeid(ES).getHash(&es2) == hashOf("bar"));
- }
- override bool equals(in void* p1, in void* p2) const { return base.equals(p1, p2); }
- @system unittest
- {
- enum E { A, B, C }
- E e1 = E.A;
- E e2 = E.B;
- assert(typeid(E).equals(&e1, &e1));
- assert(!typeid(E).equals(&e1, &e2));
- }
- override int compare(in void* p1, in void* p2) const { return base.compare(p1, p2); }
- @system unittest
- {
- enum E { A, B, C }
- E e1 = E.A;
- E e2 = E.B;
- assert(typeid(E).compare(&e1, &e1) == 0);
- assert(typeid(E).compare(&e1, &e2) < 0);
- assert(typeid(E).compare(&e2, &e1) > 0);
- }
- override @property size_t tsize() nothrow pure const { return base.tsize; }
- @safe unittest
- {
- enum E { A, B, C }
- enum ES : string { A = "a", B = "b", C = "c"}
- assert(typeid(E).tsize == E.sizeof);
- assert(typeid(ES).tsize == ES.sizeof);
- assert(typeid(E).tsize != ES.sizeof);
- }
- override void swap(void* p1, void* p2) const { return base.swap(p1, p2); }
- @system unittest
- {
- enum E { A, B, C }
- E e1 = E.A;
- E e2 = E.B;
- typeid(E).swap(&e1, &e2);
- assert(e1 == E.B);
- assert(e2 == E.A);
- }
- override @property inout(TypeInfo) next() nothrow pure inout { return base.next; }
- @system unittest
- {
- enum E { A, B, C }
- assert(typeid(E).next is null);
- }
- override @property uint flags() nothrow pure const { return base.flags; }
- @safe unittest
- {
- enum E { A, B, C }
- assert(typeid(E).flags == 0);
- }
- override const(OffsetTypeInfo)[] offTi() const { return base.offTi; }
- @system unittest
- {
- enum E { A, B, C }
- assert(typeid(E).offTi is null);
- }
- override void destroy(void* p) const { return base.destroy(p); }
- override void postblit(void* p) const { return base.postblit(p); }
- override const(void)[] initializer() const
- {
- return m_init.length ? m_init : base.initializer();
- }
- override @property size_t talign() nothrow pure const { return base.talign; }
- version (WithArgTypes) override int argTypes(out TypeInfo arg1, out TypeInfo arg2)
- {
- return base.argTypes(arg1, arg2);
- }
- override @property immutable(void)* rtInfo() const { return base.rtInfo; }
- TypeInfo base;
- string name;
- void[] m_init;
- }
- @safe unittest
- {
- enum unittest_sym_name = __traits(identifier, __traits(parent, (){}));
- enum fqn_unittest = "object." ~ unittest_sym_name; // object.__unittest_LX_CY
- enum E { A, B, C }
- enum EE { A, B, C }
- assert(typeid(E).toString() == fqn_unittest ~ ".E");
- }
- @safe unittest // issue 12233
- {
- static assert(is(typeof(TypeInfo.init) == TypeInfo));
- assert(TypeInfo.init is null);
- }
- // Please make sure to keep this in sync with TypeInfo_P (src/rt/typeinfo/ti_ptr.d)
- class TypeInfo_Pointer : TypeInfo
- {
- override string toString() const { return m_next.toString() ~ "*"; }
- override bool opEquals(Object o)
- {
- if (this is o)
- return true;
- auto c = cast(const TypeInfo_Pointer)o;
- return c && this.m_next == c.m_next;
- }
- override size_t getHash(scope const void* p) @trusted const
- {
- size_t addr = cast(size_t) *cast(const void**)p;
- return addr ^ (addr >> 4);
- }
- override bool equals(in void* p1, in void* p2) const
- {
- return *cast(void**)p1 == *cast(void**)p2;
- }
- override int compare(in void* p1, in void* p2) const
- {
- const v1 = *cast(void**) p1, v2 = *cast(void**) p2;
- return (v1 > v2) - (v1 < v2);
- }
- override @property size_t tsize() nothrow pure const
- {
- return (void*).sizeof;
- }
- override const(void)[] initializer() const @trusted
- {
- return (cast(void *)null)[0 .. (void*).sizeof];
- }
- override void swap(void* p1, void* p2) const
- {
- void* tmp = *cast(void**)p1;
- *cast(void**)p1 = *cast(void**)p2;
- *cast(void**)p2 = tmp;
- }
- override @property inout(TypeInfo) next() nothrow pure inout { return m_next; }
- override @property uint flags() nothrow pure const { return 1; }
- TypeInfo m_next;
- }
- class TypeInfo_Array : TypeInfo
- {
- override string toString() const { return value.toString() ~ "[]"; }
- override bool opEquals(Object o)
- {
- if (this is o)
- return true;
- auto c = cast(const TypeInfo_Array)o;
- return c && this.value == c.value;
- }
- override size_t getHash(scope const void* p) @trusted const
- {
- void[] a = *cast(void[]*)p;
- return getArrayHash(value, a.ptr, a.length);
- }
- override bool equals(in void* p1, in void* p2) const
- {
- void[] a1 = *cast(void[]*)p1;
- void[] a2 = *cast(void[]*)p2;
- if (a1.length != a2.length)
- return false;
- size_t sz = value.tsize;
- for (size_t i = 0; i < a1.length; i++)
- {
- if (!value.equals(a1.ptr + i * sz, a2.ptr + i * sz))
- return false;
- }
- return true;
- }
- override int compare(in void* p1, in void* p2) const
- {
- void[] a1 = *cast(void[]*)p1;
- void[] a2 = *cast(void[]*)p2;
- size_t sz = value.tsize;
- size_t len = a1.length;
- if (a2.length < len)
- len = a2.length;
- for (size_t u = 0; u < len; u++)
- {
- immutable int result = value.compare(a1.ptr + u * sz, a2.ptr + u * sz);
- if (result)
- return result;
- }
- return (a1.length > a2.length) - (a1.length < a2.length);
- }
- override @property size_t tsize() nothrow pure const
- {
- return (void[]).sizeof;
- }
- override const(void)[] initializer() const @trusted
- {
- return (cast(void *)null)[0 .. (void[]).sizeof];
- }
- override void swap(void* p1, void* p2) const
- {
- void[] tmp = *cast(void[]*)p1;
- *cast(void[]*)p1 = *cast(void[]*)p2;
- *cast(void[]*)p2 = tmp;
- }
- TypeInfo value;
- override @property inout(TypeInfo) next() nothrow pure inout
- {
- return value;
- }
- override @property uint flags() nothrow pure const { return 1; }
- override @property size_t talign() nothrow pure const
- {
- return (void[]).alignof;
- }
- version (WithArgTypes) override int argTypes(out TypeInfo arg1, out TypeInfo arg2)
- {
- arg1 = typeid(size_t);
- arg2 = typeid(void*);
- return 0;
- }
- override @property immutable(void)* rtInfo() nothrow pure const @safe { return RTInfo!(void[]); }
- }
- class TypeInfo_StaticArray : TypeInfo
- {
- override string toString() const
- {
- import core.internal.string : unsignedToTempString;
- char[20] tmpBuff = void;
- const lenString = unsignedToTempString(len, tmpBuff);
- return (() @trusted => cast(string) (value.toString() ~ "[" ~ lenString ~ "]"))();
- }
- override bool opEquals(Object o)
- {
- if (this is o)
- return true;
- auto c = cast(const TypeInfo_StaticArray)o;
- return c && this.len == c.len &&
- this.value == c.value;
- }
- override size_t getHash(scope const void* p) @trusted const
- {
- return getArrayHash(value, p, len);
- }
- override bool equals(in void* p1, in void* p2) const
- {
- size_t sz = value.tsize;
- for (size_t u = 0; u < len; u++)
- {
- if (!value.equals(p1 + u * sz, p2 + u * sz))
- return false;
- }
- return true;
- }
- override int compare(in void* p1, in void* p2) const
- {
- size_t sz = value.tsize;
- for (size_t u = 0; u < len; u++)
- {
- immutable int result = value.compare(p1 + u * sz, p2 + u * sz);
- if (result)
- return result;
- }
- return 0;
- }
- override @property size_t tsize() nothrow pure const
- {
- return len * value.tsize;
- }
- override void swap(void* p1, void* p2) const
- {
- import core.stdc.string : memcpy;
- size_t remaining = value.tsize * len;
- void[size_t.sizeof * 4] buffer = void;
- while (remaining > buffer.length)
- {
- memcpy(buffer.ptr, p1, buffer.length);
- memcpy(p1, p2, buffer.length);
- memcpy(p2, buffer.ptr, buffer.length);
- p1 += buffer.length;
- p2 += buffer.length;
- remaining -= buffer.length;
- }
- memcpy(buffer.ptr, p1, remaining);
- memcpy(p1, p2, remaining);
- memcpy(p2, buffer.ptr, remaining);
- }
- override const(void)[] initializer() nothrow pure const
- {
- return value.initializer();
- }
- override @property inout(TypeInfo) next() nothrow pure inout { return value; }
- override @property uint flags() nothrow pure const { return value.flags; }
- override void destroy(void* p) const
- {
- immutable sz = value.tsize;
- p += sz * len;
- foreach (i; 0 .. len)
- {
- p -= sz;
- value.destroy(p);
- }
- }
- override void postblit(void* p) const
- {
- immutable sz = value.tsize;
- foreach (i; 0 .. len)
- {
- value.postblit(p);
- p += sz;
- }
- }
- TypeInfo value;
- size_t len;
- override @property size_t talign() nothrow pure const
- {
- return value.talign;
- }
- version (WithArgTypes) override int argTypes(out TypeInfo arg1, out TypeInfo arg2)
- {
- arg1 = typeid(void*);
- return 0;
- }
- // just return the rtInfo of the element, we have no generic type T to run RTInfo!T on
- override @property immutable(void)* rtInfo() nothrow pure const @safe { return value.rtInfo(); }
- }
- // https://issues.dlang.org/show_bug.cgi?id=21315
- @system unittest
- {
- int[16] a, b;
- foreach (int i; 0 .. 16)
- {
- a[i] = i;
- b[i] = ~i;
- }
- typeid(int[16]).swap(&a, &b);
- foreach (int i; 0 .. 16)
- {
- assert(a[i] == ~i);
- assert(b[i] == i);
- }
- }
- class TypeInfo_AssociativeArray : TypeInfo
- {
- override string toString() const
- {
- return value.toString() ~ "[" ~ key.toString() ~ "]";
- }
- override bool opEquals(Object o)
- {
- if (this is o)
- return true;
- auto c = cast(const TypeInfo_AssociativeArray)o;
- return c && this.key == c.key &&
- this.value == c.value;
- }
- override bool equals(in void* p1, in void* p2) @trusted const
- {
- return !!_aaEqual(this, *cast(const AA*) p1, *cast(const AA*) p2);
- }
- override hash_t getHash(scope const void* p) nothrow @trusted const
- {
- return _aaGetHash(cast(AA*)p, this);
- }
- // BUG: need to add the rest of the functions
- override @property size_t tsize() nothrow pure const
- {
- return (char[int]).sizeof;
- }
- override const(void)[] initializer() const @trusted
- {
- return (cast(void *)null)[0 .. (char[int]).sizeof];
- }
- override @property inout(TypeInfo) next() nothrow pure inout { return value; }
- override @property uint flags() nothrow pure const { return 1; }
- TypeInfo value;
- TypeInfo key;
- override @property size_t talign() nothrow pure const
- {
- return (char[int]).alignof;
- }
- version (WithArgTypes) override int argTypes(out TypeInfo arg1, out TypeInfo arg2)
- {
- arg1 = typeid(void*);
- return 0;
- }
- }
- class TypeInfo_Vector : TypeInfo
- {
- override string toString() const { return "__vector(" ~ base.toString() ~ ")"; }
- override bool opEquals(Object o)
- {
- if (this is o)
- return true;
- auto c = cast(const TypeInfo_Vector)o;
- return c && this.base == c.base;
- }
- override size_t getHash(scope const void* p) const { return base.getHash(p); }
- override bool equals(in void* p1, in void* p2) const { return base.equals(p1, p2); }
- override int compare(in void* p1, in void* p2) const { return base.compare(p1, p2); }
- override @property size_t tsize() nothrow pure const { return base.tsize; }
- override void swap(void* p1, void* p2) const { return base.swap(p1, p2); }
- override @property inout(TypeInfo) next() nothrow pure inout { return base.next; }
- override @property uint flags() nothrow pure const { return 2; /* passed in SIMD register */ }
- override const(void)[] initializer() nothrow pure const
- {
- return base.initializer();
- }
- override @property size_t talign() nothrow pure const { return 16; }
- version (WithArgTypes) override int argTypes(out TypeInfo arg1, out TypeInfo arg2)
- {
- return base.argTypes(arg1, arg2);
- }
- TypeInfo base;
- }
- class TypeInfo_Function : TypeInfo
- {
- override string toString() const pure @trusted
- {
- import core.demangle : demangleType;
- alias SafeDemangleFunctionType = char[] function (const(char)[] buf, char[] dst = null) @safe nothrow pure;
- SafeDemangleFunctionType demangle = cast(SafeDemangleFunctionType) &demangleType;
- return cast(string) demangle(deco);
- }
- override bool opEquals(Object o)
- {
- if (this is o)
- return true;
- auto c = cast(const TypeInfo_Function)o;
- return c && this.deco == c.deco;
- }
- // BUG: need to add the rest of the functions
- override @property size_t tsize() nothrow pure const
- {
- return 0; // no size for functions
- }
- override const(void)[] initializer() const @safe
- {
- return null;
- }
- override @property immutable(void)* rtInfo() nothrow pure const @safe { return rtinfoNoPointers; }
- TypeInfo next;
- /**
- * Mangled function type string
- */
- string deco;
- }
- @safe unittest
- {
- abstract class C
- {
- void func();
- void func(int a);
- int func(int a, int b);
- }
- alias functionTypes = typeof(__traits(getVirtualFunctions, C, "func"));
- assert(typeid(functionTypes[0]).toString() == "void function()");
- assert(typeid(functionTypes[1]).toString() == "void function(int)");
- assert(typeid(functionTypes[2]).toString() == "int function(int, int)");
- }
- @system unittest
- {
- abstract class C
- {
- void func();
- void func(int a);
- }
- alias functionTypes = typeof(__traits(getVirtualFunctions, C, "func"));
- Object obj = typeid(functionTypes[0]);
- assert(obj.opEquals(typeid(functionTypes[0])));
- assert(typeid(functionTypes[0]) == typeid(functionTypes[0]));
- assert(typeid(functionTypes[0]) != typeid(functionTypes[1]));
- assert(typeid(functionTypes[0]).tsize() == 0);
- assert(typeid(functionTypes[0]).initializer() is null);
- assert(typeid(functionTypes[0]).rtInfo() is null);
- }
- class TypeInfo_Delegate : TypeInfo
- {
- override string toString() const pure @trusted
- {
- import core.demangle : demangleType;
- alias SafeDemangleFunctionType = char[] function (const(char)[] buf, char[] dst = null) @safe nothrow pure;
- SafeDemangleFunctionType demangle = cast(SafeDemangleFunctionType) &demangleType;
- return cast(string) demangle(deco);
- }
- @safe unittest
- {
- double sqr(double x) { return x * x; }
- sqr(double.init); // for coverage completeness
- auto delegate_str = "double delegate(double) pure nothrow @nogc @safe";
- assert(typeid(typeof(&sqr)).toString() == delegate_str);
- assert(delegate_str.hashOf() == typeid(typeof(&sqr)).hashOf());
- assert(typeid(typeof(&sqr)).toHash() == typeid(typeof(&sqr)).hashOf());
- int g;
- alias delegate_type = typeof((int a, int b) => a + b + g);
- delegate_str = "int delegate(int, int) pure nothrow @nogc @safe";
- assert(typeid(delegate_type).toString() == delegate_str);
- assert(delegate_str.hashOf() == typeid(delegate_type).hashOf());
- assert(typeid(delegate_type).toHash() == typeid(delegate_type).hashOf());
- }
- override bool opEquals(Object o)
- {
- if (this is o)
- return true;
- auto c = cast(const TypeInfo_Delegate)o;
- return c && this.deco == c.deco;
- }
- @system unittest
- {
- double sqr(double x) { return x * x; }
- int dbl(int x) { return x + x; }
- sqr(double.init); // for coverage completeness
- dbl(int.init); // for coverage completeness
- Object obj = typeid(typeof(&sqr));
- assert(obj.opEquals(typeid(typeof(&sqr))));
- assert(typeid(typeof(&sqr)) == typeid(typeof(&sqr)));
- assert(typeid(typeof(&dbl)) != typeid(typeof(&sqr)));
- }
- override size_t getHash(scope const void* p) @trusted const
- {
- return hashOf(*cast(void delegate()*)p);
- }
- override bool equals(in void* p1, in void* p2) const
- {
- auto dg1 = *cast(void delegate()*)p1;
- auto dg2 = *cast(void delegate()*)p2;
- return dg1 == dg2;
- }
- override int compare(in void* p1, in void* p2) const
- {
- auto dg1 = *cast(void delegate()*)p1;
- auto dg2 = *cast(void delegate()*)p2;
- if (dg1 < dg2)
- return -1;
- else if (dg1 > dg2)
- return 1;
- else
- return 0;
- }
- override @property size_t tsize() nothrow pure const
- {
- alias dg = int delegate();
- return dg.sizeof;
- }
- override const(void)[] initializer() const @trusted
- {
- return (cast(void *)null)[0 .. (int delegate()).sizeof];
- }
- override @property uint flags() nothrow pure const { return 1; }
- TypeInfo next;
- string deco;
- override @property size_t talign() nothrow pure const
- {
- alias dg = int delegate();
- return dg.alignof;
- }
- version (WithArgTypes) override int argTypes(out TypeInfo arg1, out TypeInfo arg2)
- {
- arg1 = typeid(void*);
- arg2 = typeid(void*);
- return 0;
- }
- override @property immutable(void)* rtInfo() nothrow pure const @safe { return RTInfo!(int delegate()); }
- }
- private extern (C) Object _d_newclass(const TypeInfo_Class ci);
- private extern (C) int _d_isbaseof(scope TypeInfo_Class child,
- scope const TypeInfo_Class parent) @nogc nothrow pure @safe; // rt.cast_
- /**
- * Runtime type information about a class.
- * Can be retrieved from an object instance by using the
- * $(DDSUBLINK spec/expression,typeid_expressions,typeid expression).
- */
- class TypeInfo_Class : TypeInfo
- {
- override string toString() const pure { return name; }
- override bool opEquals(const TypeInfo o) const
- {
- if (this is o)
- return true;
- auto c = cast(const TypeInfo_Class)o;
- return c && this.name == c.name;
- }
- override size_t getHash(scope const void* p) @trusted const
- {
- auto o = *cast(Object*)p;
- return o ? o.toHash() : 0;
- }
- override bool equals(in void* p1, in void* p2) const
- {
- Object o1 = *cast(Object*)p1;
- Object o2 = *cast(Object*)p2;
- return (o1 is o2) || (o1 && o1.opEquals(o2));
- }
- override int compare(in void* p1, in void* p2) const
- {
- Object o1 = *cast(Object*)p1;
- Object o2 = *cast(Object*)p2;
- int c = 0;
- // Regard null references as always being "less than"
- if (o1 !is o2)
- {
- if (o1)
- {
- if (!o2)
- c = 1;
- else
- c = o1.opCmp(o2);
- }
- else
- c = -1;
- }
- return c;
- }
- override @property size_t tsize() nothrow pure const
- {
- return Object.sizeof;
- }
- override const(void)[] initializer() nothrow pure const @safe
- {
- return m_init;
- }
- override @property uint flags() nothrow pure const { return 1; }
- override @property const(OffsetTypeInfo)[] offTi() nothrow pure const
- {
- return m_offTi;
- }
- final @property auto info() @safe @nogc nothrow pure const return { return this; }
- final @property auto typeinfo() @safe @nogc nothrow pure const return { return this; }
- byte[] m_init; /** class static initializer
- * (init.length gives size in bytes of class)
- */
- string name; /// class name
- void*[] vtbl; /// virtual function pointer table
- Interface[] interfaces; /// interfaces this class implements
- TypeInfo_Class base; /// base class
- void* destructor;
- void function(Object) classInvariant;
- enum ClassFlags : uint
- {
- isCOMclass = 0x1,
- noPointers = 0x2,
- hasOffTi = 0x4,
- hasCtor = 0x8,
- hasGetMembers = 0x10,
- hasTypeInfo = 0x20,
- isAbstract = 0x40,
- isCPPclass = 0x80,
- hasDtor = 0x100,
- }
- ClassFlags m_flags;
- void* deallocator;
- OffsetTypeInfo[] m_offTi;
- void function(Object) defaultConstructor; // default Constructor
- immutable(void)* m_RTInfo; // data for precise GC
- override @property immutable(void)* rtInfo() const { return m_RTInfo; }
- /**
- * Search all modules for TypeInfo_Class corresponding to classname.
- * Returns: null if not found
- */
- static const(TypeInfo_Class) find(const scope char[] classname)
- {
- foreach (m; ModuleInfo)
- {
- if (m)
- {
- //writefln("module %s, %d", m.name, m.localClasses.length);
- foreach (c; m.localClasses)
- {
- if (c is null)
- continue;
- //writefln("\tclass %s", c.name);
- if (c.name == classname)
- return c;
- }
- }
- }
- return null;
- }
- /**
- * Create instance of Object represented by 'this'.
- */
- Object create() const
- {
- if (m_flags & 8 && !defaultConstructor)
- return null;
- if (m_flags & 64) // abstract
- return null;
- Object o = _d_newclass(this);
- if (m_flags & 8 && defaultConstructor)
- {
- defaultConstructor(o);
- }
- return o;
- }
- /**
- * Returns true if the class described by `child` derives from or is
- * the class described by this `TypeInfo_Class`. Always returns false
- * if the argument is null.
- *
- * Params:
- * child = TypeInfo for some class
- * Returns:
- * true if the class described by `child` derives from or is the
- * class described by this `TypeInfo_Class`.
- */
- final bool isBaseOf(scope const TypeInfo_Class child) const @nogc nothrow pure @trusted
- {
- if (m_init.length)
- {
- // If this TypeInfo_Class represents an actual class we only need
- // to check the child and its direct ancestors.
- for (auto ti = cast() child; ti !is null; ti = ti.base)
- if (ti is this)
- return true;
- return false;
- }
- else
- {
- // If this TypeInfo_Class is the .info field of a TypeInfo_Interface
- // we also need to recursively check the child's interfaces.
- return child !is null && _d_isbaseof(cast() child, this);
- }
- }
- }
- alias ClassInfo = TypeInfo_Class;
- @safe unittest
- {
- // Bugzilla 14401
- static class X
- {
- int a;
- }
- assert(typeid(X).initializer is typeid(X).m_init);
- assert(typeid(X).initializer.length == typeid(const(X)).initializer.length);
- assert(typeid(X).initializer.length == typeid(shared(X)).initializer.length);
- assert(typeid(X).initializer.length == typeid(immutable(X)).initializer.length);
- }
- class TypeInfo_Interface : TypeInfo
- {
- override string toString() const pure { return info.name; }
- override bool opEquals(Object o)
- {
- if (this is o)
- return true;
- auto c = cast(const TypeInfo_Interface)o;
- return c && this.info.name == typeid(c).name;
- }
- override size_t getHash(scope const void* p) @trusted const
- {
- if (!*cast(void**)p)
- {
- return 0;
- }
- Interface* pi = **cast(Interface ***)*cast(void**)p;
- Object o = cast(Object)(*cast(void**)p - pi.offset);
- assert(o);
- return o.toHash();
- }
- override bool equals(in void* p1, in void* p2) const
- {
- Interface* pi = **cast(Interface ***)*cast(void**)p1;
- Object o1 = cast(Object)(*cast(void**)p1 - pi.offset);
- pi = **cast(Interface ***)*cast(void**)p2;
- Object o2 = cast(Object)(*cast(void**)p2 - pi.offset);
- return o1 == o2 || (o1 && o1.opCmp(o2) == 0);
- }
- override int compare(in void* p1, in void* p2) const
- {
- Interface* pi = **cast(Interface ***)*cast(void**)p1;
- Object o1 = cast(Object)(*cast(void**)p1 - pi.offset);
- pi = **cast(Interface ***)*cast(void**)p2;
- Object o2 = cast(Object)(*cast(void**)p2 - pi.offset);
- int c = 0;
- // Regard null references as always being "less than"
- if (o1 != o2)
- {
- if (o1)
- {
- if (!o2)
- c = 1;
- else
- c = o1.opCmp(o2);
- }
- else
- c = -1;
- }
- return c;
- }
- override @property size_t tsize() nothrow pure const
- {
- return Object.sizeof;
- }
- override const(void)[] initializer() const @trusted
- {
- return (cast(void *)null)[0 .. Object.sizeof];
- }
- override @property uint flags() nothrow pure const { return 1; }
- TypeInfo_Class info;
- /**
- * Returns true if the class described by `child` derives from the
- * interface described by this `TypeInfo_Interface`. Always returns
- * false if the argument is null.
- *
- * Params:
- * child = TypeInfo for some class
- * Returns:
- * true if the class described by `child` derives from the
- * interface described by this `TypeInfo_Interface`.
- */
- final bool isBaseOf(scope const TypeInfo_Class child) const @nogc nothrow pure @trusted
- {
- return child !is null && _d_isbaseof(cast() child, this.info);
- }
- /**
- * Returns true if the interface described by `child` derives from
- * or is the interface described by this `TypeInfo_Interface`.
- * Always returns false if the argument is null.
- *
- * Params:
- * child = TypeInfo for some interface
- * Returns:
- * true if the interface described by `child` derives from or is
- * the interface described by this `TypeInfo_Interface`.
- */
- final bool isBaseOf(scope const TypeInfo_Interface child) const @nogc nothrow pure @trusted
- {
- return child !is null && _d_isbaseof(cast() child.info, this.info);
- }
- }
- @safe unittest
- {
- enum unittest_sym_name = __traits(identifier, __traits(parent, (){}));
- enum fqn_unittest = "object." ~ unittest_sym_name; // object.__unittest_LX_CY
- interface I {}
- assert(fqn_unittest ~ ".I" == typeid(I).info.name);
- assert((fqn_unittest ~ ".I").hashOf() == typeid(I).hashOf());
- assert(typeid(I).toHash() == typeid(I).hashOf());
- }
- class TypeInfo_Struct : TypeInfo
- {
- override string toString() const { return name; }
- override size_t toHash() const
- {
- return hashOf(this.mangledName);
- }
- override bool opEquals(Object o)
- {
- if (this is o)
- return true;
- auto s = cast(const TypeInfo_Struct)o;
- return s && this.mangledName == s.mangledName;
- }
- override size_t getHash(scope const void* p) @trusted pure nothrow const
- {
- assert(p);
- if (xtoHash)
- {
- return (*xtoHash)(p);
- }
- else
- {
- return hashOf(p[0 .. initializer().length]);
- }
- }
- override bool equals(in void* p1, in void* p2) @trusted pure nothrow const
- {
- import core.stdc.string : memcmp;
- if (!p1 || !p2)
- return false;
- else if (xopEquals)
- {
- const dg = _memberFunc(p1, xopEquals);
- return dg.xopEquals(p2);
- }
- else if (p1 == p2)
- return true;
- else
- // BUG: relies on the GC not moving objects
- return memcmp(p1, p2, initializer().length) == 0;
- }
- override int compare(in void* p1, in void* p2) @trusted pure nothrow const
- {
- import core.stdc.string : memcmp;
- // Regard null references as always being "less than"
- if (p1 != p2)
- {
- if (p1)
- {
- if (!p2)
- return true;
- else if (xopCmp)
- {
- const dg = _memberFunc(p1, xopCmp);
- return dg.xopCmp(p2);
- }
- else
- // BUG: relies on the GC not moving objects
- return memcmp(p1, p2, initializer().length);
- }
- else
- return -1;
- }
- return 0;
- }
- override @property size_t tsize() nothrow pure const
- {
- return initializer().length;
- }
- override const(void)[] initializer() nothrow pure const @safe
- {
- return m_init;
- }
- override @property uint flags() nothrow pure const { return m_flags; }
- override @property size_t talign() nothrow pure const { return m_align; }
- final override void destroy(void* p) const
- {
- if (xdtor)
- {
- if (m_flags & StructFlags.isDynamicType)
- (*xdtorti)(p, this);
- else
- (*xdtor)(p);
- }
- }
- override void postblit(void* p) const
- {
- if (xpostblit)
- (*xpostblit)(p);
- }
- string mangledName;
- final @property string name() nothrow const @trusted
- {
- import core.demangle : demangleType;
- if (mangledName is null) // e.g., opaque structs
- return null;
- const key = cast(const void*) this; // faster lookup than TypeInfo_Struct, at the cost of potential duplicates per binary
- static string[typeof(key)] demangledNamesCache; // per thread
- // not nothrow:
- //return demangledNamesCache.require(key, cast(string) demangleType(mangledName));
- if (auto pDemangled = key in demangledNamesCache)
- return *pDemangled;
- const demangled = cast(string) demangleType(mangledName);
- demangledNamesCache[key] = demangled;
- return demangled;
- }
- void[] m_init; // initializer; m_init.ptr == null if 0 initialize
- @safe pure nothrow
- {
- size_t function(in void*) xtoHash;
- bool function(in void*, in void*) xopEquals;
- int function(in void*, in void*) xopCmp;
- string function(in void*) xtoString;
- enum StructFlags : uint
- {
- hasPointers = 0x1,
- isDynamicType = 0x2, // built at runtime, needs type info in xdtor
- }
- StructFlags m_flags;
- }
- union
- {
- void function(void*) xdtor;
- void function(void*, const TypeInfo_Struct ti) xdtorti;
- }
- void function(void*) xpostblit;
- uint m_align;
- override @property immutable(void)* rtInfo() nothrow pure const @safe { return m_RTInfo; }
- version (WithArgTypes)
- {
- override int argTypes(out TypeInfo arg1, out TypeInfo arg2)
- {
- arg1 = m_arg1;
- arg2 = m_arg2;
- return 0;
- }
- TypeInfo m_arg1;
- TypeInfo m_arg2;
- }
- immutable(void)* m_RTInfo; // data for precise GC
- // The xopEquals and xopCmp members are function pointers to member
- // functions, which is not guaranteed to share the same ABI, as it is not
- // known whether the `this` parameter is the first or second argument.
- // This wrapper is to convert it to a delegate which will always pass the
- // `this` parameter in the correct way.
- private struct _memberFunc
- {
- union
- {
- struct // delegate
- {
- const void* ptr;
- const void* funcptr;
- }
- @safe pure nothrow
- {
- bool delegate(in void*) xopEquals;
- int delegate(in void*) xopCmp;
- }
- }
- }
- }
- @system unittest
- {
- struct S
- {
- bool opEquals(ref const S rhs) const
- {
- return false;
- }
- }
- S s;
- assert(!typeid(S).equals(&s, &s));
- }
- class TypeInfo_Tuple : TypeInfo
- {
- TypeInfo[] elements;
- override string toString() const
- {
- string s = "(";
- foreach (i, element; elements)
- {
- if (i)
- s ~= ',';
- s ~= element.toString();
- }
- s ~= ")";
- return s;
- }
- override bool opEquals(Object o)
- {
- if (this is o)
- return true;
- auto t = cast(const TypeInfo_Tuple)o;
- if (t && elements.length == t.elements.length)
- {
- for (size_t i = 0; i < elements.length; i++)
- {
- if (elements[i] != t.elements[i])
- return false;
- }
- return true;
- }
- return false;
- }
- override size_t getHash(scope const void* p) const
- {
- assert(0);
- }
- override bool equals(in void* p1, in void* p2) const
- {
- assert(0);
- }
- override int compare(in void* p1, in void* p2) const
- {
- assert(0);
- }
- override @property size_t tsize() nothrow pure const
- {
- assert(0);
- }
- override const(void)[] initializer() const @trusted
- {
- assert(0);
- }
- override void swap(void* p1, void* p2) const
- {
- assert(0);
- }
- override void destroy(void* p) const
- {
- assert(0);
- }
- override void postblit(void* p) const
- {
- assert(0);
- }
- override @property size_t talign() nothrow pure const
- {
- assert(0);
- }
- version (WithArgTypes) override int argTypes(out TypeInfo arg1, out TypeInfo arg2)
- {
- assert(0);
- }
- }
- class TypeInfo_Const : TypeInfo
- {
- override string toString() const
- {
- return cast(string) ("const(" ~ base.toString() ~ ")");
- }
- //override bool opEquals(Object o) { return base.opEquals(o); }
- override bool opEquals(Object o)
- {
- if (this is o)
- return true;
- if (typeid(this) != typeid(o))
- return false;
- auto t = cast(TypeInfo_Const)o;
- return base.opEquals(t.base);
- }
- override size_t getHash(scope const void *p) const { return base.getHash(p); }
- override bool equals(in void *p1, in void *p2) const { return base.equals(p1, p2); }
- override int compare(in void *p1, in void *p2) const { return base.compare(p1, p2); }
- override @property size_t tsize() nothrow pure const { return base.tsize; }
- override void swap(void *p1, void *p2) const { return base.swap(p1, p2); }
- override @property inout(TypeInfo) next() nothrow pure inout { return base.next; }
- override @property uint flags() nothrow pure const { return base.flags; }
- override const(void)[] initializer() nothrow pure const
- {
- return base.initializer();
- }
- override @property size_t talign() nothrow pure const { return base.talign; }
- version (WithArgTypes) override int argTypes(out TypeInfo arg1, out TypeInfo arg2)
- {
- return base.argTypes(arg1, arg2);
- }
- TypeInfo base;
- }
- class TypeInfo_Invariant : TypeInfo_Const
- {
- override string toString() const
- {
- return cast(string) ("immutable(" ~ base.toString() ~ ")");
- }
- }
- class TypeInfo_Shared : TypeInfo_Const
- {
- override string toString() const
- {
- return cast(string) ("shared(" ~ base.toString() ~ ")");
- }
- }
- class TypeInfo_Inout : TypeInfo_Const
- {
- override string toString() const
- {
- return cast(string) ("inout(" ~ base.toString() ~ ")");
- }
- }
- // Contents of Moduleinfo._flags
- enum
- {
- MIctorstart = 0x1, // we've started constructing it
- MIctordone = 0x2, // finished construction
- MIstandalone = 0x4, // module ctor does not depend on other module
- // ctors being done first
- MItlsctor = 8,
- MItlsdtor = 0x10,
- MIctor = 0x20,
- MIdtor = 0x40,
- MIxgetMembers = 0x80,
- MIictor = 0x100,
- MIunitTest = 0x200,
- MIimportedModules = 0x400,
- MIlocalClasses = 0x800,
- MIname = 0x1000,
- }
- /*****************************************
- * An instance of ModuleInfo is generated into the object file for each compiled module.
- *
- * It provides access to various aspects of the module.
- * It is not generated for betterC.
- */
- struct ModuleInfo
- {
- uint _flags; // MIxxxx
- uint _index; // index into _moduleinfo_array[]
- version (all)
- {
- deprecated("ModuleInfo cannot be copy-assigned because it is a variable-sized struct.")
- void opAssign(const scope ModuleInfo m) { _flags = m._flags; _index = m._index; }
- }
- else
- {
- @disable this();
- }
- const:
- private void* addrOf(int flag) return nothrow pure @nogc
- in
- {
- assert(flag >= MItlsctor && flag <= MIname);
- assert(!(flag & (flag - 1)) && !(flag & ~(flag - 1) << 1));
- }
- do
- {
- import core.stdc.string : strlen;
- void* p = cast(void*)&this + ModuleInfo.sizeof;
- if (flags & MItlsctor)
- {
- if (flag == MItlsctor) return p;
- p += typeof(tlsctor).sizeof;
- }
- if (flags & MItlsdtor)
- {
- if (flag == MItlsdtor) return p;
- p += typeof(tlsdtor).sizeof;
- }
- if (flags & MIctor)
- {
- if (flag == MIctor) return p;
- p += typeof(ctor).sizeof;
- }
- if (flags & MIdtor)
- {
- if (flag == MIdtor) return p;
- p += typeof(dtor).sizeof;
- }
- if (flags & MIxgetMembers)
- {
- if (flag == MIxgetMembers) return p;
- p += typeof(xgetMembers).sizeof;
- }
- if (flags & MIictor)
- {
- if (flag == MIictor) return p;
- p += typeof(ictor).sizeof;
- }
- if (flags & MIunitTest)
- {
- if (flag == MIunitTest) return p;
- p += typeof(unitTest).sizeof;
- }
- if (flags & MIimportedModules)
- {
- if (flag == MIimportedModules) return p;
- p += size_t.sizeof + *cast(size_t*)p * typeof(importedModules[0]).sizeof;
- }
- if (flags & MIlocalClasses)
- {
- if (flag == MIlocalClasses) return p;
- p += size_t.sizeof + *cast(size_t*)p * typeof(localClasses[0]).sizeof;
- }
- if (true || flags & MIname) // always available for now
- {
- if (flag == MIname) return p;
- p += strlen(cast(immutable char*)p);
- }
- assert(0);
- }
- @property uint index() nothrow pure @nogc { return _index; }
- @property uint flags() nothrow pure @nogc { return _flags; }
- /************************
- * Returns:
- * module constructor for thread locals, `null` if there isn't one
- */
- @property void function() tlsctor() nothrow pure @nogc
- {
- return flags & MItlsctor ? *cast(typeof(return)*)addrOf(MItlsctor) : null;
- }
- /************************
- * Returns:
- * module destructor for thread locals, `null` if there isn't one
- */
- @property void function() tlsdtor() nothrow pure @nogc
- {
- return flags & MItlsdtor ? *cast(typeof(return)*)addrOf(MItlsdtor) : null;
- }
- /*****************************
- * Returns:
- * address of a module's `const(MemberInfo)[] getMembers(string)` function, `null` if there isn't one
- */
- @property void* xgetMembers() nothrow pure @nogc
- {
- return flags & MIxgetMembers ? *cast(typeof(return)*)addrOf(MIxgetMembers) : null;
- }
- /************************
- * Returns:
- * module constructor, `null` if there isn't one
- */
- @property void function() ctor() nothrow pure @nogc
- {
- return flags & MIctor ? *cast(typeof(return)*)addrOf(MIctor) : null;
- }
- /************************
- * Returns:
- * module destructor, `null` if there isn't one
- */
- @property void function() dtor() nothrow pure @nogc
- {
- return flags & MIdtor ? *cast(typeof(return)*)addrOf(MIdtor) : null;
- }
- /************************
- * Returns:
- * module order independent constructor, `null` if there isn't one
- */
- @property void function() ictor() nothrow pure @nogc
- {
- return flags & MIictor ? *cast(typeof(return)*)addrOf(MIictor) : null;
- }
- /*************
- * Returns:
- * address of function that runs the module's unittests, `null` if there isn't one
- */
- @property void function() unitTest() nothrow pure @nogc
- {
- return flags & MIunitTest ? *cast(typeof(return)*)addrOf(MIunitTest) : null;
- }
- /****************
- * Returns:
- * array of pointers to the ModuleInfo's of modules imported by this one
- */
- @property immutable(ModuleInfo*)[] importedModules() return nothrow pure @nogc
- {
- if (flags & MIimportedModules)
- {
- auto p = cast(size_t*)addrOf(MIimportedModules);
- return (cast(immutable(ModuleInfo*)*)(p + 1))[0 .. *p];
- }
- return null;
- }
- /****************
- * Returns:
- * array of TypeInfo_Class references for classes defined in this module
- */
- @property TypeInfo_Class[] localClasses() return nothrow pure @nogc
- {
- if (flags & MIlocalClasses)
- {
- auto p = cast(size_t*)addrOf(MIlocalClasses);
- return (cast(TypeInfo_Class*)(p + 1))[0 .. *p];
- }
- return null;
- }
- /********************
- * Returns:
- * name of module, `null` if no name
- */
- @property string name() return nothrow pure @nogc
- {
- import core.stdc.string : strlen;
- auto p = cast(immutable char*) addrOf(MIname);
- return p[0 .. strlen(p)];
- }
- static int opApply(scope int delegate(ModuleInfo*) dg)
- {
- import core.internal.traits : externDFunc;
- alias moduleinfos_apply = externDFunc!("rt.minfo.moduleinfos_apply",
- int function(scope int delegate(immutable(ModuleInfo*))));
- // Bugzilla 13084 - enforcing immutable ModuleInfo would break client code
- return moduleinfos_apply(
- (immutable(ModuleInfo*)m) => dg(cast(ModuleInfo*)m));
- }
- }
- @system unittest
- {
- ModuleInfo* m1;
- foreach (m; ModuleInfo)
- {
- m1 = m;
- }
- }
- ///////////////////////////////////////////////////////////////////////////////
- // Throwable
- ///////////////////////////////////////////////////////////////////////////////
- /**
- * The base class of all thrown objects.
- *
- * All thrown objects must inherit from Throwable. Class $(D Exception), which
- * derives from this class, represents the category of thrown objects that are
- * safe to catch and handle. In principle, one should not catch Throwable
- * objects that are not derived from $(D Exception), as they represent
- * unrecoverable runtime errors. Certain runtime guarantees may fail to hold
- * when these errors are thrown, making it unsafe to continue execution after
- * catching them.
- */
- class Throwable : Object
- {
- interface TraceInfo
- {
- int opApply(scope int delegate(ref const(char[]))) const;
- int opApply(scope int delegate(ref size_t, ref const(char[]))) const;
- string toString() const;
- }
- string msg; /// A message describing the error.
- /**
- * The _file name of the D source code corresponding with
- * where the error was thrown from.
- */
- string file;
- /**
- * The _line number of the D source code corresponding with
- * where the error was thrown from.
- */
- size_t line;
- /**
- * The stack trace of where the error happened. This is an opaque object
- * that can either be converted to $(D string), or iterated over with $(D
- * foreach) to extract the items in the stack trace (as strings).
- */
- TraceInfo info;
- /**
- * A reference to the _next error in the list. This is used when a new
- * $(D Throwable) is thrown from inside a $(D catch) block. The originally
- * caught $(D Exception) will be chained to the new $(D Throwable) via this
- * field.
- */
- private Throwable nextInChain;
- private uint _refcount; // 0 : allocated by GC
- // 1 : allocated by _d_newThrowable()
- // 2.. : reference count + 1
- /**
- * Returns:
- * A reference to the _next error in the list. This is used when a new
- * $(D Throwable) is thrown from inside a $(D catch) block. The originally
- * caught $(D Exception) will be chained to the new $(D Throwable) via this
- * field.
- */
- @property inout(Throwable) next() @safe inout return scope pure nothrow @nogc { return nextInChain; }
- /**
- * Replace next in chain with `tail`.
- * Use `chainTogether` instead if at all possible.
- */
- @property void next(Throwable tail) @safe scope pure nothrow @nogc
- {
- if (tail && tail._refcount)
- ++tail._refcount; // increment the replacement *first*
- auto n = nextInChain;
- nextInChain = null; // sever the tail before deleting it
- if (n && n._refcount)
- _d_delThrowable(n); // now delete the old tail
- nextInChain = tail; // and set the new tail
- }
- /**
- * Returns:
- * mutable reference to the reference count, which is
- * 0 - allocated by the GC, 1 - allocated by _d_newThrowable(),
- * and >=2 which is the reference count + 1
- * Note:
- * Marked as `@system` to discourage casual use of it.
- */
- @system @nogc final pure nothrow ref uint refcount() return { return _refcount; }
- /**
- * Loop over the chain of Throwables.
- */
- int opApply(scope int delegate(Throwable) dg)
- {
- int result = 0;
- for (Throwable t = this; t; t = t.nextInChain)
- {
- result = dg(t);
- if (result)
- break;
- }
- return result;
- }
- /**
- * Append `e2` to chain of exceptions that starts with `e1`.
- * Params:
- * e1 = start of chain (can be null)
- * e2 = second part of chain (can be null)
- * Returns:
- * Throwable that is at the start of the chain; null if both `e1` and `e2` are null
- */
- static @__future @system @nogc pure nothrow Throwable chainTogether(return scope Throwable e1, return scope Throwable e2)
- {
- if (!e1)
- return e2;
- if (!e2)
- return e1;
- if (e2.refcount())
- ++e2.refcount();
- for (auto e = e1; 1; e = e.nextInChain)
- {
- if (!e.nextInChain)
- {
- e.nextInChain = e2;
- break;
- }
- }
- return e1;
- }
- @nogc @safe pure nothrow this(string msg, Throwable nextInChain = null)
- {
- this.msg = msg;
- this.nextInChain = nextInChain;
- if (nextInChain && nextInChain._refcount)
- ++nextInChain._refcount;
- //this.info = _d_traceContext();
- }
- @nogc @safe pure nothrow this(string msg, string file, size_t line, Throwable nextInChain = null)
- {
- this(msg, nextInChain);
- this.file = file;
- this.line = line;
- //this.info = _d_traceContext();
- }
- @trusted nothrow ~this()
- {
- if (nextInChain && nextInChain._refcount)
- _d_delThrowable(nextInChain);
- }
- /**
- * Overrides $(D Object.toString) and returns the error message.
- * Internally this forwards to the $(D toString) overload that
- * takes a $(D_PARAM sink) delegate.
- */
- override string toString()
- {
- string s;
- toString((in buf) { s ~= buf; });
- return s;
- }
- /**
- * The Throwable hierarchy uses a toString overload that takes a
- * $(D_PARAM _sink) delegate to avoid GC allocations, which cannot be
- * performed in certain error situations. Override this $(D
- * toString) method to customize the error message.
- */
- void toString(scope void delegate(in char[]) sink) const
- {
- import core.internal.string : unsignedToTempString;
- char[20] tmpBuff = void;
- sink(typeid(this).name);
- sink("@"); sink(file);
- sink("("); sink(unsignedToTempString(line, tmpBuff)); sink(")");
- if (msg.length)
- {
- sink(": "); sink(msg);
- }
- if (info)
- {
- try
- {
- sink("\n----------------");
- foreach (t; info)
- {
- sink("\n"); sink(t);
- }
- }
- catch (Throwable)
- {
- // ignore more errors
- }
- }
- }
- /**
- * Get the message describing the error.
- *
- * This getter is an alternative way to access the Exception's message,
- * with the added advantage of being override-able in subclasses.
- * Subclasses are hence free to do their own memory managements without
- * being tied to the requirement of providing a `string` in a field.
- *
- * The default behavior is to return the `Throwable.msg` field.
- *
- * Returns:
- * A message representing the cause of the `Throwable`
- */
- @__future const(char)[] message() const @safe nothrow
- {
- return this.msg;
- }
- }
- /**
- * The base class of all errors that are safe to catch and handle.
- *
- * In principle, only thrown objects derived from this class are safe to catch
- * inside a $(D catch) block. Thrown objects not derived from Exception
- * represent runtime errors that should not be caught, as certain runtime
- * guarantees may not hold, making it unsafe to continue program execution.
- */
- class Exception : Throwable
- {
- /**
- * Creates a new instance of Exception. The nextInChain parameter is used
- * internally and should always be $(D null) when passed by user code.
- * This constructor does not automatically throw the newly-created
- * Exception; the $(D throw) statement should be used for that purpose.
- */
- @nogc @safe pure nothrow this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable nextInChain = null)
- {
- super(msg, file, line, nextInChain);
- }
- @nogc @safe pure nothrow this(string msg, Throwable nextInChain, string file = __FILE__, size_t line = __LINE__)
- {
- super(msg, file, line, nextInChain);
- }
- }
- ///
- @safe unittest
- {
- bool gotCaught;
- try
- {
- throw new Exception("msg");
- }
- catch (Exception e)
- {
- gotCaught = true;
- assert(e.msg == "msg");
- }
- assert(gotCaught);
- }
- @system unittest
- {
- {
- auto e = new Exception("msg");
- assert(e.file == __FILE__);
- assert(e.line == __LINE__ - 2);
- assert(e.nextInChain is null);
- assert(e.msg == "msg");
- }
- {
- auto e = new Exception("msg", new Exception("It's an Exception!"), "hello", 42);
- assert(e.file == "hello");
- assert(e.line == 42);
- assert(e.nextInChain !is null);
- assert(e.msg == "msg");
- }
- {
- auto e = new Exception("msg", "hello", 42, new Exception("It's an Exception!"));
- assert(e.file == "hello");
- assert(e.line == 42);
- assert(e.nextInChain !is null);
- assert(e.msg == "msg");
- }
- {
- auto e = new Exception("message");
- assert(e.message == "message");
- }
- }
- /**
- * The base class of all unrecoverable runtime errors.
- *
- * This represents the category of $(D Throwable) objects that are $(B not)
- * safe to catch and handle. In principle, one should not catch Error
- * objects, as they represent unrecoverable runtime errors.
- * Certain runtime guarantees may fail to hold when these errors are
- * thrown, making it unsafe to continue execution after catching them.
- */
- class Error : Throwable
- {
- /**
- * Creates a new instance of Error. The nextInChain parameter is used
- * internally and should always be $(D null) when passed by user code.
- * This constructor does not automatically throw the newly-created
- * Error; the $(D throw) statement should be used for that purpose.
- */
- @nogc @safe pure nothrow this(string msg, Throwable nextInChain = null)
- {
- super(msg, nextInChain);
- bypassedException = null;
- }
- @nogc @safe pure nothrow this(string msg, string file, size_t line, Throwable nextInChain = null)
- {
- super(msg, file, line, nextInChain);
- bypassedException = null;
- }
- /** The first $(D Exception) which was bypassed when this Error was thrown,
- or $(D null) if no $(D Exception)s were pending. */
- Throwable bypassedException;
- }
- ///
- @system unittest
- {
- bool gotCaught;
- try
- {
- throw new Error("msg");
- }
- catch (Error e)
- {
- gotCaught = true;
- assert(e.msg == "msg");
- }
- assert(gotCaught);
- }
- @safe unittest
- {
- {
- auto e = new Error("msg");
- assert(e.file is null);
- assert(e.line == 0);
- assert(e.nextInChain is null);
- assert(e.msg == "msg");
- assert(e.bypassedException is null);
- }
- {
- auto e = new Error("msg", new Exception("It's an Exception!"));
- assert(e.file is null);
- assert(e.line == 0);
- assert(e.nextInChain !is null);
- assert(e.msg == "msg");
- assert(e.bypassedException is null);
- }
- {
- auto e = new Error("msg", "hello", 42, new Exception("It's an Exception!"));
- assert(e.file == "hello");
- assert(e.line == 42);
- assert(e.nextInChain !is null);
- assert(e.msg == "msg");
- assert(e.bypassedException is null);
- }
- }
- extern (C)
- {
- // from druntime/src/rt/aaA.d
- private struct AA { void* impl; }
- // size_t _aaLen(in AA aa) pure nothrow @nogc;
- private void* _aaGetY(AA* paa, const TypeInfo_AssociativeArray ti, const size_t valsz, const scope void* pkey) pure nothrow;
- private void* _aaGetX(AA* paa, const TypeInfo_AssociativeArray ti, const size_t valsz, const scope void* pkey, out bool found) pure nothrow;
- // inout(void)* _aaGetRvalueX(inout AA aa, in TypeInfo keyti, in size_t valsz, in void* pkey);
- inout(void[]) _aaValues(inout AA aa, const size_t keysz, const size_t valsz, const TypeInfo tiValueArray) pure nothrow;
- inout(void[]) _aaKeys(inout AA aa, const size_t keysz, const TypeInfo tiKeyArray) pure nothrow;
- void* _aaRehash(AA* paa, const scope TypeInfo keyti) pure nothrow;
- void _aaClear(AA aa) pure nothrow;
- // alias _dg_t = extern(D) int delegate(void*);
- // int _aaApply(AA aa, size_t keysize, _dg_t dg);
- // alias _dg2_t = extern(D) int delegate(void*, void*);
- // int _aaApply2(AA aa, size_t keysize, _dg2_t dg);
- private struct AARange { AA impl; size_t idx; }
- AARange _aaRange(AA aa) pure nothrow @nogc @safe;
- bool _aaRangeEmpty(AARange r) pure nothrow @nogc @safe;
- void* _aaRangeFrontKey(AARange r) pure nothrow @nogc @safe;
- void* _aaRangeFrontValue(AARange r) pure nothrow @nogc @safe;
- void _aaRangePopFront(ref AARange r) pure nothrow @nogc @safe;
- int _aaEqual(scope const TypeInfo tiRaw, scope const AA aa1, scope const AA aa2);
- hash_t _aaGetHash(scope const AA* aa, scope const TypeInfo tiRaw) nothrow;
- /*
- _d_assocarrayliteralTX marked as pure, because aaLiteral can be called from pure code.
- This is a typesystem hole, however this is existing hole.
- Early compiler didn't check purity of toHash or postblit functions, if key is a UDT thus
- copiler allowed to create AA literal with keys, which have impure unsafe toHash methods.
- */
- void* _d_assocarrayliteralTX(const TypeInfo_AssociativeArray ti, void[] keys, void[] values) pure;
- }
- void* aaLiteral(Key, Value)(Key[] keys, Value[] values) @trusted pure
- {
- return _d_assocarrayliteralTX(typeid(Value[Key]), *cast(void[]*)&keys, *cast(void[]*)&values);
- }
- alias AssociativeArray(Key, Value) = Value[Key];
- /***********************************
- * Removes all remaining keys and values from an associative array.
- * Params:
- * aa = The associative array.
- */
- void clear(Value, Key)(Value[Key] aa)
- {
- _aaClear(*cast(AA *) &aa);
- }
- /** ditto */
- void clear(Value, Key)(Value[Key]* aa)
- {
- _aaClear(*cast(AA *) aa);
- }
- ///
- @system unittest
- {
- auto aa = ["k1": 2];
- aa.clear;
- assert("k1" !in aa);
- }
- // Issue 20559
- @system unittest
- {
- static class Foo
- {
- int[string] aa;
- alias aa this;
- }
- auto v = new Foo();
- v["Hello World"] = 42;
- v.clear;
- assert("Hello World" !in v);
- // Test for T*
- static assert(!__traits(compiles, (&v).clear));
- static assert( __traits(compiles, (*(&v)).clear));
- }
- /***********************************
- * Reorganizes the associative array in place so that lookups are more
- * efficient.
- * Params:
- * aa = The associative array.
- * Returns:
- * The rehashed associative array.
- */
- T rehash(T : Value[Key], Value, Key)(T aa)
- {
- _aaRehash(cast(AA*)&aa, typeid(Value[Key]));
- return aa;
- }
- /** ditto */
- T rehash(T : Value[Key], Value, Key)(T* aa)
- {
- _aaRehash(cast(AA*)aa, typeid(Value[Key]));
- return *aa;
- }
- /** ditto */
- T rehash(T : shared Value[Key], Value, Key)(T aa)
- {
- _aaRehash(cast(AA*)&aa, typeid(Value[Key]));
- return aa;
- }
- /** ditto */
- T rehash(T : shared Value[Key], Value, Key)(T* aa)
- {
- _aaRehash(cast(AA*)aa, typeid(Value[Key]));
- return *aa;
- }
- /***********************************
- * Creates a new associative array of the same size and copies the contents of
- * the associative array into it.
- * Params:
- * aa = The associative array.
- */
- V[K] dup(T : V[K], K, V)(T aa)
- {
- //pragma(msg, "K = ", K, ", V = ", V);
- // Bug10720 - check whether V is copyable
- static assert(is(typeof({ V v = aa[K.init]; })),
- "cannot call " ~ T.stringof ~ ".dup because " ~ V.stringof ~ " is not copyable");
- V[K] result;
- //foreach (k, ref v; aa)
- // result[k] = v; // Bug13701 - won't work if V is not mutable
- ref V duplicateElem(ref K k, ref const V v) @trusted pure nothrow
- {
- import core.stdc.string : memcpy;
- void* pv = _aaGetY(cast(AA*)&result, typeid(V[K]), V.sizeof, &k);
- memcpy(pv, &v, V.sizeof);
- return *cast(V*)pv;
- }
- foreach (k, ref v; aa)
- {
- static if (!__traits(hasPostblit, V))
- duplicateElem(k, v);
- else static if (__traits(isStaticArray, V))
- _doPostblit(duplicateElem(k, v)[]);
- else static if (!is(typeof(v.__xpostblit())) && is(immutable V == immutable UV, UV))
- (() @trusted => *cast(UV*) &duplicateElem(k, v))().__xpostblit();
- else
- duplicateElem(k, v).__xpostblit();
- }
- return result;
- }
- /** ditto */
- V[K] dup(T : V[K], K, V)(T* aa)
- {
- return (*aa).dup;
- }
- ///
- @safe unittest
- {
- auto aa = ["k1": 2];
- auto a2 = aa.dup;
- aa["k2"] = 3;
- assert("k2" !in a2);
- }
- // this should never be made public.
- private AARange _aaToRange(T: V[K], K, V)(ref T aa) pure nothrow @nogc @safe
- {
- // ensure we are dealing with a genuine AA.
- static if (is(const(V[K]) == const(T)))
- alias realAA = aa;
- else
- const(V[K]) realAA = aa;
- return _aaRange(() @trusted { return *cast(AA*)&realAA; } ());
- }
- /***********************************
- * Returns a $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives)
- * which will iterate over the keys of the associative array. The keys are
- * returned by reference.
- *
- * If structural changes are made to the array (removing or adding keys), all
- * ranges previously obtained through this function are invalidated. The
- * following example program will dereference a null pointer:
- *
- *---
- * import std.stdio : writeln;
- *
- * auto dict = ["k1": 1, "k2": 2];
- * auto keyRange = dict.byKey;
- * dict.clear;
- * writeln(keyRange.front); // Segmentation fault
- *---
- *
- * Params:
- * aa = The associative array.
- * Returns:
- * A forward range referencing the keys of the associative array.
- */
- auto byKey(T : V[K], K, V)(T aa) pure nothrow @nogc @safe
- {
- import core.internal.traits : substInout;
- static struct Result
- {
- AARange r;
- pure nothrow @nogc:
- @property bool empty() @safe { return _aaRangeEmpty(r); }
- @property ref front() @trusted
- {
- return *cast(substInout!K*) _aaRangeFrontKey(r);
- }
- void popFront() @safe { _aaRangePopFront(r); }
- @property Result save() { return this; }
- }
- return Result(_aaToRange(aa));
- }
- /** ditto */
- auto byKey(T : V[K], K, V)(T* aa) pure nothrow @nogc
- {
- return (*aa).byKey();
- }
- ///
- @safe unittest
- {
- auto dict = [1: "v1", 2: "v2"];
- int sum;
- foreach (v; dict.byKey)
- sum += v;
- assert(sum == 3);
- }
- /***********************************
- * Returns a $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives)
- * which will iterate over the values of the associative array. The values are
- * returned by reference.
- *
- * If structural changes are made to the array (removing or adding keys), all
- * ranges previously obtained through this function are invalidated. The
- * following example program will dereference a null pointer:
- *
- *---
- * import std.stdio : writeln;
- *
- * auto dict = ["k1": 1, "k2": 2];
- * auto valueRange = dict.byValue;
- * dict.clear;
- * writeln(valueRange.front); // Segmentation fault
- *---
- *
- * Params:
- * aa = The associative array.
- * Returns:
- * A forward range referencing the values of the associative array.
- */
- auto byValue(T : V[K], K, V)(T aa) pure nothrow @nogc @safe
- {
- import core.internal.traits : substInout;
- static struct Result
- {
- AARange r;
- pure nothrow @nogc:
- @property bool empty() @safe { return _aaRangeEmpty(r); }
- @property ref front() @trusted
- {
- return *cast(substInout!V*) _aaRangeFrontValue(r);
- }
- void popFront() @safe { _aaRangePopFront(r); }
- @property Result save() { return this; }
- }
- return Result(_aaToRange(aa));
- }
- /** ditto */
- auto byValue(T : V[K], K, V)(T* aa) pure nothrow @nogc
- {
- return (*aa).byValue();
- }
- ///
- @safe unittest
- {
- auto dict = ["k1": 1, "k2": 2];
- int sum;
- foreach (v; dict.byValue)
- sum += v;
- assert(sum == 3);
- }
- /***********************************
- * Returns a $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives)
- * which will iterate over the key-value pairs of the associative array. The
- * returned pairs are represented by an opaque type with `.key` and `.value`
- * properties for accessing references to the key and value of the pair,
- * respectively.
- *
- * If structural changes are made to the array (removing or adding keys), all
- * ranges previously obtained through this function are invalidated. The
- * following example program will dereference a null pointer:
- *
- *---
- * import std.stdio : writeln;
- *
- * auto dict = ["k1": 1, "k2": 2];
- * auto kvRange = dict.byKeyValue;
- * dict.clear;
- * writeln(kvRange.front.key, ": ", kvRange.front.value); // Segmentation fault
- *---
- *
- * Note that this is a low-level interface to iterating over the associative
- * array and is not compatible withth the
- * $(LINK2 $(ROOT_DIR)phobos/std_typecons.html#.Tuple,`Tuple`) type in Phobos.
- * For compatibility with `Tuple`, use
- * $(LINK2 $(ROOT_DIR)phobos/std_array.html#.byPair,std.array.byPair) instead.
- *
- * Params:
- * aa = The associative array.
- * Returns:
- * A forward range referencing the pairs of the associative array.
- */
- auto byKeyValue(T : V[K], K, V)(T aa) pure nothrow @nogc @safe
- {
- import core.internal.traits : substInout;
- static struct Result
- {
- AARange r;
- pure nothrow @nogc:
- @property bool empty() @safe { return _aaRangeEmpty(r); }
- @property auto front()
- {
- static struct Pair
- {
- // We save the pointers here so that the Pair we return
- // won't mutate when Result.popFront is called afterwards.
- private void* keyp;
- private void* valp;
- @property ref key() inout @trusted
- {
- return *cast(substInout!K*) keyp;
- }
- @property ref value() inout @trusted
- {
- return *cast(substInout!V*) valp;
- }
- }
- return Pair(_aaRangeFrontKey(r),
- _aaRangeFrontValue(r));
- }
- void popFront() @safe { return _aaRangePopFront(r); }
- @property Result save() { return this; }
- }
- return Result(_aaToRange(aa));
- }
- /** ditto */
- auto byKeyValue(T : V[K], K, V)(T* aa) pure nothrow @nogc
- {
- return (*aa).byKeyValue();
- }
- ///
- @safe unittest
- {
- auto dict = ["k1": 1, "k2": 2];
- int sum;
- foreach (e; dict.byKeyValue)
- {
- assert(e.key[1] == e.value + '0');
- sum += e.value;
- }
- assert(sum == 3);
- }
- /***********************************
- * Returns a newly allocated dynamic array containing a copy of the keys from
- * the associative array.
- * Params:
- * aa = The associative array.
- * Returns:
- * A dynamic array containing a copy of the keys.
- */
- Key[] keys(T : Value[Key], Value, Key)(T aa) @property
- {
- // ensure we are dealing with a genuine AA.
- static if (is(const(Value[Key]) == const(T)))
- alias realAA = aa;
- else
- const(Value[Key]) realAA = aa;
- auto res = () @trusted {
- auto a = cast(void[])_aaKeys(*cast(inout(AA)*)&realAA, Key.sizeof, typeid(Key[]));
- return *cast(Key[]*)&a;
- }();
- static if (__traits(hasPostblit, Key))
- _doPostblit(res);
- return res;
- }
- /** ditto */
- Key[] keys(T : Value[Key], Value, Key)(T *aa) @property
- {
- return (*aa).keys;
- }
- ///
- @safe unittest
- {
- auto aa = [1: "v1", 2: "v2"];
- int sum;
- foreach (k; aa.keys)
- sum += k;
- assert(sum == 3);
- }
- @safe unittest
- {
- static struct S
- {
- string str;
- void[][string] dict;
- alias dict this;
- }
- auto s = S("a");
- assert(s.keys.length == 0);
- }
- @safe unittest
- {
- @safe static struct Key
- {
- string str;
- this(this) @safe {}
- }
- string[Key] aa;
- static assert(__traits(compiles, {
- void test() @safe {
- const _ = aa.keys;
- }
- }));
- }
- @safe unittest
- {
- static struct Key
- {
- string str;
- this(this) @system {}
- }
- string[Key] aa;
- static assert(!__traits(compiles, {
- void test() @safe {
- const _ = aa.keys;
- }
- }));
- }
- /***********************************
- * Returns a newly allocated dynamic array containing a copy of the values from
- * the associative array.
- * Params:
- * aa = The associative array.
- * Returns:
- * A dynamic array containing a copy of the values.
- */
- Value[] values(T : Value[Key], Value, Key)(T aa) @property
- {
- // ensure we are dealing with a genuine AA.
- static if (is(const(Value[Key]) == const(T)))
- alias realAA = aa;
- else
- const(Value[Key]) realAA = aa;
- auto res = () @trusted {
- auto a = cast(void[])_aaValues(*cast(inout(AA)*)&realAA, Key.sizeof, Value.sizeof, typeid(Value[]));
- return *cast(Value[]*)&a;
- }();
- static if (__traits(hasPostblit, Value))
- _doPostblit(res);
- return res;
- }
- /** ditto */
- Value[] values(T : Value[Key], Value, Key)(T *aa) @property
- {
- return (*aa).values;
- }
- ///
- @safe unittest
- {
- auto aa = ["k1": 1, "k2": 2];
- int sum;
- foreach (e; aa.values)
- sum += e;
- assert(sum == 3);
- }
- @safe unittest
- {
- static struct S
- {
- string str;
- void[][string] dict;
- alias dict this;
- }
- auto s = S("a");
- assert(s.values.length == 0);
- }
- @safe unittest
- {
- @safe static struct Value
- {
- string str;
- this(this) @safe {}
- }
- Value[string] aa;
- static assert(__traits(compiles, {
- void test() @safe {
- const _ = aa.values;
- }
- }));
- }
- @safe unittest
- {
- static struct Value
- {
- string str;
- this(this) @system {}
- }
- Value[string] aa;
- static assert(!__traits(compiles, {
- void test() @safe {
- const _ = aa.values;
- }
- }));
- }
- /***********************************
- * Looks up key; if it exists returns corresponding value else evaluates and
- * returns defaultValue.
- * Params:
- * aa = The associative array.
- * key = The key.
- * defaultValue = The default value.
- * Returns:
- * The value.
- */
- inout(V) get(K, V)(inout(V[K]) aa, K key, lazy inout(V) defaultValue)
- {
- auto p = key in aa;
- return p ? *p : defaultValue;
- }
- /** ditto */
- inout(V) get(K, V)(inout(V[K])* aa, K key, lazy inout(V) defaultValue)
- {
- return (*aa).get(key, defaultValue);
- }
- ///
- @safe unittest
- {
- auto aa = ["k1": 1];
- assert(aa.get("k1", 0) == 1);
- assert(aa.get("k2", 0) == 0);
- }
- /***********************************
- * Looks up key; if it exists returns corresponding value else evaluates
- * value, adds it to the associative array and returns it.
- * Params:
- * aa = The associative array.
- * key = The key.
- * value = The required value.
- * Returns:
- * The value.
- */
- ref V require(K, V)(ref V[K] aa, K key, lazy V value = V.init)
- {
- bool found;
- // if key is @safe-ly copyable, `require` can infer @safe
- static if (isSafeCopyable!K)
- {
- auto p = () @trusted
- {
- return cast(V*) _aaGetX(cast(AA*) &aa, typeid(V[K]), V.sizeof, &key, found);
- } ();
- }
- else
- {
- auto p = cast(V*) _aaGetX(cast(AA*) &aa, typeid(V[K]), V.sizeof, &key, found);
- }
- if (found)
- return *p;
- else
- {
- *p = value; // Not `return (*p = value)` since if `=` is overloaded
- return *p; // this might not return a ref to the left-hand side.
- }
- }
- ///
- @safe unittest
- {
- auto aa = ["k1": 1];
- assert(aa.require("k1", 0) == 1);
- assert(aa.require("k2", 0) == 0);
- assert(aa["k2"] == 0);
- }
- // Tests whether T can be @safe-ly copied. Use a union to exclude destructor from the test.
- private enum bool isSafeCopyable(T) = is(typeof(() @safe { union U { T x; } T *x; auto u = U(*x); }));
- /***********************************
- * Looks up key; if it exists applies the update callable else evaluates the
- * create callable and adds it to the associative array
- * Params:
- * aa = The associative array.
- * key = The key.
- * create = The callable to apply on create.
- * update = The callable to apply on update.
- */
- void update(K, V, C, U)(ref V[K] aa, K key, scope C create, scope U update)
- if (is(typeof(create()) : V) && (is(typeof(update(aa[K.init])) : V) || is(typeof(update(aa[K.init])) == void)))
- {
- bool found;
- // if key is @safe-ly copyable, `update` may infer @safe
- static if (isSafeCopyable!K)
- {
- auto p = () @trusted
- {
- return cast(V*) _aaGetX(cast(AA*) &aa, typeid(V[K]), V.sizeof, &key, found);
- } ();
- }
- else
- {
- auto p = cast(V*) _aaGetX(cast(AA*) &aa, typeid(V[K]), V.sizeof, &key, found);
- }
- if (!found)
- *p = create();
- else
- {
- static if (is(typeof(update(*p)) == void))
- update(*p);
- else
- *p = update(*p);
- }
- }
- ///
- @system unittest
- {
- auto aa = ["k1": 1];
- aa.update("k1", {
- return -1; // create (won't be executed)
- }, (ref int v) {
- v += 1; // update
- });
- assert(aa["k1"] == 2);
- aa.update("k2", {
- return 0; // create
- }, (ref int v) {
- v = -1; // update (won't be executed)
- });
- assert(aa["k2"] == 0);
- }
- @safe unittest
- {
- static struct S
- {
- int x;
- @nogc nothrow pure:
- this(this) @system {}
- @safe const:
- // stubs
- bool opEquals(S rhs) { assert(0); }
- size_t toHash() { assert(0); }
- }
- int[string] aai;
- static assert(is(typeof(() @safe { aai.require("a", 1234); })));
- static assert(is(typeof(() @safe { aai.update("a", { return 1234; }, (ref int x) { x++; return x; }); })));
- S[string] aas;
- static assert(is(typeof(() { aas.require("a", S(1234)); })));
- static assert(is(typeof(() { aas.update("a", { return S(1234); }, (ref S s) { s.x++; return s; }); })));
- static assert(!is(typeof(() @safe { aas.update("a", { return S(1234); }, (ref S s) { s.x++; return s; }); })));
- int[S] aais;
- static assert(is(typeof(() { aais.require(S(1234), 1234); })));
- static assert(is(typeof(() { aais.update(S(1234), { return 1234; }, (ref int x) { x++; return x; }); })));
- static assert(!is(typeof(() @safe { aais.require(S(1234), 1234); })));
- static assert(!is(typeof(() @safe { aais.update(S(1234), { return 1234; }, (ref int x) { x++; return x; }); })));
- }
- @safe unittest
- {
- struct S0
- {
- int opCall(ref int v)
- {
- return v + 1;
- }
- }
- struct S1
- {
- int opCall()()
- {
- return -2;
- }
- T opCall(T)(ref T v)
- {
- return v + 1;
- }
- }
- int[string] a = ["2" : 1];
- a.update("2", () => -1, S0.init);
- assert(a["2"] == 2);
- a.update("0", () => -1, S0.init);
- assert(a["0"] == -1);
- a.update("2", S1.init, S1.init);
- assert(a["2"] == 3);
- a.update("1", S1.init, S1.init);
- assert(a["1"] == -2);
- }
- @system unittest
- {
- int[string] aa;
- foreach (n; 0 .. 2)
- aa.update("k1", {
- return 7;
- }, (ref int v) {
- return v + 3;
- });
- assert(aa["k1"] == 10);
- }
- version (CoreDdoc)
- {
- // This lets DDoc produce better documentation.
- /**
- Calculates the hash value of `arg` with an optional `seed` initial value.
- The result might not be equal to `typeid(T).getHash(&arg)`.
- Params:
- arg = argument to calculate the hash value of
- seed = optional `seed` value (may be used for hash chaining)
- Return: calculated hash value of `arg`
- */
- size_t hashOf(T)(auto ref T arg, size_t seed)
- {
- static import core.internal.hash;
- return core.internal.hash.hashOf(arg, seed);
- }
- /// ditto
- size_t hashOf(T)(auto ref T arg)
- {
- static import core.internal.hash;
- return core.internal.hash.hashOf(arg);
- }
- @safe unittest
- {
- auto h1 = "my.string".hashOf;
- assert(h1 == "my.string".hashOf);
- }
- }
- else
- {
- public import core.internal.hash : hashOf;
- }
- ///
- @system unittest
- {
- class MyObject
- {
- size_t myMegaHash() const @safe pure nothrow
- {
- return 42;
- }
- }
- struct Test
- {
- int a;
- string b;
- MyObject c;
- size_t toHash() const pure nothrow
- {
- size_t hash = a.hashOf();
- hash = b.hashOf(hash);
- size_t h1 = c.myMegaHash();
- hash = h1.hashOf(hash); //Mix two hash values
- return hash;
- }
- }
- }
- bool _xopEquals(in void*, in void*)
- {
- throw new Error("TypeInfo.equals is not implemented");
- }
- bool _xopCmp(in void*, in void*)
- {
- throw new Error("TypeInfo.compare is not implemented");
- }
- /******************************************
- * Create RTInfo for type T
- */
- template RTInfoImpl(size_t[] pointerBitmap)
- {
- immutable size_t[pointerBitmap.length] RTInfoImpl = pointerBitmap[];
- }
- template NoPointersBitmapPayload(size_t N)
- {
- enum size_t[N] NoPointersBitmapPayload = 0;
- }
- template RTInfo(T)
- {
- enum pointerBitmap = __traits(getPointerBitmap, T);
- static if (pointerBitmap[1 .. $] == NoPointersBitmapPayload!(pointerBitmap.length - 1))
- enum RTInfo = rtinfoNoPointers;
- else
- enum RTInfo = RTInfoImpl!(pointerBitmap).ptr;
- }
- /**
- * shortcuts for the precise GC, also generated by the compiler
- * used instead of the actual pointer bitmap
- */
- enum immutable(void)* rtinfoNoPointers = null;
- enum immutable(void)* rtinfoHasPointers = cast(void*)1;
- // Helper functions
- private inout(TypeInfo) getElement(return scope inout TypeInfo value) @trusted pure nothrow
- {
- TypeInfo element = cast() value;
- for (;;)
- {
- if (auto qualified = cast(TypeInfo_Const) element)
- element = qualified.base;
- else if (auto redefined = cast(TypeInfo_Enum) element)
- element = redefined.base;
- else if (auto staticArray = cast(TypeInfo_StaticArray) element)
- element = staticArray.value;
- else if (auto vector = cast(TypeInfo_Vector) element)
- element = vector.base;
- else
- break;
- }
- return cast(inout) element;
- }
- private size_t getArrayHash(const scope TypeInfo element, const scope void* ptr, const size_t count) @trusted nothrow
- {
- if (!count)
- return 0;
- const size_t elementSize = element.tsize;
- if (!elementSize)
- return 0;
- static bool hasCustomToHash(const scope TypeInfo value) @trusted pure nothrow
- {
- const element = getElement(value);
- if (const struct_ = cast(const TypeInfo_Struct) element)
- return !!struct_.xtoHash;
- return cast(const TypeInfo_Array) element
- || cast(const TypeInfo_AssociativeArray) element
- || cast(const ClassInfo) element
- || cast(const TypeInfo_Interface) element;
- }
- if (!hasCustomToHash(element))
- return hashOf(ptr[0 .. elementSize * count]);
- size_t hash = 0;
- foreach (size_t i; 0 .. count)
- hash = hashOf(element.getHash(ptr + i * elementSize), hash);
- return hash;
- }
- /// Provide the .dup array property.
- @property auto dup(T)(T[] a)
- if (!is(const(T) : T))
- {
- import core.internal.traits : Unconst;
- static assert(is(T : Unconst!T), "Cannot implicitly convert type "~T.stringof~
- " to "~Unconst!T.stringof~" in dup.");
- return _dup!(T, Unconst!T)(a);
- }
- ///
- @safe unittest
- {
- auto arr = [1, 2];
- auto arr2 = arr.dup;
- arr[0] = 0;
- assert(arr == [0, 2]);
- assert(arr2 == [1, 2]);
- }
- /// ditto
- // const overload to support implicit conversion to immutable (unique result, see DIP29)
- @property T[] dup(T)(const(T)[] a)
- if (is(const(T) : T))
- {
- return _dup!(const(T), T)(a);
- }
- /// Provide the .idup array property.
- @property immutable(T)[] idup(T)(T[] a)
- {
- static assert(is(T : immutable(T)), "Cannot implicitly convert type "~T.stringof~
- " to immutable in idup.");
- return _dup!(T, immutable(T))(a);
- }
- /// ditto
- @property immutable(T)[] idup(T:void)(const(T)[] a)
- {
- return a.dup;
- }
- ///
- @safe unittest
- {
- char[] arr = ['a', 'b', 'c'];
- string s = arr.idup;
- arr[0] = '.';
- assert(s == "abc");
- }
- private U[] _dup(T, U)(scope T[] a) pure nothrow @trusted if (__traits(isPOD, T))
- {
- if (__ctfe)
- return _dupCtfe!(T, U)(a);
- import core.stdc.string : memcpy;
- auto arr = _d_newarrayU(typeid(T[]), a.length);
- memcpy(arr.ptr, cast(const(void)*) a.ptr, T.sizeof * a.length);
- return *cast(U[]*) &arr;
- }
- private U[] _dupCtfe(T, U)(scope T[] a)
- {
- static if (is(T : void))
- assert(0, "Cannot dup a void[] array at compile time.");
- else
- {
- U[] res;
- foreach (ref e; a)
- res ~= e;
- return res;
- }
- }
- private U[] _dup(T, U)(T[] a) if (!__traits(isPOD, T))
- {
- // note: copyEmplace is `@system` inside a `@trusted` block, so the __ctfe branch
- // has the extra duty to infer _dup `@system` when the copy-constructor is `@system`.
- if (__ctfe)
- return _dupCtfe!(T, U)(a);
- import core.lifetime: copyEmplace;
- U[] res = () @trusted {
- auto arr = cast(U*) _d_newarrayU(typeid(T[]), a.length);
- size_t i;
- scope (failure)
- {
- import core.internal.lifetime: emplaceInitializer;
- // Initialize all remaining elements to not destruct garbage
- foreach (j; i .. a.length)
- emplaceInitializer(cast() arr[j]);
- }
- for (; i < a.length; i++)
- {
- copyEmplace(a.ptr[i], arr[i]);
- }
- return cast(U[])(arr[0..a.length]);
- } ();
- return res;
- }
- // https://issues.dlang.org/show_bug.cgi?id=22107
- @safe unittest
- {
- static int i;
- @safe struct S
- {
- this(this) { i++; }
- }
- void fun(scope S[] values...) @safe
- {
- values.dup;
- }
- }
- // HACK: This is a lie. `_d_arraysetcapacity` is neither `nothrow` nor `pure`, but this lie is
- // necessary for now to prevent breaking code.
- private extern (C) size_t _d_arraysetcapacity(const TypeInfo ti, size_t newcapacity, void[]* arrptr) pure nothrow;
- /**
- (Property) Gets the current _capacity of a slice. The _capacity is the size
- that the slice can grow to before the underlying array must be
- reallocated or extended.
- If an append must reallocate a slice with no possibility of extension, then
- `0` is returned. This happens when the slice references a static array, or
- if another slice references elements past the end of the current slice.
- Note: The _capacity of a slice may be impacted by operations on other slices.
- */
- @property size_t capacity(T)(T[] arr) pure nothrow @trusted
- {
- return _d_arraysetcapacity(typeid(T[]), 0, cast(void[]*)&arr);
- }
- ///
- @safe unittest
- {
- //Static array slice: no capacity
- int[4] sarray = [1, 2, 3, 4];
- int[] slice = sarray[];
- assert(sarray.capacity == 0);
- //Appending to slice will reallocate to a new array
- slice ~= 5;
- assert(slice.capacity >= 5);
- //Dynamic array slices
- int[] a = [1, 2, 3, 4];
- int[] b = a[1 .. $];
- int[] c = a[1 .. $ - 1];
- debug(SENTINEL) {} else // non-zero capacity very much depends on the array and GC implementation
- {
- assert(a.capacity != 0);
- assert(a.capacity == b.capacity + 1); //both a and b share the same tail
- }
- assert(c.capacity == 0); //an append to c must relocate c.
- }
- /**
- Reserves capacity for a slice. The capacity is the size
- that the slice can grow to before the underlying array must be
- reallocated or extended.
- Returns: The new capacity of the array (which may be larger than
- the requested capacity).
- */
- size_t reserve(T)(ref T[] arr, size_t newcapacity) pure nothrow @trusted
- {
- if (__ctfe)
- return newcapacity;
- else
- return _d_arraysetcapacity(typeid(T[]), newcapacity, cast(void[]*)&arr);
- }
- ///
- @safe unittest
- {
- //Static array slice: no capacity. Reserve relocates.
- int[4] sarray = [1, 2, 3, 4];
- int[] slice = sarray[];
- auto u = slice.reserve(8);
- assert(u >= 8);
- assert(&sarray[0] !is &slice[0]);
- assert(slice.capacity == u);
- //Dynamic array slices
- int[] a = [1, 2, 3, 4];
- a.reserve(8); //prepare a for appending 4 more items
- auto p = &a[0];
- u = a.capacity;
- a ~= [5, 6, 7, 8];
- assert(p == &a[0]); //a should not have been reallocated
- assert(u == a.capacity); //a should not have been extended
- }
- // https://issues.dlang.org/show_bug.cgi?id=12330, reserve() at CTFE time
- @safe unittest
- {
- int[] foo() {
- int[] result;
- auto a = result.reserve = 5;
- assert(a == 5);
- return result;
- }
- enum r = foo();
- }
- // Issue 6646: should be possible to use array.reserve from SafeD.
- @safe unittest
- {
- int[] a;
- a.reserve(10);
- }
- // HACK: This is a lie. `_d_arrayshrinkfit` is not `nothrow`, but this lie is necessary
- // for now to prevent breaking code.
- private extern (C) void _d_arrayshrinkfit(const TypeInfo ti, void[] arr) nothrow;
- /**
- Assume that it is safe to append to this array. Appends made to this array
- after calling this function may append in place, even if the array was a
- slice of a larger array to begin with.
- Use this only when it is certain there are no elements in use beyond the
- array in the memory block. If there are, those elements will be
- overwritten by appending to this array.
- Warning: Calling this function, and then using references to data located after the
- given array results in undefined behavior.
- Returns:
- The input is returned.
- */
- auto ref inout(T[]) assumeSafeAppend(T)(auto ref inout(T[]) arr) nothrow @system
- {
- _d_arrayshrinkfit(typeid(T[]), *(cast(void[]*)&arr));
- return arr;
- }
- ///
- @system unittest
- {
- int[] a = [1, 2, 3, 4];
- // Without assumeSafeAppend. Appending relocates.
- int[] b = a [0 .. 3];
- b ~= 5;
- assert(a.ptr != b.ptr);
- debug(SENTINEL) {} else
- {
- // With assumeSafeAppend. Appending overwrites.
- int[] c = a [0 .. 3];
- c.assumeSafeAppend() ~= 5;
- assert(a.ptr == c.ptr);
- }
- }
- @system unittest
- {
- int[] arr;
- auto newcap = arr.reserve(2000);
- assert(newcap >= 2000);
- assert(newcap == arr.capacity);
- auto ptr = arr.ptr;
- foreach (i; 0..2000)
- arr ~= i;
- assert(ptr == arr.ptr);
- arr = arr[0..1];
- arr.assumeSafeAppend();
- arr ~= 5;
- assert(ptr == arr.ptr);
- }
- @system unittest
- {
- int[] arr = [1, 2, 3];
- void foo(ref int[] i)
- {
- i ~= 5;
- }
- arr = arr[0 .. 2];
- foo(assumeSafeAppend(arr)); //pass by ref
- assert(arr[]==[1, 2, 5]);
- arr = arr[0 .. 1].assumeSafeAppend(); //pass by value
- }
- // https://issues.dlang.org/show_bug.cgi?id=10574
- @system unittest
- {
- int[] a;
- immutable(int[]) b;
- auto a2 = &assumeSafeAppend(a);
- auto b2 = &assumeSafeAppend(b);
- auto a3 = assumeSafeAppend(a[]);
- auto b3 = assumeSafeAppend(b[]);
- assert(is(typeof(*a2) == int[]));
- assert(is(typeof(*b2) == immutable(int[])));
- assert(is(typeof(a3) == int[]));
- assert(is(typeof(b3) == immutable(int[])));
- }
- private extern (C) void[] _d_newarrayU(const scope TypeInfo ti, size_t length) pure nothrow;
- private void _doPostblit(T)(T[] arr)
- {
- // infer static postblit type, run postblit if any
- static if (__traits(hasPostblit, T))
- {
- static if (__traits(isStaticArray, T) && is(T : E[], E))
- _doPostblit(cast(E[]) arr);
- else static if (!is(typeof(arr[0].__xpostblit())) && is(immutable T == immutable U, U))
- foreach (ref elem; (() @trusted => cast(U[]) arr)())
- elem.__xpostblit();
- else
- foreach (ref elem; arr)
- elem.__xpostblit();
- }
- }
- @safe unittest
- {
- static struct S1 { int* p; }
- static struct S2 { @disable this(); }
- static struct S3 { @disable this(this); }
- int dg1() pure nothrow @safe
- {
- {
- char[] m;
- string i;
- m = m.dup;
- i = i.idup;
- m = i.dup;
- i = m.idup;
- }
- {
- S1[] m;
- immutable(S1)[] i;
- m = m.dup;
- i = i.idup;
- static assert(!is(typeof(m.idup)));
- static assert(!is(typeof(i.dup)));
- }
- {
- S3[] m;
- immutable(S3)[] i;
- static assert(!is(typeof(m.dup)));
- static assert(!is(typeof(i.idup)));
- }
- {
- shared(S1)[] m;
- m = m.dup;
- static assert(!is(typeof(m.idup)));
- }
- {
- int[] a = (inout(int)) { inout(const(int))[] a; return a.dup; }(0);
- }
- return 1;
- }
- int dg2() pure nothrow @safe
- {
- {
- S2[] m = [S2.init, S2.init];
- immutable(S2)[] i = [S2.init, S2.init];
- m = m.dup;
- m = i.dup;
- i = m.idup;
- i = i.idup;
- }
- return 2;
- }
- enum a = dg1();
- enum b = dg2();
- assert(dg1() == a);
- assert(dg2() == b);
- }
- @system unittest
- {
- static struct Sunpure { this(this) @safe nothrow {} }
- static struct Sthrow { this(this) @safe pure {} }
- static struct Sunsafe { this(this) @system pure nothrow {} }
- static struct Snocopy { @disable this(this); }
- [].dup!Sunpure;
- [].dup!Sthrow;
- cast(void) [].dup!Sunsafe;
- static assert(!__traits(compiles, () pure { [].dup!Sunpure; }));
- static assert(!__traits(compiles, () nothrow { [].dup!Sthrow; }));
- static assert(!__traits(compiles, () @safe { [].dup!Sunsafe; }));
- static assert(!__traits(compiles, () { [].dup!Snocopy; }));
- [].idup!Sunpure;
- [].idup!Sthrow;
- [].idup!Sunsafe;
- static assert(!__traits(compiles, () pure { [].idup!Sunpure; }));
- static assert(!__traits(compiles, () nothrow { [].idup!Sthrow; }));
- static assert(!__traits(compiles, () @safe { [].idup!Sunsafe; }));
- static assert(!__traits(compiles, () { [].idup!Snocopy; }));
- }
- @safe unittest
- {
- // test that the copy-constructor is called with .dup
- static struct ArrElem
- {
- int a;
- this(int a)
- {
- this.a = a;
- }
- this(ref const ArrElem)
- {
- a = 2;
- }
- this(ref ArrElem) immutable
- {
- a = 3;
- }
- }
- auto arr = [ArrElem(1), ArrElem(1)];
- ArrElem[] b = arr.dup;
- assert(b[0].a == 2 && b[1].a == 2);
- immutable ArrElem[] c = arr.idup;
- assert(c[0].a == 3 && c[1].a == 3);
- }
- @system unittest
- {
- static struct Sunpure { this(ref const typeof(this)) @safe nothrow {} }
- static struct Sthrow { this(ref const typeof(this)) @safe pure {} }
- static struct Sunsafe { this(ref const typeof(this)) @system pure nothrow {} }
- [].dup!Sunpure;
- [].dup!Sthrow;
- cast(void) [].dup!Sunsafe;
- static assert(!__traits(compiles, () pure { [].dup!Sunpure; }));
- static assert(!__traits(compiles, () nothrow { [].dup!Sthrow; }));
- static assert(!__traits(compiles, () @safe { [].dup!Sunsafe; }));
- // for idup to work on structs that have copy constructors, it is necessary
- // that the struct defines a copy constructor that creates immutable objects
- static struct ISunpure { this(ref const typeof(this)) immutable @safe nothrow {} }
- static struct ISthrow { this(ref const typeof(this)) immutable @safe pure {} }
- static struct ISunsafe { this(ref const typeof(this)) immutable @system pure nothrow {} }
- [].idup!ISunpure;
- [].idup!ISthrow;
- [].idup!ISunsafe;
- static assert(!__traits(compiles, () pure { [].idup!ISunpure; }));
- static assert(!__traits(compiles, () nothrow { [].idup!ISthrow; }));
- static assert(!__traits(compiles, () @safe { [].idup!ISunsafe; }));
- }
- @safe unittest
- {
- static int*[] pureFoo() pure { return null; }
- { char[] s; immutable x = s.dup; }
- { immutable x = (cast(int*[])null).dup; }
- { immutable x = pureFoo(); }
- { immutable x = pureFoo().dup; }
- }
- @safe unittest
- {
- auto a = [1, 2, 3];
- auto b = a.dup;
- debug(SENTINEL) {} else
- assert(b.capacity >= 3);
- }
- @system unittest
- {
- // Bugzilla 12580
- void[] m = [0];
- shared(void)[] s = [cast(shared)1];
- immutable(void)[] i = [cast(immutable)2];
- s = s.dup;
- static assert(is(typeof(s.dup) == shared(void)[]));
- m = i.dup;
- i = m.dup;
- i = i.idup;
- i = m.idup;
- i = s.idup;
- i = s.dup;
- static assert(!__traits(compiles, m = s.dup));
- }
- @safe unittest
- {
- // Bugzilla 13809
- static struct S
- {
- this(this) {}
- ~this() {}
- }
- S[] arr;
- auto a = arr.dup;
- }
- @system unittest
- {
- // Bugzilla 16504
- static struct S
- {
- __gshared int* gp;
- int* p;
- // postblit and hence .dup could escape
- this(this) { gp = p; }
- }
- int p;
- scope S[1] arr = [S(&p)];
- auto a = arr.dup; // dup does escape
- }
- // https://issues.dlang.org/show_bug.cgi?id=21983
- // dup/idup destroys partially constructed arrays on failure
- @safe unittest
- {
- static struct SImpl(bool postblit)
- {
- int num;
- long l = 0xDEADBEEF;
- static if (postblit)
- {
- this(this)
- {
- if (this.num == 3)
- throw new Exception("");
- }
- }
- else
- {
- this(scope ref const SImpl other)
- {
- if (other.num == 3)
- throw new Exception("");
- this.num = other.num;
- this.l = other.l;
- }
- }
- ~this() @trusted
- {
- if (l != 0xDEADBEEF)
- {
- import core.stdc.stdio;
- printf("Unexpected value: %lld\n", l);
- fflush(stdout);
- assert(false);
- }
- }
- }
- alias Postblit = SImpl!true;
- alias Copy = SImpl!false;
- static int test(S)()
- {
- S[4] arr = [ S(1), S(2), S(3), S(4) ];
- try
- {
- arr.dup();
- assert(false);
- }
- catch (Exception)
- {
- return 1;
- }
- }
- static assert(test!Postblit());
- assert(test!Postblit());
- static assert(test!Copy());
- assert(test!Copy());
- }
- /**
- Destroys the given object and optionally resets to initial state. It's used to
- _destroy an object, calling its destructor or finalizer so it no longer
- references any other objects. It does $(I not) initiate a GC cycle or free
- any GC memory.
- If `initialize` is supplied `false`, the object is considered invalid after
- destruction, and should not be referenced.
- */
- void destroy(bool initialize = true, T)(ref T obj) if (is(T == struct))
- {
- import core.internal.destruction : destructRecurse;
- destructRecurse(obj);
- static if (initialize)
- {
- import core.internal.lifetime : emplaceInitializer;
- emplaceInitializer(obj); // emplace T.init
- }
- }
- @safe unittest
- {
- struct A { string s = "A"; }
- A a = {s: "B"};
- assert(a.s == "B");
- a.destroy;
- assert(a.s == "A");
- }
- nothrow @safe @nogc unittest
- {
- {
- struct A { string s = "A"; }
- A a;
- a.s = "asd";
- destroy!false(a);
- assert(a.s == "asd");
- destroy(a);
- assert(a.s == "A");
- }
- {
- static int destroyed = 0;
- struct C
- {
- string s = "C";
- ~this() nothrow @safe @nogc
- {
- destroyed ++;
- }
- }
- struct B
- {
- C c;
- string s = "B";
- ~this() nothrow @safe @nogc
- {
- destroyed ++;
- }
- }
- B a;
- a.s = "asd";
- a.c.s = "jkl";
- destroy!false(a);
- assert(destroyed == 2);
- assert(a.s == "asd");
- assert(a.c.s == "jkl" );
- destroy(a);
- assert(destroyed == 4);
- assert(a.s == "B");
- assert(a.c.s == "C" );
- }
- }
- private extern (C) void rt_finalize(void *data, bool det=true) nothrow;
- /// ditto
- void destroy(bool initialize = true, T)(T obj) if (is(T == class))
- {
- static if (__traits(getLinkage, T) == "C++")
- {
- static if (__traits(hasMember, T, "__xdtor"))
- obj.__xdtor();
- static if (initialize)
- {
- const initializer = __traits(initSymbol, T);
- (cast(void*)obj)[0 .. initializer.length] = initializer[];
- }
- }
- else
- {
- // Bypass overloaded opCast
- auto ptr = (() @trusted => *cast(void**) &obj)();
- rt_finalize(ptr);
- }
- }
- /// ditto
- void destroy(bool initialize = true, T)(T obj) if (is(T == interface))
- {
- static assert(__traits(getLinkage, T) == "D", "Invalid call to destroy() on extern(" ~ __traits(getLinkage, T) ~ ") interface");
- destroy!initialize(cast(Object)obj);
- }
- /// Reference type demonstration
- @system unittest
- {
- class C
- {
- struct Agg
- {
- static int dtorCount;
- int x = 10;
- ~this() { dtorCount++; }
- }
- static int dtorCount;
- string s = "S";
- Agg a;
- ~this() { dtorCount++; }
- }
- C c = new C();
- assert(c.dtorCount == 0); // destructor not yet called
- assert(c.s == "S"); // initial state `c.s` is `"S"`
- assert(c.a.dtorCount == 0); // destructor not yet called
- assert(c.a.x == 10); // initial state `c.a.x` is `10`
- c.s = "T";
- c.a.x = 30;
- assert(c.s == "T"); // `c.s` is `"T"`
- destroy(c);
- assert(c.dtorCount == 1); // `c`'s destructor was called
- assert(c.s == "S"); // `c.s` is back to its inital state, `"S"`
- assert(c.a.dtorCount == 1); // `c.a`'s destructor was called
- assert(c.a.x == 10); // `c.a.x` is back to its inital state, `10`
- // check C++ classes work too!
- extern (C++) class CPP
- {
- struct Agg
- {
- __gshared int dtorCount;
- int x = 10;
- ~this() { dtorCount++; }
- }
- __gshared int dtorCount;
- string s = "S";
- Agg a;
- ~this() { dtorCount++; }
- }
- CPP cpp = new CPP();
- assert(cpp.dtorCount == 0); // destructor not yet called
- assert(cpp.s == "S"); // initial state `cpp.s` is `"S"`
- assert(cpp.a.dtorCount == 0); // destructor not yet called
- assert(cpp.a.x == 10); // initial state `cpp.a.x` is `10`
- cpp.s = "T";
- cpp.a.x = 30;
- assert(cpp.s == "T"); // `cpp.s` is `"T"`
- destroy!false(cpp); // destroy without initialization
- assert(cpp.dtorCount == 1); // `cpp`'s destructor was called
- assert(cpp.s == "T"); // `cpp.s` is not initialized
- assert(cpp.a.dtorCount == 1); // `cpp.a`'s destructor was called
- assert(cpp.a.x == 30); // `cpp.a.x` is not initialized
- destroy(cpp);
- assert(cpp.dtorCount == 2); // `cpp`'s destructor was called again
- assert(cpp.s == "S"); // `cpp.s` is back to its inital state, `"S"`
- assert(cpp.a.dtorCount == 2); // `cpp.a`'s destructor was called again
- assert(cpp.a.x == 10); // `cpp.a.x` is back to its inital state, `10`
- }
- /// Value type demonstration
- @safe unittest
- {
- int i;
- assert(i == 0); // `i`'s initial state is `0`
- i = 1;
- assert(i == 1); // `i` changed to `1`
- destroy!false(i);
- assert(i == 1); // `i` was not initialized
- destroy(i);
- assert(i == 0); // `i` is back to its initial state `0`
- }
- @system unittest
- {
- extern(C++)
- static class C
- {
- void* ptr;
- this() {}
- }
- destroy!false(new C());
- destroy!true(new C());
- }
- @system unittest
- {
- // class with an `alias this`
- class A
- {
- static int dtorCount;
- ~this()
- {
- dtorCount++;
- }
- }
- class B
- {
- A a;
- alias a this;
- this()
- {
- a = new A;
- }
- static int dtorCount;
- ~this()
- {
- dtorCount++;
- }
- }
- auto b = new B;
- assert(A.dtorCount == 0);
- assert(B.dtorCount == 0);
- destroy(b);
- assert(A.dtorCount == 0);
- assert(B.dtorCount == 1);
- auto a = new A;
- destroy(a);
- assert(A.dtorCount == 1);
- }
- @system unittest
- {
- interface I { }
- {
- class A: I { string s = "A"; this() {} }
- auto a = new A, b = new A;
- a.s = b.s = "asd";
- destroy(a);
- assert(a.s == "A");
- I i = b;
- destroy(i);
- assert(b.s == "A");
- }
- {
- static bool destroyed = false;
- class B: I
- {
- string s = "B";
- this() {}
- ~this()
- {
- destroyed = true;
- }
- }
- auto a = new B, b = new B;
- a.s = b.s = "asd";
- destroy(a);
- assert(destroyed);
- assert(a.s == "B");
- destroyed = false;
- I i = b;
- destroy(i);
- assert(destroyed);
- assert(b.s == "B");
- }
- // this test is invalid now that the default ctor is not run after clearing
- version (none)
- {
- class C
- {
- string s;
- this()
- {
- s = "C";
- }
- }
- auto a = new C;
- a.s = "asd";
- destroy(a);
- assert(a.s == "C");
- }
- }
- nothrow @safe @nogc unittest
- {
- {
- struct A { string s = "A"; }
- A a;
- a.s = "asd";
- destroy!false(a);
- assert(a.s == "asd");
- destroy(a);
- assert(a.s == "A");
- }
- {
- static int destroyed = 0;
- struct C
- {
- string s = "C";
- ~this() nothrow @safe @nogc
- {
- destroyed ++;
- }
- }
- struct B
- {
- C c;
- string s = "B";
- ~this() nothrow @safe @nogc
- {
- destroyed ++;
- }
- }
- B a;
- a.s = "asd";
- a.c.s = "jkl";
- destroy!false(a);
- assert(destroyed == 2);
- assert(a.s == "asd");
- assert(a.c.s == "jkl" );
- destroy(a);
- assert(destroyed == 4);
- assert(a.s == "B");
- assert(a.c.s == "C" );
- }
- }
- nothrow unittest
- {
- // Bugzilla 20049: Test to ensure proper behavior of `nothrow` destructors
- class C
- {
- static int dtorCount = 0;
- this() nothrow {}
- ~this() nothrow { dtorCount++; }
- }
- auto c = new C;
- destroy(c);
- assert(C.dtorCount == 1);
- }
- // https://issues.dlang.org/show_bug.cgi?id=22832
- nothrow unittest
- {
- static struct A {}
- static class B
- {
- A opCast(T : A)() { return A(); }
- }
- destroy(B.init);
- }
- /// ditto
- void destroy(bool initialize = true, T)(ref T obj)
- if (__traits(isStaticArray, T))
- {
- foreach_reverse (ref e; obj[])
- destroy!initialize(e);
- }
- @safe unittest
- {
- int[2] a;
- a[0] = 1;
- a[1] = 2;
- destroy!false(a);
- assert(a == [ 1, 2 ]);
- destroy(a);
- assert(a == [ 0, 0 ]);
- }
- @safe unittest
- {
- static struct vec2f {
- float[2] values;
- alias values this;
- }
- vec2f v;
- destroy!(true, vec2f)(v);
- }
- @system unittest
- {
- // Bugzilla 15009
- static string op;
- static struct S
- {
- int x;
- this(int x) { op ~= "C" ~ cast(char)('0'+x); this.x = x; }
- this(this) { op ~= "P" ~ cast(char)('0'+x); }
- ~this() { op ~= "D" ~ cast(char)('0'+x); }
- }
- {
- S[2] a1 = [S(1), S(2)];
- op = "";
- }
- assert(op == "D2D1"); // built-in scope destruction
- {
- S[2] a1 = [S(1), S(2)];
- op = "";
- destroy(a1);
- assert(op == "D2D1"); // consistent with built-in behavior
- }
- {
- S[2][2] a2 = [[S(1), S(2)], [S(3), S(4)]];
- op = "";
- }
- assert(op == "D4D3D2D1");
- {
- S[2][2] a2 = [[S(1), S(2)], [S(3), S(4)]];
- op = "";
- destroy(a2);
- assert(op == "D4D3D2D1", op);
- }
- }
- // https://issues.dlang.org/show_bug.cgi?id=19218
- @system unittest
- {
- static struct S
- {
- static dtorCount = 0;
- ~this() { ++dtorCount; }
- }
- static interface I
- {
- ref S[3] getArray();
- alias getArray this;
- }
- static class C : I
- {
- static dtorCount = 0;
- ~this() { ++dtorCount; }
- S[3] a;
- alias a this;
- ref S[3] getArray() { return a; }
- }
- C c = new C();
- destroy(c);
- assert(S.dtorCount == 3);
- assert(C.dtorCount == 1);
- I i = new C();
- destroy(i);
- assert(S.dtorCount == 6);
- assert(C.dtorCount == 2);
- }
- /// ditto
- void destroy(bool initialize = true, T)(ref T obj)
- if (!is(T == struct) && !is(T == interface) && !is(T == class) && !__traits(isStaticArray, T))
- {
- static if (initialize)
- obj = T.init;
- }
- @safe unittest
- {
- {
- int a = 42;
- destroy!false(a);
- assert(a == 42);
- destroy(a);
- assert(a == 0);
- }
- {
- float a = 42;
- destroy!false(a);
- assert(a == 42);
- destroy(a);
- assert(a != a); // isnan
- }
- }
- @safe unittest
- {
- // Bugzilla 14746
- static struct HasDtor
- {
- ~this() { assert(0); }
- }
- static struct Owner
- {
- HasDtor* ptr;
- alias ptr this;
- }
- Owner o;
- assert(o.ptr is null);
- destroy(o); // must not reach in HasDtor.__dtor()
- }
- /* ************************************************************************
- COMPILER SUPPORT
- The compiler lowers certain expressions to instantiations of the following
- templates. They must be implicitly imported, which is why they are here
- in this file. They must also be `public` as they must be visible from the
- scope in which they are instantiated. They are explicitly undocumented as
- they are only intended to be instantiated by the compiler, not the user.
- **************************************************************************/
- public import core.internal.entrypoint : _d_cmain;
- public import core.internal.array.appending : _d_arrayappendTImpl;
- public import core.internal.array.appending : _d_arrayappendcTXImpl;
- public import core.internal.array.comparison : __cmp;
- public import core.internal.array.equality : __equals;
- public import core.internal.array.casting: __ArrayCast;
- public import core.internal.array.concatenation : _d_arraycatnTXImpl;
- public import core.internal.array.construction : _d_arrayctor;
- public import core.internal.array.construction : _d_arraysetctor;
- public import core.internal.array.capacity: _d_arraysetlengthTImpl;
- public import core.internal.dassert: _d_assert_fail;
- public import core.internal.destruction: __ArrayDtor;
- public import core.internal.moving: __move_post_blt;
- public import core.internal.postblit: __ArrayPostblit;
- public import core.internal.switch_: __switch;
- public import core.internal.switch_: __switch_error;
- public import core.lifetime : _d_delstructImpl;
- public import core.lifetime : _d_newThrowable;
- public @trusted @nogc nothrow pure extern (C) void _d_delThrowable(scope Throwable);
- // Compare class and interface objects for ordering.
- int __cmp(C1, C2)(C1 lhs, C2 rhs)
- if ((is(C1 : const(Object)) || (is(C1 == interface) && (__traits(getLinkage, C1) == "D"))) &&
- (is(C2 : const(Object)) || (is(C2 == interface) && (__traits(getLinkage, C2) == "D"))))
- {
- static if (is(C1 == typeof(null)) && is(C2 == typeof(null)))
- {
- return 0;
- }
- else static if (is(C1 == typeof(null)))
- {
- // Regard null references as always being "less than"
- return -1;
- }
- else static if (is(C2 == typeof(null)))
- {
- return 1;
- }
- else
- {
- if (lhs is rhs)
- return 0;
- if (lhs is null)
- return -1;
- if (rhs is null)
- return 1;
- return lhs.opCmp(rhs);
- }
- }
- // objects
- @safe unittest
- {
- class C
- {
- int i;
- this(int i) { this.i = i; }
- override int opCmp(Object c) const @safe
- {
- return i - (cast(C)c).i;
- }
- }
- auto c1 = new C(1);
- auto c2 = new C(2);
- assert(__cmp(c1, null) > 0);
- assert(__cmp(null, c1) < 0);
- assert(__cmp(c1, c1) == 0);
- assert(__cmp(c1, c2) < 0);
- assert(__cmp(c2, c1) > 0);
- assert(__cmp([c1, c1][], [c2, c2][]) < 0);
- assert(__cmp([c2, c2], [c1, c1]) > 0);
- }
- // structs
- @safe unittest
- {
- struct C
- {
- ubyte i;
- this(ubyte i) { this.i = i; }
- }
- auto c1 = C(1);
- auto c2 = C(2);
- assert(__cmp([c1, c1][], [c2, c2][]) < 0);
- assert(__cmp([c2, c2], [c1, c1]) > 0);
- assert(__cmp([c2, c2], [c2, c1]) > 0);
- }
- @safe unittest
- {
- auto a = "hello"c;
- assert(a > "hel");
- assert(a >= "hel");
- assert(a < "helloo");
- assert(a <= "helloo");
- assert(a > "betty");
- assert(a >= "betty");
- assert(a == "hello");
- assert(a <= "hello");
- assert(a >= "hello");
- assert(a < "я");
- }
- // Used in Exception Handling LSDA tables to 'wrap' C++ type info
- // so it can be distinguished from D TypeInfo
- class __cpp_type_info_ptr
- {
- void* ptr; // opaque pointer to C++ RTTI type info
- }
- // Compiler hook into the runtime implementation of array (vector) operations.
- template _arrayOp(Args...)
- {
- import core.internal.array.operations;
- alias _arrayOp = arrayOp!Args;
- }
- public import core.builtins : __ctfeWrite;
- /**
- Provides an "inline import", i.e. an `import` that is only available for a
- limited lookup. For example:
- ---
- void fun(imported!"std.stdio".File input)
- {
- ... use File from std.stdio normally ...
- }
- ---
- There is no need to import `std.stdio` at top level, so `fun` carries its own
- dependencies. The same approach can be used for template constraints:
- ---
- void fun(T)(imported!"std.stdio".File input, T value)
- if (imported!"std.traits".isIntegral!T)
- {
- ...
- }
- ---
- An inline import may be used in conjunction with the `with` statement as well.
- Inside the scope controlled by `with`, all symbols in the imported module are
- made available:
- ---
- void fun()
- {
- with (imported!"std.datetime")
- with (imported!"std.stdio")
- {
- Clock.currTime.writeln;
- }
- }
- ---
- The advantages of inline imports over top-level uses of the `import` declaration
- are the following:
- $(UL
- $(LI The `imported` template specifies dependencies at declaration level, not at
- module level. This allows reasoning about the dependency cost of declarations in
- separation instead of aggregated at module level.)
- $(LI Declarations using `imported` are easier to move around because they don't
- require top-level context, making for simpler and quicker refactorings.)
- $(LI Declarations using `imported` scale better with templates. This is because
- templates that are not instantiated do not have their parameters and constraints
- instantiated, so additional modules are not imported without necessity. This
- makes the cost of unused templates negligible. Dependencies are pulled on a need
- basis depending on the declarations used by client code.)
- )
- The use of `imported` also has drawbacks:
- $(UL
- $(LI If most declarations in a module need the same imports, then factoring them
- at top level, outside the declarations, is simpler than repeating them.)
- $(LI Traditional dependency-tracking tools such as make and other build systems
- assume file-level dependencies and need special tooling (such as rdmd) in order
- to work efficiently.)
- $(LI Dependencies at the top of a module are easier to inspect quickly than
- dependencies spread throughout the module.)
- )
- See_Also: The $(HTTP forum.dlang.org/post/tzqzmqhankrkbrfsrmbo@forum.dlang.org,
- forum discussion) that led to the creation of the `imported` facility. Credit is
- due to Daniel Nielsen and Dominikus Dittes Scherkl.
- */
- template imported(string moduleName)
- {
- mixin("import imported = " ~ moduleName ~ ";");
- }
|