12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250 |
- /*
- * It is strictly recommended to include "testlib.h" before any other include
- * in your code. In this case testlib overrides compiler specific "random()".
- *
- * If you can't compile your code and compiler outputs something about
- * ambiguous call of "random_shuffle", "rand" or "srand" it means that
- * you shouldn't use them. Use "shuffle", and "rnd.next()" instead of them
- * because these calls produce stable result for any C++ compiler. Read
- * sample generator sources for clarification.
- *
- * Please read the documentation for class "random_t" and use "rnd" instance in
- * generators. Probably, these sample calls will be usefull for you:
- * rnd.next(); rnd.next(100); rnd.next(1, 2);
- * rnd.next(3.14); rnd.next("[a-z]{1,100}").
- *
- * Also read about wnext() to generate off-center random distribution.
- *
- * See http://code.google.com/p/testlib/ to get latest version or bug tracker.
- */
- #ifndef _TESTLIB_H_
- #define _TESTLIB_H_
- /*
- * Copyright (c) 2005-2017
- */
- #define VERSION "0.9.14"
- /*
- * Mike Mirzayanov
- *
- * This material is provided "as is", with absolutely no warranty expressed
- * or implied. Any use is at your own risk.
- *
- * Permission to use or copy this software for any purpose is hereby granted
- * without fee, provided the above notices are retained on all copies.
- * Permission to modify the code and to distribute modified code is granted,
- * provided the above notices are retained, and a notice that the code was
- * modified is included with the above copyright notice.
- *
- */
- /* NOTE: This file contains testlib library for C++.
- *
- * Check, using testlib running format:
- * check.exe <Input_File> <Output_File> <Answer_File> [<Result_File> [-appes]],
- * If result file is specified it will contain results.
- *
- * Validator, using testlib running format:
- * validator.exe < input.txt,
- * It will return non-zero exit code and writes message to standard output.
- *
- * Generator, using testlib running format:
- * gen.exe [parameter-1] [parameter-2] [... paramerter-n]
- * You can write generated test(s) into standard output or into the file(s).
- *
- * Interactor, using testlib running format:
- * interactor.exe <Input_File> <Output_File> [<Answer_File> [<Result_File> [-appes]]],
- * Reads test from inf (mapped to args[1]), writes result to tout (mapped to argv[2],
- * can be judged by checker later), reads program output from ouf (mapped to stdin),
- * writes output to program via stdout (use cout, printf, etc).
- */
- const char* latestFeatures[] = {
- "Fixed compilation in VS 2015+",
- "Introduced space-separated read functions: readWords/readTokens, multilines read functions: readStrings/readLines",
- "Introduced space-separated read functions: readInts/readIntegers/readLongs/readUnsignedLongs/readDoubles/readReals/readStrictDoubles/readStrictReals",
- "Introduced split/tokenize functions to separate string by given char",
- "Introduced InStream::readUnsignedLong and InStream::readLong with unsigned long long paramerters",
- "Supported --testOverviewLogFileName for validator: bounds hits + features",
- "Fixed UB (sequence points) in random_t",
- "POINTS_EXIT_CODE returned back to 7 (instead of 0)",
- "Removed disable buffers for interactive problems, because it works unexpectedly in wine",
- "InStream over string: constructor of InStream from base InStream to inherit policies and std::string",
- "Added expectedButFound quit function, examples: expectedButFound(_wa, 10, 20), expectedButFound(_fail, ja, pa, \"[n=%d,m=%d]\", n, m)",
- "Fixed incorrect interval parsing in patterns",
- "Use registerGen(argc, argv, 1) to develop new generator, use registerGen(argc, argv, 0) to compile old generators (originally created for testlib under 0.8.7)",
- "Introduced disableFinalizeGuard() to switch off finalization checkings",
- "Use join() functions to format a range of items as a single string (separated by spaces or other separators)",
- "Use -DENABLE_UNEXPECTED_EOF to enable special exit code (by default, 8) in case of unexpected eof. It is good idea to use it in interactors",
- "Use -DUSE_RND_AS_BEFORE_087 to compile in compatibility mode with random behavior of versions before 0.8.7",
- "Fixed bug with nan in stringToDouble",
- "Fixed issue around overloads for size_t on x64",
- "Added attribute 'points' to the XML output in case of result=_points",
- "Exit codes can be customized via macros, e.g. -DPE_EXIT_CODE=14",
- "Introduced InStream function readWordTo/readTokenTo/readStringTo/readLineTo for faster reading",
- "Introduced global functions: format(), englishEnding(), upperCase(), lowerCase(), compress()",
- "Manual buffer in InStreams, some IO speed improvements",
- "Introduced quitif(bool, const char* pattern, ...) which delegates to quitf() in case of first argument is true",
- "Introduced guard against missed quitf() in checker or readEof() in validators",
- "Supported readStrictReal/readStrictDouble - to use in validators to check strictly float numbers",
- "Supported registerInteraction(argc, argv)",
- "Print checker message to the stderr instead of stdout",
- "Supported TResult _points to output calculated score, use quitp(...) functions",
- "Fixed to be compilable on Mac",
- "PC_BASE_EXIT_CODE=50 in case of defined TESTSYS",
- "Fixed issues 19-21, added __attribute__ format printf",
- "Some bug fixes",
- "ouf.readInt(1, 100) and similar calls return WA",
- "Modified random_t to avoid integer overflow",
- "Truncated checker output [patch by Stepan Gatilov]",
- "Renamed class random -> class random_t",
- "Supported name parameter for read-and-validation methods, like readInt(1, 2, \"n\")",
- "Fixed bug in readDouble()",
- "Improved ensuref(), fixed nextLine to work in case of EOF, added startTest()",
- "Supported \"partially correct\", example: quitf(_pc(13), \"result=%d\", result)",
- "Added shuffle(begin, end), use it instead of random_shuffle(begin, end)",
- "Added readLine(const string& ptrn), fixed the logic of readLine() in the validation mode",
- "Package extended with samples of generators and validators",
- "Written the documentation for classes and public methods in testlib.h",
- "Implemented random routine to support generators, use registerGen() to switch it on",
- "Implemented strict mode to validate tests, use registerValidation() to switch it on",
- "Now ncmp.cpp and wcmp.cpp are return WA if answer is suffix or prefix of the output",
- "Added InStream::readLong() and removed InStream::readLongint()",
- "Now no footer added to each report by default (use directive FOOTER to switch on)",
- "Now every checker has a name, use setName(const char* format, ...) to set it",
- "Now it is compatible with TTS (by Kittens Computing)",
- "Added \'ensure(condition, message = \"\")\' feature, it works like assert()",
- "Fixed compatibility with MS C++ 7.1",
- "Added footer with exit code information",
- "Added compatibility with EJUDGE (compile with EJUDGE directive)"
- };
- #ifdef _MSC_VER
- #define _CRT_SECURE_NO_DEPRECATE
- #define _CRT_SECURE_NO_WARNINGS
- #define _CRT_NO_VA_START_VALIDATION
- #endif
- /* Overrides random() for Borland C++. */
- #define random __random_deprecated
- #include <stdlib.h>
- #include <cstdlib>
- #include <climits>
- #include <algorithm>
- #undef random
- #include <cstdio>
- #include <cctype>
- #include <string>
- #include <vector>
- #include <map>
- #include <set>
- #include <cmath>
- #include <sstream>
- #include <fstream>
- #include <cstring>
- #include <limits>
- #include <stdarg.h>
- #include <fcntl.h>
- #if ( _WIN32 || __WIN32__ || _WIN64 || __WIN64__ || __CYGWIN__ )
- # if !defined(_MSC_VER) || _MSC_VER>1400
- # define NOMINMAX 1
- # include <windows.h>
- # else
- # define WORD unsigned short
- # include <unistd.h>
- # endif
- # include <io.h>
- # define ON_WINDOWS
- #else
- # define WORD unsigned short
- #endif
- #ifndef LLONG_MIN
- #define LLONG_MIN (-9223372036854775807LL - 1)
- #endif
- #ifndef ULLONG_MAX
- #define ULLONG_MAX (18446744073709551615)
- #endif
- #define LF ((char)10)
- #define CR ((char)13)
- #define TAB ((char)9)
- #define SPACE ((char)' ')
- #define EOFC (255)
- #ifndef OK_EXIT_CODE
- # define OK_EXIT_CODE 0
- #endif
- #ifndef WA_EXIT_CODE
- # ifdef EJUDGE
- # define WA_EXIT_CODE 5
- # else
- # define WA_EXIT_CODE 1
- # endif
- #endif
- #ifndef PE_EXIT_CODE
- # ifdef EJUDGE
- # define PE_EXIT_CODE 4
- # else
- # define PE_EXIT_CODE 2
- # endif
- #endif
- #ifndef FAIL_EXIT_CODE
- # ifdef EJUDGE
- # define FAIL_EXIT_CODE 6
- # else
- # define FAIL_EXIT_CODE 3
- # endif
- #endif
- #ifndef DIRT_EXIT_CODE
- # ifdef EJUDGE
- # define DIRT_EXIT_CODE 6
- # else
- # define DIRT_EXIT_CODE 4
- # endif
- #endif
- #ifndef POINTS_EXIT_CODE
- # define POINTS_EXIT_CODE 7
- #endif
- #ifndef UNEXPECTED_EOF_EXIT_CODE
- # define UNEXPECTED_EOF_EXIT_CODE 8
- #endif
- #ifndef PC_BASE_EXIT_CODE
- # ifdef TESTSYS
- # define PC_BASE_EXIT_CODE 50
- # else
- # define PC_BASE_EXIT_CODE 0
- # endif
- #endif
- #ifdef __GNUC__
- # define __TESTLIB_STATIC_ASSERT(condition) typedef void* __testlib_static_assert_type[(condition) ? 1 : -1] __attribute__((unused))
- #else
- # define __TESTLIB_STATIC_ASSERT(condition) typedef void* __testlib_static_assert_type[(condition) ? 1 : -1]
- #endif
- #ifdef ON_WINDOWS
- #define I64 "%I64d"
- #define U64 "%I64u"
- #else
- #define I64 "%lld"
- #define U64 "%llu"
- #endif
- #ifdef _MSC_VER
- # define NORETURN __declspec(noreturn)
- #elif defined __GNUC__
- # define NORETURN __attribute__ ((noreturn))
- #else
- # define NORETURN
- #endif
-
- static char __testlib_format_buffer[16777216];
- static int __testlib_format_buffer_usage_count = 0;
- #define FMT_TO_RESULT(fmt, cstr, result) std::string result; \
- if (__testlib_format_buffer_usage_count != 0) \
- __testlib_fail("FMT_TO_RESULT::__testlib_format_buffer_usage_count != 0"); \
- __testlib_format_buffer_usage_count++; \
- va_list ap; \
- va_start(ap, fmt); \
- std::vsprintf(__testlib_format_buffer, cstr, ap); \
- va_end(ap); \
- result = std::string(__testlib_format_buffer); \
- __testlib_format_buffer_usage_count--; \
- const long long __TESTLIB_LONGLONG_MAX = 9223372036854775807LL;
- NORETURN static void __testlib_fail(const std::string& message);
- template<typename T>
- static inline T __testlib_abs(const T& x)
- {
- return x > 0 ? x : -x;
- }
- template<typename T>
- static inline T __testlib_min(const T& a, const T& b)
- {
- return a < b ? a : b;
- }
- template<typename T>
- static inline T __testlib_max(const T& a, const T& b)
- {
- return a > b ? a : b;
- }
- static bool __testlib_prelimIsNaN(double r)
- {
- volatile double ra = r;
- #ifndef __BORLANDC__
- return ((ra != ra) == true) && ((ra == ra) == false) && ((1.0 > ra) == false) && ((1.0 < ra) == false);
- #else
- return std::_isnan(ra);
- #endif
- }
- static std::string removeDoubleTrailingZeroes(std::string value)
- {
- while (!value.empty() && value[value.length() - 1] == '0' && value.find('.') != std::string::npos)
- value = value.substr(0, value.length() - 1);
- return value + '0';
- }
- #ifdef __GNUC__
- __attribute__ ((format (printf, 1, 2)))
- #endif
- std::string format(const char* fmt, ...)
- {
- FMT_TO_RESULT(fmt, fmt, result);
- return result;
- }
- std::string format(const std::string fmt, ...)
- {
- FMT_TO_RESULT(fmt, fmt.c_str(), result);
- return result;
- }
- static std::string __testlib_part(const std::string& s);
- static bool __testlib_isNaN(double r)
- {
- __TESTLIB_STATIC_ASSERT(sizeof(double) == sizeof(long long));
- volatile double ra = r;
- long long llr1, llr2;
- std::memcpy((void*)&llr1, (void*)&ra, sizeof(double));
- ra = -ra;
- std::memcpy((void*)&llr2, (void*)&ra, sizeof(double));
- long long llnan = 0xFFF8000000000000;
- return __testlib_prelimIsNaN(r) || llnan == llr1 || llnan == llr2;
- }
- static double __testlib_nan()
- {
- __TESTLIB_STATIC_ASSERT(sizeof(double) == sizeof(long long));
- #ifndef NAN
- long long llnan = 0xFFF8000000000000;
- double nan;
- std::memcpy(&nan, &llnan, sizeof(double));
- return nan;
- #else
- return NAN;
- #endif
- }
- static bool __testlib_isInfinite(double r)
- {
- volatile double ra = r;
- return (ra > 1E300 || ra < -1E300);
- }
- #ifdef __GNUC__
- __attribute__((const))
- #endif
- inline bool doubleCompare(double expected, double result, double MAX_DOUBLE_ERROR)
- {
- if (__testlib_isNaN(expected))
- {
- return __testlib_isNaN(result);
- }
- else
- if (__testlib_isInfinite(expected))
- {
- if (expected > 0)
- {
- return result > 0 && __testlib_isInfinite(result);
- }
- else
- {
- return result < 0 && __testlib_isInfinite(result);
- }
- }
- else
- if (__testlib_isNaN(result) || __testlib_isInfinite(result))
- {
- return false;
- }
- else
- if (__testlib_abs(result - expected) <= MAX_DOUBLE_ERROR + 1E-15)
- {
- return true;
- }
- else
- {
- double minv = __testlib_min(expected * (1.0 - MAX_DOUBLE_ERROR),
- expected * (1.0 + MAX_DOUBLE_ERROR));
- double maxv = __testlib_max(expected * (1.0 - MAX_DOUBLE_ERROR),
- expected * (1.0 + MAX_DOUBLE_ERROR));
- return result + 1E-15 >= minv && result <= maxv + 1E-15;
- }
- }
- #ifdef __GNUC__
- __attribute__((const))
- #endif
- inline double doubleDelta(double expected, double result)
- {
- double absolute = __testlib_abs(result - expected);
-
- if (__testlib_abs(expected) > 1E-9)
- {
- double relative = __testlib_abs(absolute / expected);
- return __testlib_min(absolute, relative);
- }
- else
- return absolute;
- }
- #if !defined(_MSC_VER) || _MSC_VER<1900
- #ifndef _fileno
- #define _fileno(_stream) ((_stream)->_file)
- #endif
- #endif
- #ifndef O_BINARY
- static void __testlib_set_binary(
- #ifdef __GNUC__
- __attribute__((unused))
- #endif
- std::FILE* file
- )
- #else
- static void __testlib_set_binary(std::FILE* file)
- #endif
- {
- #ifdef O_BINARY
- if (NULL != file)
- {
- #ifndef __BORLANDC__
- _setmode(_fileno(file), O_BINARY);
- #else
- setmode(fileno(file), O_BINARY);
- #endif
- }
- #endif
- }
- /*
- * Very simple regex-like pattern.
- * It used for two purposes: validation and generation.
- *
- * For example, pattern("[a-z]{1,5}").next(rnd) will return
- * random string from lowercase latin letters with length
- * from 1 to 5. It is easier to call rnd.next("[a-z]{1,5}")
- * for the same effect.
- *
- * Another samples:
- * "mike|john" will generate (match) "mike" or "john";
- * "-?[1-9][0-9]{0,3}" will generate (match) non-zero integers from -9999 to 9999;
- * "id-([ac]|b{2})" will generate (match) "id-a", "id-bb", "id-c";
- * "[^0-9]*" will match sequences (empty or non-empty) without digits, you can't
- * use it for generations.
- *
- * You can't use pattern for generation if it contains meta-symbol '*'. Also it
- * is not recommended to use it for char-sets with meta-symbol '^' like [^a-z].
- *
- * For matching very simple greedy algorithm is used. For example, pattern
- * "[0-9]?1" will not match "1", because of greedy nature of matching.
- * Alternations (meta-symbols "|") are processed with brute-force algorithm, so
- * do not use many alternations in one expression.
- *
- * If you want to use one expression many times it is better to compile it into
- * a single pattern like "pattern p("[a-z]+")". Later you can use
- * "p.matches(std::string s)" or "p.next(random_t& rd)" to check matching or generate
- * new string by pattern.
- *
- * Simpler way to read token and check it for pattern matching is "inf.readToken("[a-z]+")".
- */
- class random_t;
- class pattern
- {
- public:
- /* Create pattern instance by string. */
- pattern(std::string s);
- /* Generate new string by pattern and given random_t. */
- std::string next(random_t& rnd) const;
- /* Checks if given string match the pattern. */
- bool matches(const std::string& s) const;
- /* Returns source string of the pattern. */
- std::string src() const;
- private:
- bool matches(const std::string& s, size_t pos) const;
- std::string s;
- std::vector<pattern> children;
- std::vector<char> chars;
- int from;
- int to;
- };
- /*
- * Use random_t instances to generate random values. It is preffered
- * way to use randoms instead of rand() function or self-written
- * randoms.
- *
- * Testlib defines global variable "rnd" of random_t class.
- * Use registerGen(argc, argv, 1) to setup random_t seed be command
- * line (to use latest random generator version).
- *
- * Random generates uniformly distributed values if another strategy is
- * not specified explicitly.
- */
- class random_t
- {
- private:
- unsigned long long seed;
- static const unsigned long long multiplier;
- static const unsigned long long addend;
- static const unsigned long long mask;
- static const int lim;
- long long nextBits(int bits)
- {
- if (bits <= 48)
- {
- seed = (seed * multiplier + addend) & mask;
- return (long long)(seed >> (48 - bits));
- }
- else
- {
- if (bits > 63)
- __testlib_fail("random_t::nextBits(int bits): n must be less than 64");
- int lowerBitCount = (random_t::version == 0 ? 31 : 32);
-
- long long left = (nextBits(31) << 32);
- long long right = nextBits(lowerBitCount);
-
- return left ^ right;
- }
- }
- public:
- static int version;
- /* New random_t with fixed seed. */
- random_t()
- : seed(3905348978240129619LL)
- {
- }
- /* Sets seed by command line. */
- void setSeed(int argc, char* argv[])
- {
- random_t p;
- seed = 3905348978240129619LL;
- for (int i = 1; i < argc; i++)
- {
- std::size_t le = std::strlen(argv[i]);
- for (std::size_t j = 0; j < le; j++)
- seed = seed * multiplier + (unsigned int)(argv[i][j]) + addend;
- seed += multiplier / addend;
- }
- seed = seed & mask;
- }
- /* Sets seed by given value. */
- void setSeed(long long _seed)
- {
- _seed = (_seed ^ multiplier) & mask;
- seed = _seed;
- }
- #ifndef __BORLANDC__
- /* Random string value by given pattern (see pattern documentation). */
- std::string next(const std::string& ptrn)
- {
- pattern p(ptrn);
- return p.next(*this);
- }
- #else
- /* Random string value by given pattern (see pattern documentation). */
- std::string next(std::string ptrn)
- {
- pattern p(ptrn);
- return p.next(*this);
- }
- #endif
- /* Random value in range [0, n-1]. */
- int next(int n)
- {
- if (n <= 0)
- __testlib_fail("random_t::next(int n): n must be positive");
- if ((n & -n) == n) // n is a power of 2
- return (int)((n * (long long)nextBits(31)) >> 31);
- const long long limit = INT_MAX / n * n;
-
- long long bits;
- do {
- bits = nextBits(31);
- } while (bits >= limit);
- return int(bits % n);
- }
- /* Random value in range [0, n-1]. */
- unsigned int next(unsigned int n)
- {
- if (n >= INT_MAX)
- __testlib_fail("random_t::next(unsigned int n): n must be less INT_MAX");
- return (unsigned int)next(int(n));
- }
- /* Random value in range [0, n-1]. */
- long long next(long long n)
- {
- if (n <= 0)
- __testlib_fail("random_t::next(long long n): n must be positive");
- const long long limit = __TESTLIB_LONGLONG_MAX / n * n;
-
- long long bits;
- do {
- bits = nextBits(63);
- } while (bits >= limit);
- return bits % n;
- }
- /* Random value in range [0, n-1]. */
- unsigned long long next(unsigned long long n)
- {
- if (n >= (unsigned long long)(__TESTLIB_LONGLONG_MAX))
- __testlib_fail("random_t::next(unsigned long long n): n must be less LONGLONG_MAX");
- return (unsigned long long)next((long long)(n));
- }
- /* Random value in range [0, n-1]. */
- long next(long n)
- {
- return (long)next((long long)(n));
- }
- /* Random value in range [0, n-1]. */
- unsigned long next(unsigned long n)
- {
- if (n >= (unsigned long)(LONG_MAX))
- __testlib_fail("random_t::next(unsigned long n): n must be less LONG_MAX");
- return (unsigned long)next((unsigned long long)(n));
- }
- /* Returns random value in range [from,to]. */
- int next(int from, int to)
- {
- return int(next((long long)to - from + 1) + from);
- }
- /* Returns random value in range [from,to]. */
- unsigned int next(unsigned int from, unsigned int to)
- {
- return (unsigned int)(next((long long)to - from + 1) + from);
- }
- /* Returns random value in range [from,to]. */
- long long next(long long from, long long to)
- {
- return next(to - from + 1) + from;
- }
- /* Returns random value in range [from,to]. */
- unsigned long long next(unsigned long long from, unsigned long long to)
- {
- if (from > to)
- __testlib_fail("random_t::next(unsigned long long from, unsigned long long to): from can't not exceed to");
- return next(to - from + 1) + from;
- }
- /* Returns random value in range [from,to]. */
- long next(long from, long to)
- {
- return next(to - from + 1) + from;
- }
- /* Returns random value in range [from,to]. */
- unsigned long next(unsigned long from, unsigned long to)
- {
- if (from > to)
- __testlib_fail("random_t::next(unsigned long from, unsigned long to): from can't not exceed to");
- return next(to - from + 1) + from;
- }
- /* Random double value in range [0, 1). */
- double next()
- {
- long long left = ((long long)(nextBits(26)) << 27);
- long long right = nextBits(27);
- return (double)(left + right) / (double)(1LL << 53);
- }
- /* Random double value in range [0, n). */
- double next(double n)
- {
- return n * next();
- }
- /* Random double value in range [from, to). */
- double next(double from, double to)
- {
- if (from > to)
- __testlib_fail("random_t::next(double from, double to): from can't not exceed to");
- return next(to - from) + from;
- }
- /* Returns random element from container. */
- template <typename Container>
- typename Container::value_type any(const Container& c)
- {
- size_t size = c.size();
- if (size <= 0)
- __testlib_fail("random_t::any(const Container& c): c.size() must be positive");
- return *(c.begin() + next(size));
- }
- /* Returns random element from iterator range. */
- template <typename Iter>
- typename Iter::value_type any(const Iter& begin, const Iter& end)
- {
- int size = int(end - begin);
- if (size <= 0)
- __testlib_fail("random_t::any(const Iter& begin, const Iter& end): range must have positive length");
- return *(begin + next(size));
- }
- /* Random string value by given pattern (see pattern documentation). */
- #ifdef __GNUC__
- __attribute__ ((format (printf, 2, 3)))
- #endif
- std::string next(const char* format, ...)
- {
- FMT_TO_RESULT(format, format, ptrn);
- return next(ptrn);
- }
- /*
- * Weighted next. If type == 0 than it is usual "next()".
- *
- * If type = 1, than it returns "max(next(), next())"
- * (the number of "max" functions equals to "type").
- *
- * If type < 0, than "max" function replaces with "min".
- */
- int wnext(int n, int type)
- {
- if (n <= 0)
- __testlib_fail("random_t::wnext(int n, int type): n must be positive");
-
- if (abs(type) < random_t::lim)
- {
- int result = next(n);
- for (int i = 0; i < +type; i++)
- result = __testlib_max(result, next(n));
-
- for (int i = 0; i < -type; i++)
- result = __testlib_min(result, next(n));
- return result;
- }
- else
- {
- double p;
-
- if (type > 0)
- p = std::pow(next() + 0.0, 1.0 / (type + 1));
- else
- p = 1 - std::pow(next() + 0.0, 1.0 / (-type + 1));
- return int(n * p);
- }
- }
-
- /* See wnext(int, int). It uses the same algorithms. */
- long long wnext(long long n, int type)
- {
- if (n <= 0)
- __testlib_fail("random_t::wnext(long long n, int type): n must be positive");
-
- if (abs(type) < random_t::lim)
- {
- long long result = next(n);
- for (int i = 0; i < +type; i++)
- result = __testlib_max(result, next(n));
-
- for (int i = 0; i < -type; i++)
- result = __testlib_min(result, next(n));
- return result;
- }
- else
- {
- double p;
-
- if (type > 0)
- p = std::pow(next() + 0.0, 1.0 / (type + 1));
- else
- p = std::pow(next() + 0.0, - type + 1);
- return __testlib_min(__testlib_max((long long)(double(n) * p), 0LL), n - 1LL);
- }
- }
-
- /* See wnext(int, int). It uses the same algorithms. */
- double wnext(int type)
- {
- if (abs(type) < random_t::lim)
- {
- double result = next();
- for (int i = 0; i < +type; i++)
- result = __testlib_max(result, next());
-
- for (int i = 0; i < -type; i++)
- result = __testlib_min(result, next());
- return result;
- }
- else
- {
- double p;
-
- if (type > 0)
- p = std::pow(next() + 0.0, 1.0 / (type + 1));
- else
- p = std::pow(next() + 0.0, - type + 1);
- return p;
- }
- }
-
- /* See wnext(int, int). It uses the same algorithms. */
- double wnext(double n, int type)
- {
- if (n <= 0)
- __testlib_fail("random_t::wnext(double n, int type): n must be positive");
- if (abs(type) < random_t::lim)
- {
- double result = next();
- for (int i = 0; i < +type; i++)
- result = __testlib_max(result, next());
-
- for (int i = 0; i < -type; i++)
- result = __testlib_min(result, next());
- return n * result;
- }
- else
- {
- double p;
-
- if (type > 0)
- p = std::pow(next() + 0.0, 1.0 / (type + 1));
- else
- p = std::pow(next() + 0.0, - type + 1);
- return n * p;
- }
- }
- /* See wnext(int, int). It uses the same algorithms. */
- unsigned int wnext(unsigned int n, int type)
- {
- if (n >= INT_MAX)
- __testlib_fail("random_t::wnext(unsigned int n, int type): n must be less INT_MAX");
- return (unsigned int)wnext(int(n), type);
- }
-
- /* See wnext(int, int). It uses the same algorithms. */
- unsigned long long wnext(unsigned long long n, int type)
- {
- if (n >= (unsigned long long)(__TESTLIB_LONGLONG_MAX))
- __testlib_fail("random_t::wnext(unsigned long long n, int type): n must be less LONGLONG_MAX");
- return (unsigned long long)wnext((long long)(n), type);
- }
- /* See wnext(int, int). It uses the same algorithms. */
- long wnext(long n, int type)
- {
- return (long)wnext((long long)(n), type);
- }
-
- /* See wnext(int, int). It uses the same algorithms. */
- unsigned long wnext(unsigned long n, int type)
- {
- if (n >= (unsigned long)(LONG_MAX))
- __testlib_fail("random_t::wnext(unsigned long n, int type): n must be less LONG_MAX");
- return (unsigned long)wnext((unsigned long long)(n), type);
- }
- /* Returns weighted random value in range [from, to]. */
- int wnext(int from, int to, int type)
- {
- if (from > to)
- __testlib_fail("random_t::wnext(int from, int to, int type): from can't not exceed to");
- return wnext(to - from + 1, type) + from;
- }
-
- /* Returns weighted random value in range [from, to]. */
- int wnext(unsigned int from, unsigned int to, int type)
- {
- if (from > to)
- __testlib_fail("random_t::wnext(unsigned int from, unsigned int to, int type): from can't not exceed to");
- return int(wnext(to - from + 1, type) + from);
- }
-
- /* Returns weighted random value in range [from, to]. */
- long long wnext(long long from, long long to, int type)
- {
- if (from > to)
- __testlib_fail("random_t::wnext(long long from, long long to, int type): from can't not exceed to");
- return wnext(to - from + 1, type) + from;
- }
-
- /* Returns weighted random value in range [from, to]. */
- unsigned long long wnext(unsigned long long from, unsigned long long to, int type)
- {
- if (from > to)
- __testlib_fail("random_t::wnext(unsigned long long from, unsigned long long to, int type): from can't not exceed to");
- return wnext(to - from + 1, type) + from;
- }
-
- /* Returns weighted random value in range [from, to]. */
- long wnext(long from, long to, int type)
- {
- if (from > to)
- __testlib_fail("random_t::wnext(long from, long to, int type): from can't not exceed to");
- return wnext(to - from + 1, type) + from;
- }
-
- /* Returns weighted random value in range [from, to]. */
- unsigned long wnext(unsigned long from, unsigned long to, int type)
- {
- if (from > to)
- __testlib_fail("random_t::wnext(unsigned long from, unsigned long to, int type): from can't not exceed to");
- return wnext(to - from + 1, type) + from;
- }
-
- /* Returns weighted random double value in range [from, to). */
- double wnext(double from, double to, int type)
- {
- if (from > to)
- __testlib_fail("random_t::wnext(double from, double to, int type): from can't not exceed to");
- return wnext(to - from, type) + from;
- }
- /* Returns weighted random element from container. */
- template <typename Container>
- typename Container::value_type wany(const Container& c, int type)
- {
- size_t size = c.size();
- if (size <= 0)
- __testlib_fail("random_t::wany(const Container& c, int type): c.size() must be positive");
- return *(c.begin() + wnext(size, type));
- }
- /* Returns weighted random element from iterator range. */
- template <typename Iter>
- typename Iter::value_type wany(const Iter& begin, const Iter& end, int type)
- {
- int size = int(end - begin);
- if (size <= 0)
- __testlib_fail("random_t::any(const Iter& begin, const Iter& end, int type): range must have positive length");
- return *(begin + wnext(size, type));
- }
- };
- const int random_t::lim = 25;
- const unsigned long long random_t::multiplier = 0x5DEECE66DLL;
- const unsigned long long random_t::addend = 0xBLL;
- const unsigned long long random_t::mask = (1LL << 48) - 1;
- int random_t::version = -1;
- /* Pattern implementation */
- bool pattern::matches(const std::string& s) const
- {
- return matches(s, 0);
- }
- static bool __pattern_isSlash(const std::string& s, size_t pos)
- {
- return s[pos] == '\\';
- }
- #ifdef __GNUC__
- __attribute__((pure))
- #endif
- static bool __pattern_isCommandChar(const std::string& s, size_t pos, char value)
- {
- if (pos >= s.length())
- return false;
- int slashes = 0;
- int before = int(pos) - 1;
- while (before >= 0 && s[before] == '\\')
- before--, slashes++;
- return slashes % 2 == 0 && s[pos] == value;
- }
- static char __pattern_getChar(const std::string& s, size_t& pos)
- {
- if (__pattern_isSlash(s, pos))
- pos += 2;
- else
- pos++;
- return s[pos - 1];
- }
- #ifdef __GNUC__
- __attribute__((pure))
- #endif
- static int __pattern_greedyMatch(const std::string& s, size_t pos, const std::vector<char> chars)
- {
- int result = 0;
- while (pos < s.length())
- {
- char c = s[pos++];
- if (!std::binary_search(chars.begin(), chars.end(), c))
- break;
- else
- result++;
- }
- return result;
- }
- std::string pattern::src() const
- {
- return s;
- }
- bool pattern::matches(const std::string& s, size_t pos) const
- {
- std::string result;
- if (to > 0)
- {
- int size = __pattern_greedyMatch(s, pos, chars);
- if (size < from)
- return false;
- if (size > to)
- size = to;
- pos += size;
- }
- if (children.size() > 0)
- {
- for (size_t child = 0; child < children.size(); child++)
- if (children[child].matches(s, pos))
- return true;
- return false;
- }
- else
- return pos == s.length();
- }
- std::string pattern::next(random_t& rnd) const
- {
- std::string result;
- result.reserve(20);
- if (to == INT_MAX)
- __testlib_fail("pattern::next(random_t& rnd): can't process character '*' for generation");
- if (to > 0)
- {
- int count = rnd.next(to - from + 1) + from;
- for (int i = 0; i < count; i++)
- result += chars[rnd.next(int(chars.size()))];
- }
- if (children.size() > 0)
- {
- int child = rnd.next(int(children.size()));
- result += children[child].next(rnd);
- }
- return result;
- }
- static void __pattern_scanCounts(const std::string& s, size_t& pos, int& from, int& to)
- {
- if (pos >= s.length())
- {
- from = to = 1;
- return;
- }
-
- if (__pattern_isCommandChar(s, pos, '{'))
- {
- std::vector<std::string> parts;
- std::string part;
- pos++;
- while (pos < s.length() && !__pattern_isCommandChar(s, pos, '}'))
- {
- if (__pattern_isCommandChar(s, pos, ','))
- parts.push_back(part), part = "", pos++;
- else
- part += __pattern_getChar(s, pos);
- }
- if (part != "")
- parts.push_back(part);
- if (!__pattern_isCommandChar(s, pos, '}'))
- __testlib_fail("pattern: Illegal pattern (or part) \"" + s + "\"");
- pos++;
- if (parts.size() < 1 || parts.size() > 2)
- __testlib_fail("pattern: Illegal pattern (or part) \"" + s + "\"");
- std::vector<int> numbers;
- for (size_t i = 0; i < parts.size(); i++)
- {
- if (parts[i].length() == 0)
- __testlib_fail("pattern: Illegal pattern (or part) \"" + s + "\"");
- int number;
- if (std::sscanf(parts[i].c_str(), "%d", &number) != 1)
- __testlib_fail("pattern: Illegal pattern (or part) \"" + s + "\"");
- numbers.push_back(number);
- }
- if (numbers.size() == 1)
- from = to = numbers[0];
- else
- from = numbers[0], to = numbers[1];
- if (from > to)
- __testlib_fail("pattern: Illegal pattern (or part) \"" + s + "\"");
- }
- else
- {
- if (__pattern_isCommandChar(s, pos, '?'))
- {
- from = 0, to = 1, pos++;
- return;
- }
- if (__pattern_isCommandChar(s, pos, '*'))
- {
- from = 0, to = INT_MAX, pos++;
- return;
- }
- if (__pattern_isCommandChar(s, pos, '+'))
- {
- from = 1, to = INT_MAX, pos++;
- return;
- }
-
- from = to = 1;
- }
- }
- static std::vector<char> __pattern_scanCharSet(const std::string& s, size_t& pos)
- {
- if (pos >= s.length())
- __testlib_fail("pattern: Illegal pattern (or part) \"" + s + "\"");
- std::vector<char> result;
- if (__pattern_isCommandChar(s, pos, '['))
- {
- pos++;
- bool negative = __pattern_isCommandChar(s, pos, '^');
- char prev = 0;
- while (pos < s.length() && !__pattern_isCommandChar(s, pos, ']'))
- {
- if (__pattern_isCommandChar(s, pos, '-') && prev != 0)
- {
- pos++;
- if (pos + 1 == s.length() || __pattern_isCommandChar(s, pos, ']'))
- {
- result.push_back(prev);
- prev = '-';
- continue;
- }
- char next = __pattern_getChar(s, pos);
- if (prev > next)
- __testlib_fail("pattern: Illegal pattern (or part) \"" + s + "\"");
- for (char c = prev; c != next; c++)
- result.push_back(c);
- result.push_back(next);
- prev = 0;
- }
- else
- {
- if (prev != 0)
- result.push_back(prev);
- prev = __pattern_getChar(s, pos);
- }
- }
- if (prev != 0)
- result.push_back(prev);
- if (!__pattern_isCommandChar(s, pos, ']'))
- __testlib_fail("pattern: Illegal pattern (or part) \"" + s + "\"");
- pos++;
- if (negative)
- {
- std::sort(result.begin(), result.end());
- std::vector<char> actuals;
- for (int code = 0; code < 255; code++)
- {
- char c = char(code);
- if (!std::binary_search(result.begin(), result.end(), c))
- actuals.push_back(c);
- }
- result = actuals;
- }
- std::sort(result.begin(), result.end());
- }
- else
- result.push_back(__pattern_getChar(s, pos));
- return result;
- }
- pattern::pattern(std::string s): s(s), from(0), to(0)
- {
- std::string t;
- for (size_t i = 0; i < s.length(); i++)
- if (!__pattern_isCommandChar(s, i, ' '))
- t += s[i];
- s = t;
- int opened = 0;
- int firstClose = -1;
- std::vector<int> seps;
- for (size_t i = 0; i < s.length(); i++)
- {
- if (__pattern_isCommandChar(s, i, '('))
- {
- opened++;
- continue;
- }
- if (__pattern_isCommandChar(s, i, ')'))
- {
- opened--;
- if (opened == 0 && firstClose == -1)
- firstClose = int(i);
- continue;
- }
-
- if (opened < 0)
- __testlib_fail("pattern: Illegal pattern (or part) \"" + s + "\"");
- if (__pattern_isCommandChar(s, i, '|') && opened == 0)
- seps.push_back(int(i));
- }
- if (opened != 0)
- __testlib_fail("pattern: Illegal pattern (or part) \"" + s + "\"");
- if (seps.size() == 0 && firstClose + 1 == (int)s.length()
- && __pattern_isCommandChar(s, 0, '(') && __pattern_isCommandChar(s, s.length() - 1, ')'))
- {
- children.push_back(pattern(s.substr(1, s.length() - 2)));
- }
- else
- {
- if (seps.size() > 0)
- {
- seps.push_back(int(s.length()));
- int last = 0;
- for (size_t i = 0; i < seps.size(); i++)
- {
- children.push_back(pattern(s.substr(last, seps[i] - last)));
- last = seps[i] + 1;
- }
- }
- else
- {
- size_t pos = 0;
- chars = __pattern_scanCharSet(s, pos);
- __pattern_scanCounts(s, pos, from, to);
- if (pos < s.length())
- children.push_back(pattern(s.substr(pos)));
- }
- }
- }
- /* End of pattern implementation */
- template <typename C>
- inline bool isEof(C c)
- {
- return c == EOFC;
- }
- template <typename C>
- inline bool isEoln(C c)
- {
- return (c == LF || c == CR);
- }
- template<typename C>
- inline bool isBlanks(C c)
- {
- return (c == LF || c == CR || c == SPACE || c == TAB);
- }
- enum TMode
- {
- _input, _output, _answer
- };
- /* Outcomes 6-15 are reserved for future use. */
- enum TResult
- {
- _ok = 0,
- _wa = 1,
- _pe = 2,
- _fail = 3,
- _dirt = 4,
- _points = 5,
- _unexpected_eof = 8,
- _partially = 16
- };
- enum TTestlibMode
- {
- _unknown, _checker, _validator, _generator, _interactor
- };
- #define _pc(exitCode) (TResult(_partially + (exitCode)))
- /* Outcomes 6-15 are reserved for future use. */
- const std::string outcomes[] = {
- "accepted",
- "wrong-answer",
- "presentation-error",
- "fail",
- "fail",
- #ifndef PCMS2
- "points",
- #else
- "relative-scoring",
- #endif
- "reserved",
- "reserved",
- "unexpected-eof",
- "reserved",
- "reserved",
- "reserved",
- "reserved",
- "reserved",
- "reserved",
- "reserved",
- "partially-correct"
- };
- class InputStreamReader
- {
- public:
- virtual int curChar() = 0;
- virtual int nextChar() = 0;
- virtual void skipChar() = 0;
- virtual void unreadChar(int c) = 0;
- virtual std::string getName() = 0;
- virtual bool eof() = 0;
- virtual void close() = 0;
- virtual ~InputStreamReader() = 0;
- };
- InputStreamReader::~InputStreamReader()
- {
- // No operations.
- }
- class StringInputStreamReader: public InputStreamReader
- {
- private:
- std::string s;
- size_t pos;
- public:
- StringInputStreamReader(const std::string& content): s(content), pos(0)
- {
- // No operations.
- }
- int curChar()
- {
- if (pos >= s.length())
- return EOFC;
- else
- return s[pos];
- }
- int nextChar()
- {
- if (pos >= s.length())
- {
- pos++;
- return EOFC;
- }
- else
- return s[pos++];
- }
- void skipChar()
- {
- pos++;
- }
- void unreadChar(int c)
- {
- if (pos == 0)
- __testlib_fail("FileFileInputStreamReader::unreadChar(int): pos == 0.");
- pos--;
- if (pos < s.length())
- s[pos] = char(c);
- }
- std::string getName()
- {
- return __testlib_part(s);
- }
- bool eof()
- {
- return pos >= s.length();
- }
- void close()
- {
- // No operations.
- }
- };
- class FileInputStreamReader: public InputStreamReader
- {
- private:
- std::FILE* file;
- std::string name;
- inline int postprocessGetc(int getcResult)
- {
- if (getcResult != EOF)
- return getcResult;
- else
- return EOFC;
- }
- public:
- FileInputStreamReader(std::FILE* file, const std::string& name): file(file), name(name)
- {
- // No operations.
- }
- int curChar()
- {
- if (feof(file))
- return EOFC;
- else
- {
- int c = getc(file);
- ungetc(c, file);
- return postprocessGetc(c);
- }
- }
- int nextChar()
- {
- if (feof(file))
- return EOFC;
- else
- return postprocessGetc(getc(file));
- }
- void skipChar()
- {
- getc(file);
- }
- void unreadChar(int c)
- {
- ungetc(c, file);
- }
- std::string getName()
- {
- return name;
- }
- bool eof()
- {
- if (NULL == file || feof(file))
- return true;
- else
- {
- int c = nextChar();
- if (c == EOFC || (c == EOF && feof(file)))
- return true;
- unreadChar(c);
- return false;
- }
- }
- void close()
- {
- if (NULL != file)
- {
- fclose(file);
- file = NULL;
- }
- }
- };
- class BufferedFileInputStreamReader: public InputStreamReader
- {
- private:
- static const size_t BUFFER_SIZE;
- static const size_t MAX_UNREAD_COUNT;
-
- std::FILE* file;
- char* buffer;
- bool* isEof;
- int bufferPos;
- size_t bufferSize;
- std::string name;
- bool refill()
- {
- if (NULL == file)
- __testlib_fail("BufferedFileInputStreamReader: file == NULL (" + getName() + ")");
- if (bufferPos >= int(bufferSize))
- {
- size_t readSize = fread(
- buffer + MAX_UNREAD_COUNT,
- 1,
- BUFFER_SIZE - MAX_UNREAD_COUNT,
- file
- );
- if (readSize < BUFFER_SIZE - MAX_UNREAD_COUNT
- && ferror(file))
- __testlib_fail("BufferedFileInputStreamReader: unable to read (" + getName() + ")");
- bufferSize = MAX_UNREAD_COUNT + readSize;
- bufferPos = int(MAX_UNREAD_COUNT);
- std::memset(isEof + MAX_UNREAD_COUNT, 0, sizeof(isEof[0]) * readSize);
- return readSize > 0;
- }
- else
- return true;
- }
- public:
- BufferedFileInputStreamReader(std::FILE* file, const std::string& name): file(file), name(name)
- {
- buffer = new char[BUFFER_SIZE];
- isEof = new bool[BUFFER_SIZE];
- bufferSize = MAX_UNREAD_COUNT;
- bufferPos = int(MAX_UNREAD_COUNT);
- }
- ~BufferedFileInputStreamReader()
- {
- if (NULL != buffer)
- {
- delete[] buffer;
- buffer = NULL;
- }
- if (NULL != isEof)
- {
- delete[] isEof;
- isEof = NULL;
- }
- }
- int curChar()
- {
- if (!refill())
- return EOFC;
- return isEof[bufferPos] ? EOFC : buffer[bufferPos];
- }
- int nextChar()
- {
- if (!refill())
- return EOFC;
- return isEof[bufferPos] ? EOFC : buffer[bufferPos++];
- }
- void skipChar()
- {
- bufferPos++;
- }
- void unreadChar(int c)
- {
- bufferPos--;
- if (bufferPos < 0)
- __testlib_fail("BufferedFileInputStreamReader::unreadChar(int): bufferPos < 0");
- isEof[bufferPos] = (c == EOFC);
- buffer[bufferPos] = char(c);
- }
- std::string getName()
- {
- return name;
- }
-
- bool eof()
- {
- return !refill() || EOFC == curChar();
- }
- void close()
- {
- if (NULL != file)
- {
- fclose(file);
- file = NULL;
- }
- }
- };
- const size_t BufferedFileInputStreamReader::BUFFER_SIZE = 2000000;
- const size_t BufferedFileInputStreamReader::MAX_UNREAD_COUNT = BufferedFileInputStreamReader::BUFFER_SIZE / 2;
- /*
- * Streams to be used for reading data in checkers or validators.
- * Each read*() method moves pointer to the next character after the
- * read value.
- */
- struct InStream
- {
- /* Do not use them. */
- InStream();
- ~InStream();
- /* Wrap std::string with InStream. */
- InStream(const InStream& baseStream, std::string content);
- InputStreamReader* reader;
- std::string name;
- TMode mode;
- bool opened;
- bool stdfile;
- bool strict;
- int wordReserveSize;
- std::string _tmpReadToken;
- int readManyIteration;
- void init(std::string fileName, TMode mode);
- void init(std::FILE* f, TMode mode);
- /* Moves stream pointer to the first non-white-space character or EOF. */
- void skipBlanks();
-
- /* Returns current character in the stream. Doesn't remove it from stream. */
- char curChar();
- /* Moves stream pointer one character forward. */
- void skipChar();
- /* Returns current character and moves pointer one character forward. */
- char nextChar();
-
- /* Returns current character and moves pointer one character forward. */
- char readChar();
- /* As "readChar()" but ensures that the result is equal to given parameter. */
- char readChar(char c);
- /* As "readChar()" but ensures that the result is equal to the space (code=32). */
- char readSpace();
- /* Puts back the character into the stream. */
- void unreadChar(char c);
- /* Reopens stream, you should not use it. */
- void reset(std::FILE* file = NULL);
- /* Checks that current position is EOF. If not it doesn't move stream pointer. */
- bool eof();
- /* Moves pointer to the first non-white-space character and calls "eof()". */
- bool seekEof();
- /*
- * Checks that current position contains EOLN.
- * If not it doesn't move stream pointer.
- * In strict mode expects "#13#10" for windows or "#10" for other platforms.
- */
- bool eoln();
- /* Moves pointer to the first non-space and non-tab character and calls "eoln()". */
- bool seekEoln();
- /* Moves stream pointer to the first character of the next line (if exists). */
- void nextLine();
- /*
- * Reads new token. Ignores white-spaces into the non-strict mode
- * (strict mode is used in validators usually).
- */
- std::string readWord();
- /* The same as "readWord()", it is preffered to use "readToken()". */
- std::string readToken();
- /* The same as "readWord()", but ensures that token matches to given pattern. */
- std::string readWord(const std::string& ptrn, const std::string& variableName = "");
- std::string readWord(const pattern& p, const std::string& variableName = "");
- std::vector<std::string> readWords(int size, const std::string& ptrn, const std::string& variablesName = "", int indexBase = 1);
- std::vector<std::string> readWords(int size, const pattern& p, const std::string& variablesName = "", int indexBase = 1);
- /* The same as "readToken()", but ensures that token matches to given pattern. */
- std::string readToken(const std::string& ptrn, const std::string& variableName = "");
- std::string readToken(const pattern& p, const std::string& variableName = "");
- std::vector<std::string> readTokens(int size, const std::string& ptrn, const std::string& variablesName = "", int indexBase = 1);
- std::vector<std::string> readTokens(int size, const pattern& p, const std::string& variablesName = "", int indexBase = 1);
- void readWordTo(std::string& result);
- void readWordTo(std::string& result, const pattern& p, const std::string& variableName = "");
- void readWordTo(std::string& result, const std::string& ptrn, const std::string& variableName = "");
- void readTokenTo(std::string& result);
- void readTokenTo(std::string& result, const pattern& p, const std::string& variableName = "");
- void readTokenTo(std::string& result, const std::string& ptrn, const std::string& variableName = "");
- /*
- * Reads new long long value. Ignores white-spaces into the non-strict mode
- * (strict mode is used in validators usually).
- */
- long long readLong();
- unsigned long long readUnsignedLong();
- /*
- * Reads new int. Ignores white-spaces into the non-strict mode
- * (strict mode is used in validators usually).
- */
- int readInteger();
- /*
- * Reads new int. Ignores white-spaces into the non-strict mode
- * (strict mode is used in validators usually).
- */
- int readInt();
- /* As "readLong()" but ensures that value in the range [minv,maxv]. */
- long long readLong(long long minv, long long maxv, const std::string& variableName = "");
- /* Reads space-separated sequence of long longs. */
- std::vector<long long> readLongs(int size, long long minv, long long maxv, const std::string& variablesName = "", int indexBase = 1);
- unsigned long long readUnsignedLong(unsigned long long minv, unsigned long long maxv, const std::string& variableName = "");
- std::vector<unsigned long long> readUnsignedLongs(int size, unsigned long long minv, unsigned long long maxv, const std::string& variablesName = "", int indexBase = 1);
- unsigned long long readLong(unsigned long long minv, unsigned long long maxv, const std::string& variableName = "");
- std::vector<unsigned long long> readLongs(int size, unsigned long long minv, unsigned long long maxv, const std::string& variablesName = "", int indexBase = 1);
- /* As "readInteger()" but ensures that value in the range [minv,maxv]. */
- int readInteger(int minv, int maxv, const std::string& variableName = "");
- /* As "readInt()" but ensures that value in the range [minv,maxv]. */
- int readInt(int minv, int maxv, const std::string& variableName = "");
- /* Reads space-separated sequence of integers. */
- std::vector<int> readIntegers(int size, int minv, int maxv, const std::string& variablesName = "", int indexBase = 1);
- /* Reads space-separated sequence of integers. */
- std::vector<int> readInts(int size, int minv, int maxv, const std::string& variablesName = "", int indexBase = 1);
- /*
- * Reads new double. Ignores white-spaces into the non-strict mode
- * (strict mode is used in validators usually).
- */
- double readReal();
- /*
- * Reads new double. Ignores white-spaces into the non-strict mode
- * (strict mode is used in validators usually).
- */
- double readDouble();
-
- /* As "readReal()" but ensures that value in the range [minv,maxv]. */
- double readReal(double minv, double maxv, const std::string& variableName = "");
- std::vector<double> readReals(int size, double minv, double maxv, const std::string& variablesName = "", int indexBase = 1);
- /* As "readDouble()" but ensures that value in the range [minv,maxv]. */
- double readDouble(double minv, double maxv, const std::string& variableName = "");
- std::vector<double> readDoubles(int size, double minv, double maxv, const std::string& variablesName = "", int indexBase = 1);
-
- /*
- * As "readReal()" but ensures that value in the range [minv,maxv] and
- * number of digit after the decimal point is in range [minAfterPointDigitCount,maxAfterPointDigitCount]
- * and number is in the form "[-]digit(s)[.digit(s)]".
- */
- double readStrictReal(double minv, double maxv,
- int minAfterPointDigitCount, int maxAfterPointDigitCount,
- const std::string& variableName = "");
- std::vector<double> readStrictReals(int size, double minv, double maxv,
- int minAfterPointDigitCount, int maxAfterPointDigitCount,
- const std::string& variablesName = "", int indexBase = 1);
- /*
- * As "readDouble()" but ensures that value in the range [minv,maxv] and
- * number of digit after the decimal point is in range [minAfterPointDigitCount,maxAfterPointDigitCount]
- * and number is in the form "[-]digit(s)[.digit(s)]".
- */
- double readStrictDouble(double minv, double maxv,
- int minAfterPointDigitCount, int maxAfterPointDigitCount,
- const std::string& variableName = "");
- std::vector<double> readStrictDoubles(int size, double minv, double maxv,
- int minAfterPointDigitCount, int maxAfterPointDigitCount,
- const std::string& variablesName = "", int indexBase = 1);
-
- /* As readLine(). */
- std::string readString();
- /* Read many lines. */
- std::vector<std::string> readStrings(int size, int indexBase = 1);
- /* See readLine(). */
- void readStringTo(std::string& result);
- /* The same as "readLine()/readString()", but ensures that line matches to the given pattern. */
- std::string readString(const pattern& p, const std::string& variableName = "");
- /* The same as "readLine()/readString()", but ensures that line matches to the given pattern. */
- std::string readString(const std::string& ptrn, const std::string& variableName = "");
- /* Read many lines. */
- std::vector<std::string> readStrings(int size, const pattern& p, const std::string& variableName = "", int indexBase = 1);
- /* Read many lines. */
- std::vector<std::string> readStrings(int size, const std::string& ptrn, const std::string& variableName = "", int indexBase = 1);
- /* The same as "readLine()/readString()", but ensures that line matches to the given pattern. */
- void readStringTo(std::string& result, const pattern& p, const std::string& variableName = "");
- /* The same as "readLine()/readString()", but ensures that line matches to the given pattern. */
- void readStringTo(std::string& result, const std::string& ptrn, const std::string& variableName = "");
- /*
- * Reads line from the current position to EOLN or EOF. Moves stream pointer to
- * the first character of the new line (if possible).
- */
- std::string readLine();
- /* Read many lines. */
- std::vector<std::string> readLines(int size, int indexBase = 1);
- /* See readLine(). */
- void readLineTo(std::string& result);
- /* The same as "readLine()", but ensures that line matches to the given pattern. */
- std::string readLine(const pattern& p, const std::string& variableName = "");
- /* The same as "readLine()", but ensures that line matches to the given pattern. */
- std::string readLine(const std::string& ptrn, const std::string& variableName = "");
- /* Read many lines. */
- std::vector<std::string> readLines(int size, const pattern& p, const std::string& variableName = "", int indexBase = 1);
- /* Read many lines. */
- std::vector<std::string> readLines(int size, const std::string& ptrn, const std::string& variableName = "", int indexBase = 1);
- /* The same as "readLine()", but ensures that line matches to the given pattern. */
- void readLineTo(std::string& result, const pattern& p, const std::string& variableName = "");
- /* The same as "readLine()", but ensures that line matches to the given pattern. */
- void readLineTo(std::string& result, const std::string& ptrn, const std::string& variableName = "");
- /* Reads EOLN or fails. Use it in validators. Calls "eoln()" method internally. */
- void readEoln();
- /* Reads EOF or fails. Use it in validators. Calls "eof()" method internally. */
- void readEof();
- /*
- * Quit-functions aborts program with <result> and <message>:
- * input/answer streams replace any result to FAIL.
- */
- NORETURN void quit(TResult result, const char* msg);
- /*
- * Quit-functions aborts program with <result> and <message>:
- * input/answer streams replace any result to FAIL.
- */
- NORETURN void quitf(TResult result, const char* msg, ...);
- /*
- * Quit-functions aborts program with <result> and <message>:
- * input/answer streams replace any result to FAIL.
- */
- NORETURN void quits(TResult result, std::string msg);
- void close();
- const static int NO_INDEX = INT_MAX;
- const static WORD LightGray = 0x07;
- const static WORD LightRed = 0x0c;
- const static WORD LightCyan = 0x0b;
- const static WORD LightGreen = 0x0a;
- const static WORD LightYellow = 0x0e;
- static void textColor(WORD color);
- static void quitscr(WORD color, const char* msg);
- static void quitscrS(WORD color, std::string msg);
- void xmlSafeWrite(std::FILE * file, const char* msg);
- private:
- InStream(const InStream&);
- InStream& operator =(const InStream&);
- };
- InStream inf;
- InStream ouf;
- InStream ans;
- bool appesMode;
- std::string resultName;
- std::string checkerName = "untitled checker";
- random_t rnd;
- TTestlibMode testlibMode = _unknown;
- double __testlib_points = std::numeric_limits<float>::infinity();
- struct ValidatorBoundsHit
- {
- static const double EPS;
- bool minHit;
- bool maxHit;
- ValidatorBoundsHit(bool minHit = false, bool maxHit = false): minHit(minHit), maxHit(maxHit)
- {
- };
- ValidatorBoundsHit merge(const ValidatorBoundsHit& validatorBoundsHit)
- {
- return ValidatorBoundsHit(
- __testlib_max(minHit, validatorBoundsHit.minHit),
- __testlib_max(maxHit, validatorBoundsHit.maxHit)
- );
- }
- };
- const double ValidatorBoundsHit::EPS = 1E-12;
- class Validator
- {
- private:
- std::string _testset;
- std::string _group;
- std::string _testOverviewLogFileName;
- std::map<std::string, ValidatorBoundsHit> _boundsHitByVariableName;
- std::set<std::string> _features;
- std::set<std::string> _hitFeatures;
- bool isVariableNameBoundsAnalyzable(const std::string& variableName)
- {
- for (size_t i = 0; i < variableName.length(); i++)
- if ((variableName[i] >= '0' && variableName[i] <= '9') || variableName[i] < ' ')
- return false;
- return true;
- }
- bool isFeatureNameAnalyzable(const std::string& featureName)
- {
- for (size_t i = 0; i < featureName.length(); i++)
- if (featureName[i] < ' ')
- return false;
- return true;
- }
- public:
- Validator(): _testset("tests"), _group()
- {
- }
- std::string testset() const
- {
- return _testset;
- }
-
- std::string group() const
- {
- return _group;
- }
- std::string testOverviewLogFileName() const
- {
- return _testOverviewLogFileName;
- }
-
- void setTestset(const char* const testset)
- {
- _testset = testset;
- }
- void setGroup(const char* const group)
- {
- _group = group;
- }
- void setTestOverviewLogFileName(const char* const testOverviewLogFileName)
- {
- _testOverviewLogFileName = testOverviewLogFileName;
- }
- void addBoundsHit(const std::string& variableName, ValidatorBoundsHit boundsHit)
- {
- if (isVariableNameBoundsAnalyzable(variableName))
- {
- _boundsHitByVariableName[variableName]
- = boundsHit.merge(_boundsHitByVariableName[variableName]);
- }
- }
- std::string getBoundsHitLog()
- {
- std::string result;
- for (std::map<std::string, ValidatorBoundsHit>::iterator i = _boundsHitByVariableName.begin();
- i != _boundsHitByVariableName.end();
- i++)
- {
- result += "\"" + i->first + "\":";
- if (i->second.minHit)
- result += " min-value-hit";
- if (i->second.maxHit)
- result += " max-value-hit";
- result += "\n";
- }
- return result;
- }
- std::string getFeaturesLog()
- {
- std::string result;
- for (std::set<std::string>::iterator i = _features.begin();
- i != _features.end();
- i++)
- {
- result += "feature \"" + *i + "\":";
- if (_hitFeatures.count(*i))
- result += " hit";
- result += "\n";
- }
- return result;
- }
- void writeTestOverviewLog()
- {
- if (!_testOverviewLogFileName.empty())
- {
- std::string fileName(_testOverviewLogFileName);
- _testOverviewLogFileName = "";
- FILE* testOverviewLogFile = fopen(fileName.c_str(), "w");
- if (NULL == testOverviewLogFile)
- __testlib_fail("Validator::writeTestOverviewLog: can't test overview log to (" + fileName + ")");
- fprintf(testOverviewLogFile, "%s%s", getBoundsHitLog().c_str(), getFeaturesLog().c_str());
- if (fclose(testOverviewLogFile))
- __testlib_fail("Validator::writeTestOverviewLog: can't close test overview log file (" + fileName + ")");
- }
- }
- void addFeature(const std::string& feature)
- {
- if (_features.count(feature))
- __testlib_fail("Feature " + feature + " registered twice.");
- if (!isFeatureNameAnalyzable(feature))
- __testlib_fail("Feature name '" + feature + "' contains restricted characters.");
- _features.insert(feature);
- }
- void feature(const std::string& feature)
- {
- if (!isFeatureNameAnalyzable(feature))
- __testlib_fail("Feature name '" + feature + "' contains restricted characters.");
- if (!_features.count(feature))
- __testlib_fail("Feature " + feature + " didn't registered via addFeature(feature).");
- _hitFeatures.insert(feature);
- }
- } validator;
- struct TestlibFinalizeGuard
- {
- static bool alive;
- int quitCount, readEofCount;
- TestlibFinalizeGuard() : quitCount(0), readEofCount(0)
- {
- // No operations.
- }
- ~TestlibFinalizeGuard()
- {
- bool _alive = alive;
- alive = false;
- if (_alive)
- {
- if (testlibMode == _checker && quitCount == 0)
- __testlib_fail("Checker must end with quit or quitf call.");
- if (testlibMode == _validator && readEofCount == 0 && quitCount == 0)
- __testlib_fail("Validator must end with readEof call.");
- }
- validator.writeTestOverviewLog();
- }
- };
- bool TestlibFinalizeGuard::alive = true;
- TestlibFinalizeGuard testlibFinalizeGuard;
- /*
- * Call it to disable checks on finalization.
- */
- void disableFinalizeGuard()
- {
- TestlibFinalizeGuard::alive = false;
- }
- /* Interactor streams.
- */
- std::fstream tout;
- /* implementation
- */
- template <typename T>
- static std::string vtos(const T& t)
- {
- std::string s;
- std::stringstream ss;
- ss << t;
- ss >> s;
- return s;
- }
- template <typename T>
- static std::string toString(const T& t)
- {
- return vtos(t);
- }
- InStream::InStream()
- {
- reader = NULL;
- name = "";
- mode = _input;
- strict = false;
- stdfile = false;
- wordReserveSize = 4;
- readManyIteration = NO_INDEX;
- }
- InStream::InStream(const InStream& baseStream, std::string content)
- {
- reader = new StringInputStreamReader(content);
- opened = true;
- strict = baseStream.strict;
- mode = baseStream.mode;
- name = "based on " + baseStream.name;
- readManyIteration = NO_INDEX;
- }
- InStream::~InStream()
- {
- if (NULL != reader)
- {
- reader->close();
- delete reader;
- reader = NULL;
- }
- }
- #ifdef __GNUC__
- __attribute__((const))
- #endif
- int resultExitCode(TResult r)
- {
- if (r == _ok)
- return OK_EXIT_CODE;
- if (r == _wa)
- return WA_EXIT_CODE;
- if (r == _pe)
- return PE_EXIT_CODE;
- if (r == _fail)
- return FAIL_EXIT_CODE;
- if (r == _dirt)
- return DIRT_EXIT_CODE;
- if (r == _points)
- return POINTS_EXIT_CODE;
- if (r == _unexpected_eof)
- #ifdef ENABLE_UNEXPECTED_EOF
- return UNEXPECTED_EOF_EXIT_CODE;
- #else
- return PE_EXIT_CODE;
- #endif
- if (r >= _partially)
- return PC_BASE_EXIT_CODE + (r - _partially);
- return FAIL_EXIT_CODE;
- }
- void InStream::textColor(
- #if !(defined(ON_WINDOWS) && (!defined(_MSC_VER) || _MSC_VER>1400)) && defined(__GNUC__)
- __attribute__((unused))
- #endif
- WORD color
- )
- {
- #if defined(ON_WINDOWS) && (!defined(_MSC_VER) || _MSC_VER>1400)
- HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
- SetConsoleTextAttribute(handle, color);
- #endif
- #if !defined(ON_WINDOWS) && defined(__CNUC__)
- if (isatty(2))
- {
- switch (color)
- {
- case LightRed:
- fprintf(stderr, "\033[1;31m");
- break;
- case LightCyan:
- fprintf(stderr, "\033[1;36m");
- break;
- case LightGreen:
- fprintf(stderr, "\033[1;32m");
- break;
- case LightYellow:
- fprintf(stderr, "\033[1;33m");
- break;
- case LightGray:
- default:
- fprintf(stderr, "\033[0m");
- }
- }
- #endif
- }
- NORETURN void halt(int exitCode)
- {
- #ifdef FOOTER
- InStream::textColor(InStream::LightGray);
- std::fprintf(stderr, "Checker: \"%s\"\n", checkerName.c_str());
- std::fprintf(stderr, "Exit code: %d\n", exitCode);
- InStream::textColor(InStream::LightGray);
- #endif
- std::exit(exitCode);
- }
- static bool __testlib_shouldCheckDirt(TResult result)
- {
- return result == _ok || result == _points || result >= _partially;
- }
- NORETURN void InStream::quit(TResult result, const char* msg)
- {
- if (TestlibFinalizeGuard::alive)
- testlibFinalizeGuard.quitCount++;
- #ifndef ENABLE_UNEXPECTED_EOF
- if (result == _unexpected_eof)
- result = _pe;
- #endif
- if (mode != _output && result != _fail)
- quits(_fail, std::string(msg) + " (" + name + ")");
- std::FILE * resultFile;
- std::string errorName;
-
- if (__testlib_shouldCheckDirt(result))
- {
- if (testlibMode != _interactor && !ouf.seekEof())
- quit(_dirt, "Extra information in the output file");
- }
- int pctype = result - _partially;
- bool isPartial = false;
- switch (result)
- {
- case _ok:
- errorName = "ok ";
- quitscrS(LightGreen, errorName);
- break;
- case _wa:
- errorName = "wrong answer ";
- quitscrS(LightRed, errorName);
- break;
- case _pe:
- errorName = "wrong output format ";
- quitscrS(LightRed, errorName);
- break;
- case _fail:
- errorName = "FAIL ";
- quitscrS(LightRed, errorName);
- break;
- case _dirt:
- errorName = "wrong output format ";
- quitscrS(LightCyan, errorName);
- result = _pe;
- break;
- case _points:
- errorName = "points ";
- quitscrS(LightYellow, errorName);
- break;
- case _unexpected_eof:
- errorName = "unexpected eof ";
- quitscrS(LightCyan, errorName);
- break;
- default:
- if (result >= _partially)
- {
- errorName = format("partially correct (%d) ", pctype);
- isPartial = true;
- quitscrS(LightYellow, errorName);
- }
- else
- quit(_fail, "What is the code ??? ");
- }
- if (resultName != "")
- {
- resultFile = std::fopen(resultName.c_str(), "w");
- if (resultFile == NULL)
- quit(_fail, "Can not write to the result file");
- if (appesMode)
- {
- std::fprintf(resultFile, "<?xml version=\"1.0\" encoding=\"windows-1251\"?>");
- if (isPartial)
- std::fprintf(resultFile, "<result outcome = \"%s\" pctype = \"%d\">", outcomes[(int)_partially].c_str(), pctype);
- else
- {
- if (result != _points)
- std::fprintf(resultFile, "<result outcome = \"%s\">", outcomes[(int)result].c_str());
- else
- {
- if (__testlib_points == std::numeric_limits<float>::infinity())
- quit(_fail, "Expected points, but infinity found");
- std::string stringPoints = removeDoubleTrailingZeroes(format("%.10f", __testlib_points));
- std::fprintf(resultFile, "<result outcome = \"%s\" points = \"%s\">", outcomes[(int)result].c_str(), stringPoints.c_str());
- }
- }
- xmlSafeWrite(resultFile, msg);
- std::fprintf(resultFile, "</result>\n");
- }
- else
- std::fprintf(resultFile, "%s", msg);
- if (NULL == resultFile || fclose(resultFile) != 0)
- quit(_fail, "Can not write to the result file");
- }
- quitscr(LightGray, msg);
- std::fprintf(stderr, "\n");
- inf.close();
- ouf.close();
- ans.close();
- if (tout.is_open())
- tout.close();
- textColor(LightGray);
- if (resultName != "")
- std::fprintf(stderr, "See file to check exit message\n");
- halt(resultExitCode(result));
- }
- #ifdef __GNUC__
- __attribute__ ((format (printf, 3, 4)))
- #endif
- NORETURN void InStream::quitf(TResult result, const char* msg, ...)
- {
- FMT_TO_RESULT(msg, msg, message);
- InStream::quit(result, message.c_str());
- }
- NORETURN void InStream::quits(TResult result, std::string msg)
- {
- InStream::quit(result, msg.c_str());
- }
- void InStream::xmlSafeWrite(std::FILE * file, const char* msg)
- {
- size_t lmsg = strlen(msg);
- for (size_t i = 0; i < lmsg; i++)
- {
- if (msg[i] == '&')
- {
- std::fprintf(file, "%s", "&");
- continue;
- }
- if (msg[i] == '<')
- {
- std::fprintf(file, "%s", "<");
- continue;
- }
- if (msg[i] == '>')
- {
- std::fprintf(file, "%s", ">");
- continue;
- }
- if (msg[i] == '"')
- {
- std::fprintf(file, "%s", """);
- continue;
- }
- if (0 <= msg[i] && msg[i] <= 31)
- {
- std::fprintf(file, "%c", '.');
- continue;
- }
- std::fprintf(file, "%c", msg[i]);
- }
- }
- void InStream::quitscrS(WORD color, std::string msg)
- {
- quitscr(color, msg.c_str());
- }
- void InStream::quitscr(WORD color, const char* msg)
- {
- if (resultName == "")
- {
- textColor(color);
- std::fprintf(stderr, "%s", msg);
- textColor(LightGray);
- }
- }
- void InStream::reset(std::FILE* file)
- {
- if (opened && stdfile)
- quit(_fail, "Can't reset standard handle");
- if (opened)
- close();
- if (!stdfile)
- if (NULL == (file = std::fopen(name.c_str(), "rb")))
- {
- if (mode == _output)
- quits(_pe, std::string("Output file not found: \"") + name + "\"");
-
- if (mode == _answer)
- quits(_fail, std::string("Answer file not found: \"") + name + "\"");
- }
- if (NULL != file)
- {
- opened = true;
- __testlib_set_binary(file);
- if (stdfile)
- reader = new FileInputStreamReader(file, name);
- else
- reader = new BufferedFileInputStreamReader(file, name);
- }
- else
- {
- opened = false;
- reader = NULL;
- }
- }
- void InStream::init(std::string fileName, TMode mode)
- {
- opened = false;
- name = fileName;
- stdfile = false;
- this->mode = mode;
-
- reset();
- }
- void InStream::init(std::FILE* f, TMode mode)
- {
- opened = false;
-
- name = "untitled";
-
- if (f == stdin)
- name = "stdin", stdfile = true;
-
- if (f == stdout)
- name = "stdout", stdfile = true;
-
- if (f == stderr)
- name = "stderr", stdfile = true;
- this->mode = mode;
- reset(f);
- }
- char InStream::curChar()
- {
- return char(reader->curChar());
- }
- char InStream::nextChar()
- {
- return char(reader->nextChar());
- }
- char InStream::readChar()
- {
- return nextChar();
- }
- char InStream::readChar(char c)
- {
- char found = readChar();
- if (c != found)
- {
- if (!isEoln(found))
- quit(_pe, ("Unexpected character '" + std::string(1, found) + "', but '" + std::string(1, c) + "' expected").c_str());
- else
- quit(_pe, ("Unexpected character " + ("#" + vtos(int(found))) + ", but '" + std::string(1, c) + "' expected").c_str());
- }
- return found;
- }
- char InStream::readSpace()
- {
- return readChar(' ');
- }
- void InStream::unreadChar(char c)
- {
- reader->unreadChar(c);
- }
- void InStream::skipChar()
- {
- reader->skipChar();
- }
- void InStream::skipBlanks()
- {
- while (isBlanks(reader->curChar()))
- reader->skipChar();
- }
- std::string InStream::readWord()
- {
- readWordTo(_tmpReadToken);
- return _tmpReadToken;
- }
- void InStream::readWordTo(std::string& result)
- {
- if (!strict)
- skipBlanks();
- int cur = reader->nextChar();
- if (cur == EOFC)
- quit(_unexpected_eof, "Unexpected end of file - token expected");
- if (isBlanks(cur))
- quit(_pe, "Unexpected white-space - token expected");
- result.clear();
- while (!(isBlanks(cur) || cur == EOFC))
- {
- result += char(cur);
- cur = reader->nextChar();
- }
- reader->unreadChar(cur);
- if (result.length() == 0)
- quit(_unexpected_eof, "Unexpected end of file or white-space - token expected");
- }
- std::string InStream::readToken()
- {
- return readWord();
- }
- void InStream::readTokenTo(std::string& result)
- {
- readWordTo(result);
- }
- static std::string __testlib_part(const std::string& s)
- {
- if (s.length() <= 64)
- return s;
- else
- return s.substr(0, 30) + "..." + s.substr(s.length() - 31, 31);
- }
- #define __testlib_readMany(readMany, readOne, typeName, space) \
- if (size < 0) \
- quit(_fail, #readMany ": size should be non-negative."); \
- if (size > 100000000) \
- quit(_fail, #readMany ": size should be at most 100000000."); \
- \
- std::vector<typeName> result(size); \
- readManyIteration = indexBase; \
- \
- for (int i = 0; i < size; i++) \
- { \
- result[i] = readOne; \
- readManyIteration++; \
- if (space && i + 1 < size) \
- readSpace(); \
- } \
- \
- readManyIteration = NO_INDEX; \
- return result; \
- std::string InStream::readWord(const pattern& p, const std::string& variableName)
- {
- readWordTo(_tmpReadToken);
- if (!p.matches(_tmpReadToken))
- {
- if (readManyIteration == NO_INDEX)
- {
- if (variableName.empty())
- quit(_wa, ("Token \"" + __testlib_part(_tmpReadToken) + "\" doesn't correspond to pattern \"" + p.src() + "\"").c_str());
- else
- quit(_wa, ("Token parameter [name=" + variableName + "] equals to \"" + __testlib_part(_tmpReadToken) + "\", doesn't correspond to pattern \"" + p.src() + "\"").c_str());
- }
- else
- {
- if (variableName.empty())
- quit(_wa, ("Token element [index=" + vtos(readManyIteration) + "] equals to \"" + __testlib_part(_tmpReadToken) + "\" doesn't correspond to pattern \"" + p.src() + "\"").c_str());
- else
- quit(_wa, ("Token element " + variableName + "[" + vtos(readManyIteration) + "] equals to \"" + __testlib_part(_tmpReadToken) + "\", doesn't correspond to pattern \"" + p.src() + "\"").c_str());
- }
- }
- return _tmpReadToken;
- }
- std::vector<std::string> InStream::readWords(int size, const pattern& p, const std::string& variablesName, int indexBase)
- {
- __testlib_readMany(readWords, readWord(p, variablesName), std::string, true);
- }
- std::string InStream::readWord(const std::string& ptrn, const std::string& variableName)
- {
- return readWord(pattern(ptrn), variableName);
- }
- std::vector<std::string> InStream::readWords(int size, const std::string& ptrn, const std::string& variablesName, int indexBase)
- {
- pattern p(ptrn);
- __testlib_readMany(readWords, readWord(p, variablesName), std::string, true);
- }
- std::string InStream::readToken(const pattern& p, const std::string& variableName)
- {
- return readWord(p, variableName);
- }
- std::vector<std::string> InStream::readTokens(int size, const pattern& p, const std::string& variablesName, int indexBase)
- {
- __testlib_readMany(readTokens, readToken(p, variablesName), std::string, true);
- }
- std::string InStream::readToken(const std::string& ptrn, const std::string& variableName)
- {
- return readWord(ptrn, variableName);
- }
- std::vector<std::string> InStream::readTokens(int size, const std::string& ptrn, const std::string& variablesName, int indexBase)
- {
- pattern p(ptrn);
- __testlib_readMany(readTokens, readWord(p, variablesName), std::string, true);
- }
- void InStream::readWordTo(std::string& result, const pattern& p, const std::string& variableName)
- {
- readWordTo(result);
- if (!p.matches(result))
- {
- if (variableName.empty())
- quit(_wa, ("Token \"" + __testlib_part(result) + "\" doesn't correspond to pattern \"" + p.src() + "\"").c_str());
- else
- quit(_wa, ("Token parameter [name=" + variableName + "] equals to \"" + __testlib_part(result) + "\", doesn't correspond to pattern \"" + p.src() + "\"").c_str());
- }
- }
- void InStream::readWordTo(std::string& result, const std::string& ptrn, const std::string& variableName)
- {
- return readWordTo(result, pattern(ptrn), variableName);
- }
- void InStream::readTokenTo(std::string& result, const pattern& p, const std::string& variableName)
- {
- return readWordTo(result, p, variableName);
- }
- void InStream::readTokenTo(std::string& result, const std::string& ptrn, const std::string& variableName)
- {
- return readWordTo(result, ptrn, variableName);
- }
- #ifdef __GNUC__
- __attribute__((pure))
- #endif
- static inline bool equals(long long integer, const char* s)
- {
- if (integer == LLONG_MIN)
- return strcmp(s, "-9223372036854775808") == 0;
- if (integer == 0LL)
- return strcmp(s, "0") == 0;
- size_t length = strlen(s);
- if (length == 0)
- return false;
- if (integer < 0 && s[0] != '-')
- return false;
- if (integer < 0)
- s++, length--, integer = -integer;
- if (length == 0)
- return false;
- while (integer > 0)
- {
- int digit = int(integer % 10);
- if (s[length - 1] != '0' + digit)
- return false;
- length--;
- integer /= 10;
- }
- return length == 0;
- }
- #ifdef __GNUC__
- __attribute__((pure))
- #endif
- static inline bool equals(unsigned long long integer, const char* s)
- {
- if (integer == ULLONG_MAX)
- return strcmp(s, "18446744073709551615") == 0;
- if (integer == 0ULL)
- return strcmp(s, "0") == 0;
- size_t length = strlen(s);
- if (length == 0)
- return false;
- while (integer > 0)
- {
- int digit = int(integer % 10);
- if (s[length - 1] != '0' + digit)
- return false;
- length--;
- integer /= 10;
- }
- return length == 0;
- }
- static inline double stringToDouble(InStream& in, const char* buffer)
- {
- double retval;
- size_t length = strlen(buffer);
- int minusCount = 0;
- int plusCount = 0;
- int decimalPointCount = 0;
- int digitCount = 0;
- int eCount = 0;
- for (size_t i = 0; i < length; i++)
- {
- if (('0' <= buffer[i] && buffer[i] <= '9') || buffer[i] == '.'
- || buffer[i] == 'e' || buffer[i] == 'E'
- || buffer[i] == '-' || buffer[i] == '+')
- {
- if ('0' <= buffer[i] && buffer[i] <= '9')
- digitCount++;
- if (buffer[i] == 'e' || buffer[i] == 'E')
- eCount++;
- if (buffer[i] == '-')
- minusCount++;
- if (buffer[i] == '+')
- plusCount++;
- if (buffer[i] == '.')
- decimalPointCount++;
- }
- else
- in.quit(_pe, ("Expected double, but \"" + __testlib_part(buffer) + "\" found").c_str());
- }
- // If for sure is not a number in standard notation or in e-notation.
- if (digitCount == 0 || minusCount > 2 || plusCount > 2 || decimalPointCount > 1 || eCount > 1)
- in.quit(_pe, ("Expected double, but \"" + __testlib_part(buffer) + "\" found").c_str());
- char* suffix = new char[length + 1];
- int scanned = std::sscanf(buffer, "%lf%s", &retval, suffix);
- bool empty = strlen(suffix) == 0;
- delete[] suffix;
- if (scanned == 1 || (scanned == 2 && empty))
- {
- if (__testlib_isNaN(retval))
- in.quit(_pe, ("Expected double, but \"" + __testlib_part(buffer) + "\" found").c_str());
- return retval;
- }
- else
- in.quit(_pe, ("Expected double, but \"" + __testlib_part(buffer) + "\" found").c_str());
- }
- static inline double stringToStrictDouble(InStream& in, const char* buffer, int minAfterPointDigitCount, int maxAfterPointDigitCount)
- {
- if (minAfterPointDigitCount < 0)
- in.quit(_fail, "stringToStrictDouble: minAfterPointDigitCount should be non-negative.");
-
- if (minAfterPointDigitCount > maxAfterPointDigitCount)
- in.quit(_fail, "stringToStrictDouble: minAfterPointDigitCount should be less or equal to maxAfterPointDigitCount.");
- double retval;
- size_t length = strlen(buffer);
- if (length == 0 || length > 1000)
- in.quit(_pe, ("Expected strict double, but \"" + __testlib_part(buffer) + "\" found").c_str());
- if (buffer[0] != '-' && (buffer[0] < '0' || buffer[0] > '9'))
- in.quit(_pe, ("Expected strict double, but \"" + __testlib_part(buffer) + "\" found").c_str());
- int pointPos = -1;
- for (size_t i = 1; i + 1 < length; i++)
- {
- if (buffer[i] == '.')
- {
- if (pointPos > -1)
- in.quit(_pe, ("Expected strict double, but \"" + __testlib_part(buffer) + "\" found").c_str());
- pointPos = int(i);
- }
- if (buffer[i] != '.' && (buffer[i] < '0' || buffer[i] > '9'))
- in.quit(_pe, ("Expected strict double, but \"" + __testlib_part(buffer) + "\" found").c_str());
- }
- if (buffer[length - 1] < '0' || buffer[length - 1] > '9')
- in.quit(_pe, ("Expected strict double, but \"" + __testlib_part(buffer) + "\" found").c_str());
- int afterDigitsCount = (pointPos == -1 ? 0 : int(length) - pointPos - 1);
- if (afterDigitsCount < minAfterPointDigitCount || afterDigitsCount > maxAfterPointDigitCount)
- in.quit(_pe, ("Expected strict double with number of digits after point in range ["
- + vtos(minAfterPointDigitCount)
- + ","
- + vtos(maxAfterPointDigitCount)
- + "], but \"" + __testlib_part(buffer) + "\" found").c_str()
- );
- int firstDigitPos = -1;
- for (size_t i = 0; i < length; i++)
- if (buffer[i] >= '0' && buffer[i] <= '9')
- {
- firstDigitPos = int(i);
- break;
- }
- if (firstDigitPos > 1 || firstDigitPos == -1)
- in.quit(_pe, ("Expected strict double, but \"" + __testlib_part(buffer) + "\" found").c_str());
- if (buffer[firstDigitPos] == '0' && firstDigitPos + 1 < int(length)
- && buffer[firstDigitPos + 1] >= '0' && buffer[firstDigitPos + 1] <= '9')
- in.quit(_pe, ("Expected strict double, but \"" + __testlib_part(buffer) + "\" found").c_str());
- char* suffix = new char[length + 1];
- int scanned = std::sscanf(buffer, "%lf%s", &retval, suffix);
- bool empty = strlen(suffix) == 0;
- delete[] suffix;
- if (scanned == 1 || (scanned == 2 && empty))
- {
- if (__testlib_isNaN(retval) || __testlib_isInfinite(retval))
- in.quit(_pe, ("Expected double, but \"" + __testlib_part(buffer) + "\" found").c_str());
- return retval;
- }
- else
- in.quit(_pe, ("Expected double, but \"" + __testlib_part(buffer) + "\" found").c_str());
- }
- static inline long long stringToLongLong(InStream& in, const char* buffer)
- {
- if (strcmp(buffer, "-9223372036854775808") == 0)
- return LLONG_MIN;
- bool minus = false;
- size_t length = strlen(buffer);
-
- if (length > 1 && buffer[0] == '-')
- minus = true;
- if (length > 20)
- in.quit(_pe, ("Expected integer, but \"" + __testlib_part(buffer) + "\" found").c_str());
- long long retval = 0LL;
- int zeroes = 0;
- int processingZeroes = true;
-
- for (int i = (minus ? 1 : 0); i < int(length); i++)
- {
- if (buffer[i] == '0' && processingZeroes)
- zeroes++;
- else
- processingZeroes = false;
- if (buffer[i] < '0' || buffer[i] > '9')
- in.quit(_pe, ("Expected integer, but \"" + __testlib_part(buffer) + "\" found").c_str());
- retval = retval * 10 + (buffer[i] - '0');
- }
- if (retval < 0)
- in.quit(_pe, ("Expected integer, but \"" + __testlib_part(buffer) + "\" found").c_str());
-
- if ((zeroes > 0 && (retval != 0 || minus)) || zeroes > 1)
- in.quit(_pe, ("Expected integer, but \"" + __testlib_part(buffer) + "\" found").c_str());
- retval = (minus ? -retval : +retval);
- if (length < 19)
- return retval;
- if (equals(retval, buffer))
- return retval;
- else
- in.quit(_pe, ("Expected int64, but \"" + __testlib_part(buffer) + "\" found").c_str());
- }
- static inline unsigned long long stringToUnsignedLongLong(InStream& in, const char* buffer)
- {
- size_t length = strlen(buffer);
- if (length > 20)
- in.quit(_pe, ("Expected unsigned integer, but \"" + __testlib_part(buffer) + "\" found").c_str());
- if (length > 1 && buffer[0] == '0')
- in.quit(_pe, ("Expected unsigned integer, but \"" + __testlib_part(buffer) + "\" found").c_str());
- unsigned long long retval = 0LL;
- for (int i = 0; i < int(length); i++)
- {
- if (buffer[i] < '0' || buffer[i] > '9')
- in.quit(_pe, ("Expected unsigned integer, but \"" + __testlib_part(buffer) + "\" found").c_str());
- retval = retval * 10 + (buffer[i] - '0');
- }
- if (length < 19)
- return retval;
- if (length == 20 && strcmp(buffer, "18446744073709551615") == 1)
- in.quit(_pe, ("Expected unsigned int64, but \"" + __testlib_part(buffer) + "\" found").c_str());
- if (equals(retval, buffer))
- return retval;
- else
- in.quit(_pe, ("Expected unsigned int64, but \"" + __testlib_part(buffer) + "\" found").c_str());
- }
- int InStream::readInteger()
- {
- if (!strict && seekEof())
- quit(_unexpected_eof, "Unexpected end of file - int32 expected");
- readWordTo(_tmpReadToken);
-
- long long value = stringToLongLong(*this, _tmpReadToken.c_str());
- if (value < INT_MIN || value > INT_MAX)
- quit(_pe, ("Expected int32, but \"" + __testlib_part(_tmpReadToken) + "\" found").c_str());
-
- return int(value);
- }
- long long InStream::readLong()
- {
- if (!strict && seekEof())
- quit(_unexpected_eof, "Unexpected end of file - int64 expected");
- readWordTo(_tmpReadToken);
- return stringToLongLong(*this, _tmpReadToken.c_str());
- }
- unsigned long long InStream::readUnsignedLong()
- {
- if (!strict && seekEof())
- quit(_unexpected_eof, "Unexpected end of file - int64 expected");
- readWordTo(_tmpReadToken);
- return stringToUnsignedLongLong(*this, _tmpReadToken.c_str());
- }
- long long InStream::readLong(long long minv, long long maxv, const std::string& variableName)
- {
- long long result = readLong();
- if (result < minv || result > maxv)
- {
- if (readManyIteration == NO_INDEX)
- {
- if (variableName.empty())
- quit(_wa, ("Integer " + vtos(result) + " violates the range [" + vtos(minv) + ", " + vtos(maxv) + "]").c_str());
- else
- quit(_wa, ("Integer parameter [name=" + std::string(variableName) + "] equals to " + vtos(result) + ", violates the range [" + vtos(minv) + ", " + vtos(maxv) + "]").c_str());
- }
- else
- {
- if (variableName.empty())
- quit(_wa, ("Integer element [index=" + vtos(readManyIteration) + "] equals to " + vtos(result) + ", violates the range [" + vtos(minv) + ", " + vtos(maxv) + "]").c_str());
- else
- quit(_wa, ("Integer element " + std::string(variableName) + "[" + vtos(readManyIteration) + "] equals to " + vtos(result) + ", violates the range [" + vtos(minv) + ", " + vtos(maxv) + "]").c_str());
- }
- }
- if (strict && !variableName.empty())
- validator.addBoundsHit(variableName, ValidatorBoundsHit(minv == result, maxv == result));
- return result;
- }
- std::vector<long long> InStream::readLongs(int size, long long minv, long long maxv, const std::string& variablesName, int indexBase)
- {
- __testlib_readMany(readLongs, readLong(minv, maxv, variablesName), long long, true)
- }
- unsigned long long InStream::readUnsignedLong(unsigned long long minv, unsigned long long maxv, const std::string& variableName)
- {
- unsigned long long result = readUnsignedLong();
- if (result < minv || result > maxv)
- {
- if (readManyIteration == NO_INDEX)
- {
- if (variableName.empty())
- quit(_wa, ("Unsigned integer " + vtos(result) + " violates the range [" + vtos(minv) + ", " + vtos(maxv) + "]").c_str());
- else
- quit(_wa, ("Unsigned integer parameter [name=" + std::string(variableName) + "] equals to " + vtos(result) + ", violates the range [" + vtos(minv) + ", " + vtos(maxv) + "]").c_str());
- }
- else
- {
- if (variableName.empty())
- quit(_wa, ("Unsigned integer element [index=" + vtos(readManyIteration) + "] equals to " + vtos(result) + ", violates the range [" + vtos(minv) + ", " + vtos(maxv) + "]").c_str());
- else
- quit(_wa, ("Unsigned integer element " + std::string(variableName) + "[" + vtos(readManyIteration) + "] equals to " + vtos(result) + ", violates the range [" + vtos(minv) + ", " + vtos(maxv) + "]").c_str());
- }
- }
- if (strict && !variableName.empty())
- validator.addBoundsHit(variableName, ValidatorBoundsHit(minv == result, maxv == result));
- return result;
- }
- std::vector<unsigned long long> InStream::readUnsignedLongs(int size, unsigned long long minv, unsigned long long maxv, const std::string& variablesName, int indexBase)
- {
- __testlib_readMany(readUnsignedLongs, readUnsignedLong(minv, maxv, variablesName), unsigned long long, true)
- }
- unsigned long long InStream::readLong(unsigned long long minv, unsigned long long maxv, const std::string& variableName)
- {
- return readUnsignedLong(minv, maxv, variableName);
- }
- int InStream::readInt()
- {
- return readInteger();
- }
- int InStream::readInt(int minv, int maxv, const std::string& variableName)
- {
- int result = readInt();
- if (result < minv || result > maxv)
- {
- if (readManyIteration == NO_INDEX)
- {
- if (variableName.empty())
- quit(_wa, ("Integer " + vtos(result) + " violates the range [" + vtos(minv) + ", " + vtos(maxv) + "]").c_str());
- else
- quit(_wa, ("Integer parameter [name=" + std::string(variableName) + "] equals to " + vtos(result) + ", violates the range [" + vtos(minv) + ", " + vtos(maxv) + "]").c_str());
- }
- else
- {
- if (variableName.empty())
- quit(_wa, ("Integer element [index=" + vtos(readManyIteration) + "] equals to " + vtos(result) + ", violates the range [" + vtos(minv) + ", " + vtos(maxv) + "]").c_str());
- else
- quit(_wa, ("Integer element " + std::string(variableName) + "[" + vtos(readManyIteration) + "] equals to " + vtos(result) + ", violates the range [" + vtos(minv) + ", " + vtos(maxv) + "]").c_str());
- }
- }
- if (strict && !variableName.empty())
- validator.addBoundsHit(variableName, ValidatorBoundsHit(minv == result, maxv == result));
- return result;
- }
- int InStream::readInteger(int minv, int maxv, const std::string& variableName)
- {
- return readInt(minv, maxv, variableName);
- }
- std::vector<int> InStream::readInts(int size, int minv, int maxv, const std::string& variablesName, int indexBase)
- {
- __testlib_readMany(readInts, readInt(minv, maxv, variablesName), int, true)
- }
- std::vector<int> InStream::readIntegers(int size, int minv, int maxv, const std::string& variablesName, int indexBase)
- {
- __testlib_readMany(readIntegers, readInt(minv, maxv, variablesName), int, true)
- }
- double InStream::readReal()
- {
- if (!strict && seekEof())
- quit(_unexpected_eof, "Unexpected end of file - double expected");
- return stringToDouble(*this, readWord().c_str());
- }
- double InStream::readDouble()
- {
- return readReal();
- }
- double InStream::readReal(double minv, double maxv, const std::string& variableName)
- {
- double result = readReal();
- if (result < minv || result > maxv)
- {
- if (readManyIteration == NO_INDEX)
- {
- if (variableName.empty())
- quit(_wa, ("Double " + vtos(result) + " violates the range [" + vtos(minv) + ", " + vtos(maxv) + "]").c_str());
- else
- quit(_wa, ("Double parameter [name=" + std::string(variableName) + "] equals to " + vtos(result) + ", violates the range [" + vtos(minv) + ", " + vtos(maxv) + "]").c_str());
- }
- else
- {
- if (variableName.empty())
- quit(_wa, ("Double element [index=" + vtos(readManyIteration) + "] equals to " + vtos(result) + ", violates the range [" + vtos(minv) + ", " + vtos(maxv) + "]").c_str());
- else
- quit(_wa, ("Double element " + std::string(variableName) + "[" + vtos(readManyIteration) + "] equals to " + vtos(result) + ", violates the range [" + vtos(minv) + ", " + vtos(maxv) + "]").c_str());
- }
- }
- if (strict && !variableName.empty())
- validator.addBoundsHit(variableName, ValidatorBoundsHit(
- doubleDelta(minv, result) < ValidatorBoundsHit::EPS,
- doubleDelta(maxv, result) < ValidatorBoundsHit::EPS
- ));
- return result;
- }
- std::vector<double> InStream::readReals(int size, double minv, double maxv, const std::string& variablesName, int indexBase)
- {
- __testlib_readMany(readReals, readReal(minv, maxv, variablesName), double, true)
- }
- double InStream::readDouble(double minv, double maxv, const std::string& variableName)
- {
- return readReal(minv, maxv, variableName);
- }
- std::vector<double> InStream::readDoubles(int size, double minv, double maxv, const std::string& variablesName, int indexBase)
- {
- __testlib_readMany(readDoubles, readDouble(minv, maxv, variablesName), double, true)
- }
- double InStream::readStrictReal(double minv, double maxv,
- int minAfterPointDigitCount, int maxAfterPointDigitCount,
- const std::string& variableName)
- {
- if (!strict && seekEof())
- quit(_unexpected_eof, "Unexpected end of file - strict double expected");
- double result = stringToStrictDouble(*this, readWord().c_str(),
- minAfterPointDigitCount, maxAfterPointDigitCount);
- if (result < minv || result > maxv)
- {
- if (readManyIteration == NO_INDEX)
- {
- if (variableName.empty())
- quit(_wa, ("Strict double " + vtos(result) + " violates the range [" + vtos(minv) + ", " + vtos(maxv) + "]").c_str());
- else
- quit(_wa, ("Strict double parameter [name=" + std::string(variableName) + "] equals to " + vtos(result) + ", violates the range [" + vtos(minv) + ", " + vtos(maxv) + "]").c_str());
- }
- else
- {
- if (variableName.empty())
- quit(_wa, ("Strict double element [index=" + vtos(readManyIteration) + "] equals to " + vtos(result) + ", violates the range [" + vtos(minv) + ", " + vtos(maxv) + "]").c_str());
- else
- quit(_wa, ("Strict double element " + std::string(variableName) + "[" + vtos(readManyIteration) + "] equals to " + vtos(result) + ", violates the range [" + vtos(minv) + ", " + vtos(maxv) + "]").c_str());
- }
- }
- if (strict && !variableName.empty())
- validator.addBoundsHit(variableName, ValidatorBoundsHit(
- doubleDelta(minv, result) < ValidatorBoundsHit::EPS,
- doubleDelta(maxv, result) < ValidatorBoundsHit::EPS
- ));
- return result;
- }
- std::vector<double> InStream::readStrictReals(int size, double minv, double maxv,
- int minAfterPointDigitCount, int maxAfterPointDigitCount,
- const std::string& variablesName, int indexBase)
- {
- __testlib_readMany(readStrictReals, readStrictReal(minv, maxv, minAfterPointDigitCount, maxAfterPointDigitCount, variablesName), double, true)
- }
- double InStream::readStrictDouble(double minv, double maxv,
- int minAfterPointDigitCount, int maxAfterPointDigitCount,
- const std::string& variableName)
- {
- return readStrictReal(minv, maxv,
- minAfterPointDigitCount, maxAfterPointDigitCount,
- variableName);
- }
- std::vector<double> InStream::readStrictDoubles(int size, double minv, double maxv,
- int minAfterPointDigitCount, int maxAfterPointDigitCount,
- const std::string& variablesName, int indexBase)
- {
- __testlib_readMany(readStrictDoubles, readStrictDouble(minv, maxv, minAfterPointDigitCount, maxAfterPointDigitCount, variablesName), double, true)
- }
- bool InStream::eof()
- {
- if (!strict && NULL == reader)
- return true;
- return reader->eof();
- }
- bool InStream::seekEof()
- {
- if (!strict && NULL == reader)
- return true;
- skipBlanks();
- return eof();
- }
- bool InStream::eoln()
- {
- if (!strict && NULL == reader)
- return true;
- int c = reader->nextChar();
- if (!strict)
- {
- if (c == EOFC)
- return true;
- if (c == CR)
- {
- c = reader->nextChar();
- if (c != LF)
- {
- reader->unreadChar(c);
- reader->unreadChar(CR);
- return false;
- }
- else
- return true;
- }
-
- if (c == LF)
- return true;
- reader->unreadChar(c);
- return false;
- }
- else
- {
- bool returnCr = false;
- #ifdef ON_WINDOWS
- if (c != CR)
- {
- reader->unreadChar(c);
- return false;
- }
- else
- {
- if (!returnCr)
- returnCr = true;
- c = reader->nextChar();
- }
- #endif
- if (c != LF)
- {
- reader->unreadChar(c);
- if (returnCr)
- reader->unreadChar(CR);
- return false;
- }
- return true;
- }
- }
- void InStream::readEoln()
- {
- if (!eoln())
- quit(_pe, "Expected EOLN");
- }
- void InStream::readEof()
- {
- if (!eof())
- quit(_pe, "Expected EOF");
- if (TestlibFinalizeGuard::alive && this == &inf)
- testlibFinalizeGuard.readEofCount++;
- }
- bool InStream::seekEoln()
- {
- if (!strict && NULL == reader)
- return true;
-
- int cur;
- do
- {
- cur = reader->nextChar();
- }
- while (cur == SPACE || cur == TAB);
- reader->unreadChar(cur);
- return eoln();
- }
- void InStream::nextLine()
- {
- readLine();
- }
- void InStream::readStringTo(std::string& result)
- {
- if (NULL == reader)
- quit(_pe, "Expected line");
- result.clear();
- int cur;
- for (;;)
- {
- cur = reader->curChar();
- if (isEoln(cur))
- break;
- if (cur == EOFC)
- break;
- result += char(reader->nextChar());
- }
- if (strict)
- readEoln();
- else
- eoln();
- }
- std::string InStream::readString()
- {
- readStringTo(_tmpReadToken);
- return _tmpReadToken;
- }
- std::vector<std::string> InStream::readStrings(int size, int indexBase)
- {
- __testlib_readMany(readStrings, readString(), std::string, false)
- }
- void InStream::readStringTo(std::string& result, const pattern& p, const std::string& variableName)
- {
- readStringTo(result);
- if (!p.matches(result))
- {
- if (readManyIteration == NO_INDEX)
- {
- if (variableName.empty())
- quit(_wa, ("Line \"" + __testlib_part(result) + "\" doesn't correspond to pattern \"" + p.src() + "\"").c_str());
- else
- quit(_wa, ("Line [name=" + variableName + "] equals to \"" + __testlib_part(result) + "\", doesn't correspond to pattern \"" + p.src() + "\"").c_str());
- }
- else
- {
- if (variableName.empty())
- quit(_wa, ("Line element [index=" + vtos(readManyIteration) + "] equals to \"" + __testlib_part(result) + "\" doesn't correspond to pattern \"" + p.src() + "\"").c_str());
- else
- quit(_wa, ("Line element " + std::string(variableName) + "[" + vtos(readManyIteration) + "] equals to \"" + __testlib_part(result) + "\", doesn't correspond to pattern \"" + p.src() + "\"").c_str());
- }
- }
- }
- void InStream::readStringTo(std::string& result, const std::string& ptrn, const std::string& variableName)
- {
- readStringTo(result, pattern(ptrn), variableName);
- }
- std::string InStream::readString(const pattern& p, const std::string& variableName)
- {
- readStringTo(_tmpReadToken, p, variableName);
- return _tmpReadToken;
- }
- std::vector<std::string> InStream::readStrings(int size, const pattern& p, const std::string& variablesName, int indexBase)
- {
- __testlib_readMany(readStrings, readString(p, variablesName), std::string, false)
- }
- std::string InStream::readString(const std::string& ptrn, const std::string& variableName)
- {
- readStringTo(_tmpReadToken, ptrn, variableName);
- return _tmpReadToken;
- }
- std::vector<std::string> InStream::readStrings(int size, const std::string& ptrn, const std::string& variablesName, int indexBase)
- {
- pattern p(ptrn);
- __testlib_readMany(readStrings, readString(p, variablesName), std::string, false)
- }
- void InStream::readLineTo(std::string& result)
- {
- readStringTo(result);
- }
- std::string InStream::readLine()
- {
- return readString();
- }
- std::vector<std::string> InStream::readLines(int size, int indexBase)
- {
- __testlib_readMany(readLines, readString(), std::string, false)
- }
- void InStream::readLineTo(std::string& result, const pattern& p, const std::string& variableName)
- {
- readStringTo(result, p, variableName);
- }
- void InStream::readLineTo(std::string& result, const std::string& ptrn, const std::string& variableName)
- {
- readStringTo(result, ptrn, variableName);
- }
- std::string InStream::readLine(const pattern& p, const std::string& variableName)
- {
- return readString(p, variableName);
- }
- std::vector<std::string> InStream::readLines(int size, const pattern& p, const std::string& variablesName, int indexBase)
- {
- __testlib_readMany(readLines, readString(p, variablesName), std::string, false)
- }
- std::string InStream::readLine(const std::string& ptrn, const std::string& variableName)
- {
- return readString(ptrn, variableName);
- }
- std::vector<std::string> InStream::readLines(int size, const std::string& ptrn, const std::string& variablesName, int indexBase)
- {
- pattern p(ptrn);
- __testlib_readMany(readLines, readString(p, variablesName), std::string, false)
- }
- void InStream::close()
- {
- if (NULL != reader)
- {
- reader->close();
- delete reader;
- reader = NULL;
- }
-
- opened = false;
- }
- NORETURN void quit(TResult result, const std::string& msg)
- {
- ouf.quit(result, msg.c_str());
- }
- NORETURN void quit(TResult result, const char* msg)
- {
- ouf.quit(result, msg);
- }
- NORETURN void __testlib_quitp(double points, const char* message)
- {
- __testlib_points = points;
- std::string stringPoints = removeDoubleTrailingZeroes(format("%.10f", points));
- std::string quitMessage;
- if (NULL == message || 0 == strlen(message))
- quitMessage = stringPoints;
- else
- quitMessage = stringPoints + " " + message;
- quit(_points, quitMessage.c_str());
- }
- NORETURN void __testlib_quitp(int points, const char* message)
- {
- __testlib_points = points;
- std::string stringPoints = format("%d", points);
- std::string quitMessage;
- if (NULL == message || 0 == strlen(message))
- quitMessage = stringPoints;
- else
- quitMessage = stringPoints + " " + message;
- quit(_points, quitMessage.c_str());
- }
- NORETURN void quitp(float points, const std::string& message = "")
- {
- __testlib_quitp(double(points), message.c_str());
- }
- NORETURN void quitp(double points, const std::string& message = "")
- {
- __testlib_quitp(points, message.c_str());
- }
- NORETURN void quitp(long double points, const std::string& message = "")
- {
- __testlib_quitp(double(points), message.c_str());
- }
- NORETURN void quitp(int points, const std::string& message = "")
- {
- __testlib_quitp(points, message.c_str());
- }
- template<typename F>
- #ifdef __GNUC__
- __attribute__ ((format (printf, 2, 3)))
- #endif
- NORETURN void quitp(F points, const char* format, ...)
- {
- FMT_TO_RESULT(format, format, message);
- quitp(points, message);
- }
- #ifdef __GNUC__
- __attribute__ ((format (printf, 2, 3)))
- #endif
- NORETURN void quitf(TResult result, const char* format, ...)
- {
- FMT_TO_RESULT(format, format, message);
- quit(result, message);
- }
- #ifdef __GNUC__
- __attribute__ ((format (printf, 3, 4)))
- #endif
- void quitif(bool condition, TResult result, const char* format, ...)
- {
- if (condition)
- {
- FMT_TO_RESULT(format, format, message);
- quit(result, message);
- }
- }
- NORETURN void __testlib_help()
- {
- InStream::textColor(InStream::LightCyan);
- std::fprintf(stderr, "TESTLIB %s, http://code.google.com/p/testlib/ ", VERSION);
- std::fprintf(stderr, "by Mike Mirzayanov, copyright(c) 2005-2017\n");
- std::fprintf(stderr, "Checker name: \"%s\"\n", checkerName.c_str());
- InStream::textColor(InStream::LightGray);
- std::fprintf(stderr, "\n");
- std::fprintf(stderr, "Latest features: \n");
- for (size_t i = 0; i < sizeof(latestFeatures) / sizeof(char*); i++)
- {
- std::fprintf(stderr, "*) %s\n", latestFeatures[i]);
- }
- std::fprintf(stderr, "\n");
- std::fprintf(stderr, "Program must be run with the following arguments: \n");
- std::fprintf(stderr, " <input-file> <output-file> <answer-file> [<report-file> [<-appes>]]\n\n");
- std::exit(FAIL_EXIT_CODE);
- }
- static void __testlib_ensuresPreconditions()
- {
- // testlib assumes: sizeof(int) = 4.
- __TESTLIB_STATIC_ASSERT(sizeof(int) == 4);
- // testlib assumes: INT_MAX == 2147483647.
- __TESTLIB_STATIC_ASSERT(INT_MAX == 2147483647);
- // testlib assumes: sizeof(long long) = 8.
- __TESTLIB_STATIC_ASSERT(sizeof(long long) == 8);
- // testlib assumes: sizeof(double) = 8.
- __TESTLIB_STATIC_ASSERT(sizeof(double) == 8);
- // testlib assumes: no -ffast-math.
- if (!__testlib_isNaN(+__testlib_nan()))
- quit(_fail, "Function __testlib_isNaN is not working correctly: possible reason is '-ffast-math'");
- if (!__testlib_isNaN(-__testlib_nan()))
- quit(_fail, "Function __testlib_isNaN is not working correctly: possible reason is '-ffast-math'");
- }
- void registerGen(int argc, char* argv[], int randomGeneratorVersion)
- {
- if (randomGeneratorVersion < 0 || randomGeneratorVersion > 1)
- quitf(_fail, "Random generator version is expected to be 0 or 1.");
- random_t::version = randomGeneratorVersion;
- __testlib_ensuresPreconditions();
- testlibMode = _generator;
- __testlib_set_binary(stdin);
- rnd.setSeed(argc, argv);
- }
- #ifdef USE_RND_AS_BEFORE_087
- void registerGen(int argc, char* argv[])
- {
- registerGen(argc, argv, 0);
- }
- #else
- #ifdef __GNUC__
- __attribute__ ((deprecated("Use registerGen(argc, argv, 0) or registerGen(argc, argv, 1)."
- " The third parameter stands for the random generator version."
- " If you are trying to compile old generator use macro -DUSE_RND_AS_BEFORE_087 or registerGen(argc, argv, 0)."
- " Version 1 has been released on Spring, 2013. Use it to write new generators.")))
- #endif
- #ifdef _MSC_VER
- __declspec(deprecated("Use registerGen(argc, argv, 0) or registerGen(argc, argv, 1)."
- " The third parameter stands for the random generator version."
- " If you are trying to compile old generator use macro -DUSE_RND_AS_BEFORE_087 or registerGen(argc, argv, 0)."
- " Version 1 has been released on Spring, 2013. Use it to write new generators."))
- #endif
- void registerGen(int argc, char* argv[])
- {
- std::fprintf(stderr, "Use registerGen(argc, argv, 0) or registerGen(argc, argv, 1)."
- " The third parameter stands for the random generator version."
- " If you are trying to compile old generator use macro -DUSE_RND_AS_BEFORE_087 or registerGen(argc, argv, 0)."
- " Version 1 has been released on Spring, 2013. Use it to write new generators.\n\n");
- registerGen(argc, argv, 0);
- }
- #endif
- void registerInteraction(int argc, char* argv[])
- {
- __testlib_ensuresPreconditions();
- testlibMode = _interactor;
- __testlib_set_binary(stdin);
- if (argc > 1 && !strcmp("--help", argv[1]))
- __testlib_help();
-
- if (argc < 3 || argc > 6)
- {
- quit(_fail, std::string("Program must be run with the following arguments: ") +
- std::string("<input-file> <output-file> [<answer-file> [<report-file> [<-appes>]]]") +
- "\nUse \"--help\" to get help information");
- }
- if (argc <= 4)
- {
- resultName = "";
- appesMode = false;
- }
- if (argc == 5)
- {
- resultName = argv[4];
- appesMode = false;
- }
- if (argc == 6)
- {
- if (strcmp("-APPES", argv[5]) && strcmp("-appes", argv[5]))
- {
- quit(_fail, std::string("Program must be run with the following arguments: ") +
- "<input-file> <output-file> <answer-file> [<report-file> [<-appes>]]");
- }
- else
- {
- resultName = argv[4];
- appesMode = true;
- }
- }
- inf.init(argv[1], _input);
- tout.open(argv[2], std::ios_base::out);
- if (tout.fail() || !tout.is_open())
- quit(_fail, std::string("Can not write to the test-output-file '") + argv[2] + std::string("'"));
- ouf.init(stdin, _output);
-
- if (argc >= 4)
- ans.init(argv[3], _answer);
- else
- ans.name = "unopened answer stream";
- }
- void registerValidation()
- {
- __testlib_ensuresPreconditions();
- testlibMode = _validator;
- __testlib_set_binary(stdin);
- inf.init(stdin, _input);
- inf.strict = true;
- }
- void registerValidation(int argc, char* argv[])
- {
- registerValidation();
- for (int i = 1; i < argc; i++)
- {
- if (!strcmp("--testset", argv[i]))
- {
- if (i + 1 < argc && strlen(argv[i + 1]) > 0)
- validator.setTestset(argv[++i]);
- else
- quit(_fail, std::string("Validator must be run with the following arguments: ") +
- "[--testset testset] [--group group] [--testOverviewLogFileName fileName]");
- }
- if (!strcmp("--group", argv[i]))
- {
- if (i + 1 < argc)
- validator.setGroup(argv[++i]);
- else
- quit(_fail, std::string("Validator must be run with the following arguments: ") +
- "[--testset testset] [--group group] [--testOverviewLogFileName fileName]");
- }
- if (!strcmp("--testOverviewLogFileName", argv[i]))
- {
- if (i + 1 < argc)
- validator.setTestOverviewLogFileName(argv[++i]);
- else
- quit(_fail, std::string("Validator must be run with the following arguments: ") +
- "[--testset testset] [--group group] [--testOverviewLogFileName fileName]");
- }
- }
- }
- void addFeature(const std::string& feature)
- {
- if (testlibMode != _validator)
- quit(_fail, "Features are supported in validators only.");
- validator.addFeature(feature);
- }
- void feature(const std::string& feature)
- {
- if (testlibMode != _validator)
- quit(_fail, "Features are supported in validators only.");
- validator.feature(feature);
- }
- void registerTestlibCmd(int argc, char* argv[])
- {
- __testlib_ensuresPreconditions();
- testlibMode = _checker;
- __testlib_set_binary(stdin);
- if (argc > 1 && !strcmp("--help", argv[1]))
- __testlib_help();
- if (argc < 4 || argc > 6)
- {
- quit(_fail, std::string("Program must be run with the following arguments: ") +
- std::string("<input-file> <output-file> <answer-file> [<report-file> [<-appes>]]") +
- "\nUse \"--help\" to get help information");
- }
- if (argc == 4)
- {
- resultName = "";
- appesMode = false;
- }
- if (argc == 5)
- {
- resultName = argv[4];
- appesMode = false;
- }
- if (argc == 6)
- {
- if (strcmp("-APPES", argv[5]) && strcmp("-appes", argv[5]))
- {
- quit(_fail, std::string("Program must be run with the following arguments: ") +
- "<input-file> <output-file> <answer-file> [<report-file> [<-appes>]]");
- }
- else
- {
- resultName = argv[4];
- appesMode = true;
- }
- }
- inf.init(argv[1], _input);
- ouf.init(argv[2], _output);
- ans.init(argv[3], _answer);
- }
- void registerTestlib(int argc, ...)
- {
- if (argc < 3 || argc > 5)
- quit(_fail, std::string("Program must be run with the following arguments: ") +
- "<input-file> <output-file> <answer-file> [<report-file> [<-appes>]]");
- char** argv = new char*[argc + 1];
-
- va_list ap;
- va_start(ap, argc);
- argv[0] = NULL;
- for (int i = 0; i < argc; i++)
- {
- argv[i + 1] = va_arg(ap, char*);
- }
- va_end(ap);
- registerTestlibCmd(argc + 1, argv);
- delete[] argv;
- }
- static inline void __testlib_ensure(bool cond, const std::string& msg)
- {
- if (!cond)
- quit(_fail, msg.c_str());
- }
- #ifdef __GNUC__
- __attribute__((unused))
- #endif
- static inline void __testlib_ensure(bool cond, const char* msg)
- {
- if (!cond)
- quit(_fail, msg);
- }
- #define ensure(cond) __testlib_ensure(cond, "Condition failed: \"" #cond "\"")
- #ifdef __GNUC__
- __attribute__ ((format (printf, 2, 3)))
- #endif
- inline void ensuref(bool cond, const char* format, ...)
- {
- if (!cond)
- {
- FMT_TO_RESULT(format, format, message);
- __testlib_ensure(cond, message);
- }
- }
- NORETURN static void __testlib_fail(const std::string& message)
- {
- quitf(_fail, "%s", message.c_str());
- }
- #ifdef __GNUC__
- __attribute__ ((format (printf, 1, 2)))
- #endif
- void setName(const char* format, ...)
- {
- FMT_TO_RESULT(format, format, name);
- checkerName = name;
- }
- /*
- * Do not use random_shuffle, because it will produce different result
- * for different C++ compilers.
- *
- * This implementation uses testlib random_t to produce random numbers, so
- * it is stable.
- */
- template<typename _RandomAccessIter>
- void shuffle(_RandomAccessIter __first, _RandomAccessIter __last)
- {
- if (__first == __last) return;
- for (_RandomAccessIter __i = __first + 1; __i != __last; ++__i)
- std::iter_swap(__i, __first + rnd.next(int(__i - __first) + 1));
- }
- template<typename _RandomAccessIter>
- #if defined(__GNUC__) && !defined(__clang__)
- __attribute__ ((error("Don't use random_shuffle(), use shuffle() instead")))
- #endif
- void random_shuffle(_RandomAccessIter , _RandomAccessIter )
- {
- quitf(_fail, "Don't use random_shuffle(), use shuffle() instead");
- }
- #ifdef __GLIBC__
- # define RAND_THROW_STATEMENT throw()
- #else
- # define RAND_THROW_STATEMENT
- #endif
- #if defined(__GNUC__) && !defined(__clang__)
- __attribute__ ((error("Don't use rand(), use rnd.next() instead")))
- #endif
- #ifdef _MSC_VER
- # pragma warning( disable : 4273 )
- #endif
- int rand() RAND_THROW_STATEMENT
- {
- quitf(_fail, "Don't use rand(), use rnd.next() instead");
-
- /* This line never runs. */
- //throw "Don't use rand(), use rnd.next() instead";
- }
- #if defined(__GNUC__) && !defined(__clang__)
- __attribute__ ((error("Don't use srand(), you should use "
- "'registerGen(argc, argv, 1);' to initialize generator seed "
- "by hash code of the command line params. The third parameter "
- "is randomGeneratorVersion (currently the latest is 1).")))
- #endif
- #ifdef _MSC_VER
- # pragma warning( disable : 4273 )
- #endif
- void srand(unsigned int seed) RAND_THROW_STATEMENT
- {
- quitf(_fail, "Don't use srand(), you should use "
- "'registerGen(argc, argv, 1);' to initialize generator seed "
- "by hash code of the command line params. The third parameter "
- "is randomGeneratorVersion (currently the latest is 1) [ignored seed=%d].", seed);
- }
- void startTest(int test)
- {
- const std::string testFileName = vtos(test);
- if (NULL == freopen(testFileName.c_str(), "wt", stdout))
- __testlib_fail("Unable to write file '" + testFileName + "'");
- }
- inline std::string upperCase(std::string s)
- {
- for (size_t i = 0; i < s.length(); i++)
- if ('a' <= s[i] && s[i] <= 'z')
- s[i] = char(s[i] - 'a' + 'A');
- return s;
- }
- inline std::string lowerCase(std::string s)
- {
- for (size_t i = 0; i < s.length(); i++)
- if ('A' <= s[i] && s[i] <= 'Z')
- s[i] = char(s[i] - 'A' + 'a');
- return s;
- }
- inline std::string compress(const std::string& s)
- {
- return __testlib_part(s);
- }
- inline std::string englishEnding(int x)
- {
- x %= 100;
- if (x / 10 == 1)
- return "th";
- if (x % 10 == 1)
- return "st";
- if (x % 10 == 2)
- return "nd";
- if (x % 10 == 3)
- return "rd";
- return "th";
- }
- inline std::string trim(const std::string& s)
- {
- if (s.empty())
- return s;
- int left = 0;
- while (left < int(s.length()) && isBlanks(s[left]))
- left++;
- if (left >= int(s.length()))
- return "";
- int right = int(s.length()) - 1;
- while (right >= 0 && isBlanks(s[right]))
- right--;
- if (right < 0)
- return "";
- return s.substr(left, right - left + 1);
- }
- template <typename _ForwardIterator, typename _Separator>
- std::string join(_ForwardIterator first, _ForwardIterator last, _Separator separator)
- {
- std::stringstream ss;
- bool repeated = false;
- for (_ForwardIterator i = first; i != last; i++)
- {
- if (repeated)
- ss << separator;
- else
- repeated = true;
- ss << *i;
- }
- return ss.str();
- }
- template <typename _ForwardIterator>
- std::string join(_ForwardIterator first, _ForwardIterator last)
- {
- return join(first, last, ' ');
- }
- template <typename _Collection, typename _Separator>
- std::string join(const _Collection& collection, _Separator separator)
- {
- return join(collection.begin(), collection.end(), separator);
- }
- template <typename _Collection>
- std::string join(const _Collection& collection)
- {
- return join(collection, ' ');
- }
- /**
- * Splits string s by character separator returning exactly k+1 items,
- * where k is the number of separator occurences.
- */
- std::vector<std::string> split(const std::string& s, char separator)
- {
- std::vector<std::string> result;
- std::string item;
- for (size_t i = 0; i < s.length(); i++)
- if (s[i] == separator)
- {
- result.push_back(item);
- item = "";
- }
- else
- item += s[i];
- result.push_back(item);
- return result;
- }
- /**
- * Splits string s by character separators returning exactly k+1 items,
- * where k is the number of separator occurences.
- */
- std::vector<std::string> split(const std::string& s, const std::string& separators)
- {
- if (separators.empty())
- return std::vector<std::string>(1, s);
- std::vector<bool> isSeparator(256);
- for (size_t i = 0; i < separators.size(); i++)
- isSeparator[(unsigned char)(separators[i])] = true;
- std::vector<std::string> result;
- std::string item;
- for (size_t i = 0; i < s.length(); i++)
- if (isSeparator[(unsigned char)(s[i])])
- {
- result.push_back(item);
- item = "";
- }
- else
- item += s[i];
- result.push_back(item);
- return result;
- }
- /**
- * Splits string s by character separator returning non-empty items.
- */
- std::vector<std::string> tokenize(const std::string& s, char separator)
- {
- std::vector<std::string> result;
- std::string item;
- for (size_t i = 0; i < s.length(); i++)
- if (s[i] == separator)
- {
- if (!item.empty())
- result.push_back(item);
- item = "";
- }
- else
- item += s[i];
- if (!item.empty())
- result.push_back(item);
- return result;
- }
- /**
- * Splits string s by character separators returning non-empty items.
- */
- std::vector<std::string> tokenize(const std::string& s, const std::string& separators)
- {
- if (separators.empty())
- return std::vector<std::string>(1, s);
- std::vector<bool> isSeparator(256);
- for (size_t i = 0; i < separators.size(); i++)
- isSeparator[(unsigned char)(separators[i])] = true;
- std::vector<std::string> result;
- std::string item;
- for (size_t i = 0; i < s.length(); i++)
- if (isSeparator[(unsigned char)(s[i])])
- {
- if (!item.empty())
- result.push_back(item);
- item = "";
- }
- else
- item += s[i];
-
- if (!item.empty())
- result.push_back(item);
- return result;
- }
- NORETURN void __testlib_expectedButFound(TResult result, std::string expected, std::string found, const char* prepend)
- {
- std::string message;
- if (strlen(prepend) != 0)
- message = format("%s: expected '%s', but found '%s'",
- compress(prepend).c_str(), compress(expected).c_str(), compress(found).c_str());
- else
- message = format("expected '%s', but found '%s'",
- compress(expected).c_str(), compress(found).c_str());
- quit(result, message);
- }
- NORETURN void __testlib_expectedButFound(TResult result, double expected, double found, const char* prepend)
- {
- std::string expectedString = removeDoubleTrailingZeroes(format("%.12f", expected));
- std::string foundString = removeDoubleTrailingZeroes(format("%.12f", found));
- __testlib_expectedButFound(result, expectedString, foundString, prepend);
- }
- template <typename T>
- #ifdef __GNUC__
- __attribute__ ((format (printf, 4, 5)))
- #endif
- NORETURN void expectedButFound(TResult result, T expected, T found, const char* prependFormat = "", ...)
- {
- FMT_TO_RESULT(prependFormat, prependFormat, prepend);
- std::string expectedString = vtos(expected);
- std::string foundString = vtos(found);
- __testlib_expectedButFound(result, expectedString, foundString, prepend.c_str());
- }
- template <>
- #ifdef __GNUC__
- __attribute__ ((format (printf, 4, 5)))
- #endif
- NORETURN void expectedButFound<std::string>(TResult result, std::string expected, std::string found, const char* prependFormat, ...)
- {
- FMT_TO_RESULT(prependFormat, prependFormat, prepend);
- __testlib_expectedButFound(result, expected, found, prepend.c_str());
- }
- template <>
- #ifdef __GNUC__
- __attribute__ ((format (printf, 4, 5)))
- #endif
- NORETURN void expectedButFound<double>(TResult result, double expected, double found, const char* prependFormat, ...)
- {
- FMT_TO_RESULT(prependFormat, prependFormat, prepend);
- std::string expectedString = removeDoubleTrailingZeroes(format("%.12f", expected));
- std::string foundString = removeDoubleTrailingZeroes(format("%.12f", found));
- __testlib_expectedButFound(result, expectedString, foundString, prepend.c_str());
- }
- template <>
- #ifdef __GNUC__
- __attribute__ ((format (printf, 4, 5)))
- #endif
- NORETURN void expectedButFound<const char*>(TResult result, const char* expected, const char* found, const char* prependFormat, ...)
- {
- FMT_TO_RESULT(prependFormat, prependFormat, prepend);
- __testlib_expectedButFound(result, std::string(expected), std::string(found), prepend.c_str());
- }
- template <>
- #ifdef __GNUC__
- __attribute__ ((format (printf, 4, 5)))
- #endif
- NORETURN void expectedButFound<float>(TResult result, float expected, float found, const char* prependFormat, ...)
- {
- FMT_TO_RESULT(prependFormat, prependFormat, prepend);
- __testlib_expectedButFound(result, double(expected), double(found), prepend.c_str());
- }
- template <>
- #ifdef __GNUC__
- __attribute__ ((format (printf, 4, 5)))
- #endif
- NORETURN void expectedButFound<long double>(TResult result, long double expected, long double found, const char* prependFormat, ...)
- {
- FMT_TO_RESULT(prependFormat, prependFormat, prepend);
- __testlib_expectedButFound(result, double(expected), double(found), prepend.c_str());
- }
- #endif
|