2016-07-18 16:39:37 +00:00
/*
* 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 .
*
2022-10-10 06:43:01 +00:00
* See https : //github.com/MikeMirzayanov/testlib/ to get latest version or bug tracker.
2016-07-18 16:39:37 +00:00
*/
# ifndef _TESTLIB_H_
# define _TESTLIB_H_
/*
2022-10-10 06:43:01 +00:00
* Copyright ( c ) 2005 - 2022
2016-07-18 16:39:37 +00:00
*/
2022-10-10 06:43:01 +00:00
# define VERSION "0.9.38-SNAPSHOT"
2016-07-18 16:39:37 +00:00
/*
* 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 ) .
*/
2022-10-10 06:43:01 +00:00
const char * latestFeatures [ ] = {
" For checker added --group and --testset command line params (like for validator), use checker.group() or checker.testset() to get values " ,
" Added quitpi(points_info, message) function to return with _points exit code 7 and given points_info " ,
" rnd.partition(size, sum[, min_part=1]) returns random (unsorted) partition which is a representation of the given `sum` as a sum of `size` positive integers (or >=min_part if specified) " ,
" rnd.distinct(size, n) and rnd.distinct(size, from, to) " ,
" opt<bool>( \" some_missing_key \" ) returns false now " ,
" has_opt(key) " ,
" Abort validator on validator.testset()/validator.group() if registered without using command line " ,
" Print integer range violations in a human readable way like `violates the range [1, 10^9]` " ,
" Opts supported: use them like n = opt<int>( \" n \" ), in a command line you can use an exponential notation " ,
" Reformatted " ,
" Use setTestCase(i) or unsetTestCase() to support test cases (you can use it in any type of program: generator, interactor, validator or checker) " ,
" Fixed issue #87: readStrictDouble accepts \" -0.00 \" " ,
" Fixed issue #83: added InStream::quitif(condition, ...) " ,
" Fixed issue #79: fixed missed guard against repeated header include " ,
" Fixed issue #80: fixed UB in case of huge quitf message " ,
" Fixed issue #84: added readXs(size, indexBase = 1) " ,
" Fixed stringstream repeated usage issue " ,
" Fixed compilation in g++ (for std=c++03) " ,
" Batch of println functions (support collections, iterator ranges) " ,
" Introduced rnd.perm(size, first = 0) to generate a `first`-indexed permutation " ,
" Allow any whitespace in readInts-like functions for non-validators " ,
" Ignore 4+ command line arguments ifdef EJUDGE " ,
" Speed up of vtos " ,
" Show line number in validators in case of incorrect format " ,
" Truncate huge checker/validator/interactor message " ,
" Fixed issue with readTokenTo of very long tokens, now aborts with _pe/_fail depending of a stream type " ,
" Introduced InStream::ensure/ensuref checking a condition, returns wa/fail depending of a stream type " ,
" 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) " ,
" Added compatibility with Contester (compile with CONTESTER directive) "
} ;
2016-07-18 16:39:37 +00:00
# ifdef _MSC_VER
# define _CRT_SECURE_NO_DEPRECATE
# define _CRT_SECURE_NO_WARNINGS
2022-10-10 06:43:01 +00:00
# define _CRT_NO_VA_START_VALIDATION
2016-07-18 16:39:37 +00:00
# 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>
2022-10-10 06:43:01 +00:00
# include <map>
# include <set>
2016-07-18 16:39:37 +00:00
# include <cmath>
2022-10-10 06:43:01 +00:00
# include <iostream>
2016-07-18 16:39:37 +00:00
# include <sstream>
# include <fstream>
# include <cstring>
# include <limits>
# include <stdarg.h>
# include <fcntl.h>
2022-10-10 06:43:01 +00:00
# if (_WIN32 || __WIN32__ || _WIN64 || __WIN64__ || __CYGWIN__)
# if !defined(_MSC_VER) || _MSC_VER > 1400
# define NOMINMAX 1
2016-07-18 16:39:37 +00:00
# include <windows.h>
# else
# define WORD unsigned short
2022-10-10 06:43:01 +00:00
# include <unistd.h>
2016-07-18 16:39:37 +00:00
# endif
# include <io.h>
# define ON_WINDOWS
2022-10-10 06:43:01 +00:00
# if defined(_MSC_VER) && _MSC_VER > 1400
# pragma warning( disable : 4127 )
# pragma warning( disable : 4146 )
# pragma warning( disable : 4458 )
# endif
2016-07-18 16:39:37 +00:00
# else
# define WORD unsigned short
2022-10-10 06:43:01 +00:00
# include <unistd.h>
2016-07-18 16:39:37 +00:00
# endif
2022-10-10 06:43:01 +00:00
# if defined(FOR_WINDOWS) && defined(FOR_LINUX)
# error Only one target system is allowed
2016-07-18 16:39:37 +00:00
# endif
# ifndef LLONG_MIN
# define LLONG_MIN (-9223372036854775807LL - 1)
# endif
2022-10-10 06:43:01 +00:00
# ifndef ULLONG_MAX
# define ULLONG_MAX (18446744073709551615)
# endif
2016-07-18 16:39:37 +00:00
# define LF ((char)10)
# define CR ((char)13)
# define TAB ((char)9)
# define SPACE ((char)' ')
2022-10-10 06:43:01 +00:00
# define EOFC (255)
2016-07-18 16:39:37 +00:00
# ifndef OK_EXIT_CODE
2022-10-10 06:43:01 +00:00
# ifdef CONTESTER
# define OK_EXIT_CODE 0xAC
# else
# define OK_EXIT_CODE 0
# endif
2016-07-18 16:39:37 +00:00
# endif
# ifndef WA_EXIT_CODE
# ifdef EJUDGE
# define WA_EXIT_CODE 5
2022-10-10 06:43:01 +00:00
# elif defined(CONTESTER)
# define WA_EXIT_CODE 0xAB
2016-07-18 16:39:37 +00:00
# else
# define WA_EXIT_CODE 1
# endif
# endif
# ifndef PE_EXIT_CODE
# ifdef EJUDGE
# define PE_EXIT_CODE 4
2022-10-10 06:43:01 +00:00
# elif defined(CONTESTER)
# define PE_EXIT_CODE 0xAA
2016-07-18 16:39:37 +00:00
# else
# define PE_EXIT_CODE 2
# endif
# endif
# ifndef FAIL_EXIT_CODE
# ifdef EJUDGE
# define FAIL_EXIT_CODE 6
2022-10-10 06:43:01 +00:00
# elif defined(CONTESTER)
# define FAIL_EXIT_CODE 0xA3
2016-07-18 16:39:37 +00:00
# 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
2022-10-10 06:43:01 +00:00
# define POINTS_EXIT_CODE 7
2016-07-18 16:39:37 +00:00
# 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
2022-10-10 06:43:01 +00:00
static char __testlib_format_buffer [ 16777216 ] ;
2016-07-18 16:39:37 +00:00
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 ) ; \
2022-10-10 06:43:01 +00:00
vsnprintf ( __testlib_format_buffer , sizeof ( __testlib_format_buffer ) , cstr , ap ) ; \
2016-07-18 16:39:37 +00:00
va_end ( ap ) ; \
2022-10-10 06:43:01 +00:00
__testlib_format_buffer [ sizeof ( __testlib_format_buffer ) - 1 ] = 0 ; \
2016-07-18 16:39:37 +00:00
result = std : : string ( __testlib_format_buffer ) ; \
__testlib_format_buffer_usage_count - - ; \
const long long __TESTLIB_LONGLONG_MAX = 9223372036854775807LL ;
2022-10-10 06:43:01 +00:00
bool __testlib_hasTestCase ;
int __testlib_testCase = - 1 ;
void setTestCase ( int testCase ) {
__testlib_hasTestCase = true ;
__testlib_testCase = testCase ;
}
void unsetTestCase ( ) {
__testlib_hasTestCase = false ;
__testlib_testCase = - 1 ;
}
NORETURN static void __testlib_fail ( const std : : string & message ) ;
2016-07-18 16:39:37 +00:00
template < typename T >
2022-10-10 06:43:01 +00:00
static inline T __testlib_abs ( const T & x ) {
2016-07-18 16:39:37 +00:00
return x > 0 ? x : - x ;
}
template < typename T >
2022-10-10 06:43:01 +00:00
static inline T __testlib_min ( const T & a , const T & b ) {
2016-07-18 16:39:37 +00:00
return a < b ? a : b ;
}
template < typename T >
2022-10-10 06:43:01 +00:00
static inline T __testlib_max ( const T & a , const T & b ) {
2016-07-18 16:39:37 +00:00
return a > b ? a : b ;
}
2022-10-10 06:43:01 +00:00
static bool __testlib_prelimIsNaN ( double r ) {
2016-07-18 16:39:37 +00:00
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
}
2022-10-10 06:43:01 +00:00
static std : : string removeDoubleTrailingZeroes ( std : : string value ) {
2016-07-18 16:39:37 +00:00
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
2022-10-10 06:43:01 +00:00
std : : string format ( const char * fmt , . . . ) {
2016-07-18 16:39:37 +00:00
FMT_TO_RESULT ( fmt , fmt , result ) ;
return result ;
}
2022-10-10 06:43:01 +00:00
std : : string format ( const std : : string fmt , . . . ) {
2016-07-18 16:39:37 +00:00
FMT_TO_RESULT ( fmt , fmt . c_str ( ) , result ) ;
return result ;
}
2022-10-10 06:43:01 +00:00
static std : : string __testlib_part ( const std : : string & s ) ;
2016-07-18 16:39:37 +00:00
2022-10-10 06:43:01 +00:00
static bool __testlib_isNaN ( double r ) {
2016-07-18 16:39:37 +00:00
__TESTLIB_STATIC_ASSERT ( sizeof ( double ) = = sizeof ( long long ) ) ;
volatile double ra = r ;
long long llr1 , llr2 ;
2022-10-10 06:43:01 +00:00
std : : memcpy ( ( void * ) & llr1 , ( void * ) & ra , sizeof ( double ) ) ;
2016-07-18 16:39:37 +00:00
ra = - ra ;
2022-10-10 06:43:01 +00:00
std : : memcpy ( ( void * ) & llr2 , ( void * ) & ra , sizeof ( double ) ) ;
long long llnan = 0xFFF8000000000000LL ;
2016-07-18 16:39:37 +00:00
return __testlib_prelimIsNaN ( r ) | | llnan = = llr1 | | llnan = = llr2 ;
}
2022-10-10 06:43:01 +00:00
static double __testlib_nan ( ) {
2016-07-18 16:39:37 +00:00
__TESTLIB_STATIC_ASSERT ( sizeof ( double ) = = sizeof ( long long ) ) ;
2022-10-10 06:43:01 +00:00
# ifndef NAN
long long llnan = 0xFFF8000000000000LL ;
2016-07-18 16:39:37 +00:00
double nan ;
std : : memcpy ( & nan , & llnan , sizeof ( double ) ) ;
return nan ;
2022-10-10 06:43:01 +00:00
# else
return NAN ;
# endif
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
static bool __testlib_isInfinite ( double r ) {
2016-07-18 16:39:37 +00:00
volatile double ra = r ;
2022-10-10 06:43:01 +00:00
return ( ra > 1E300 | | ra < - 1E300 ) ;
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
# ifdef __GNUC__
__attribute__ ( ( const ) )
2016-07-18 16:39:37 +00:00
# endif
2022-10-10 06:43:01 +00:00
inline bool doubleCompare ( double expected , double result , double MAX_DOUBLE_ERROR ) {
MAX_DOUBLE_ERROR + = 1E-15 ;
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 ) {
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 > = minv & & result < = maxv ;
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
}
# ifdef __GNUC__
__attribute__ ( ( const ) )
2016-07-18 16:39:37 +00:00
# endif
2022-10-10 06:43:01 +00:00
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 ;
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
static void __testlib_set_binary ( std : : FILE * file ) {
if ( NULL ! = file ) {
# ifdef O_BINARY
# ifdef _MSC_VER
_setmode ( _fileno ( file ) , O_BINARY ) ;
# elseif
setmode ( fileno ( file ) , O_BINARY ) ;
# endif
2016-07-18 16:39:37 +00:00
# else
2022-10-10 06:43:01 +00:00
if ( file = = stdin )
freopen ( NULL , " rb " , file ) ;
if ( file = = stdout | | file = = stderr )
freopen ( NULL , " wb " , file ) ;
2016-07-18 16:39:37 +00:00
# endif
2022-10-10 06:43:01 +00:00
}
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
# if __cplusplus > 199711L || defined(_MSC_VER)
/* opts */
void prepareOpts ( int argc , char * argv [ ] ) ;
# endif
2016-07-18 16:39:37 +00:00
/*
* 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 ] + " ) " .
2022-10-10 06:43:01 +00:00
*
* All spaces are ignored in regex , unless escaped with \ . For example , ouf . readLine ( " NO SOLUTION " )
* will expect " NOSOLUTION " , the correct call should be ouf . readLine ( " NO \\ SOLUTION " ) or
* ouf . readLine ( R " (NO \ SOLUTION) " ) if you prefer raw string literals from C + + 11.
2016-07-18 16:39:37 +00:00
*/
class random_t ;
2022-10-10 06:43:01 +00:00
class pattern {
2016-07-18 16:39:37 +00:00
public :
/* Create pattern instance by string. */
pattern ( std : : string s ) ;
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
/* Generate new string by pattern and given random_t. */
2022-10-10 06:43:01 +00:00
std : : string next ( random_t & rnd ) const ;
2016-07-18 16:39:37 +00:00
/* Checks if given string match the pattern. */
2022-10-10 06:43:01 +00:00
bool matches ( const std : : string & s ) const ;
2016-07-18 16:39:37 +00:00
/* Returns source string of the pattern. */
std : : string src ( ) const ;
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
private :
2022-10-10 06:43:01 +00:00
bool matches ( const std : : string & s , size_t pos ) const ;
2016-07-18 16:39:37 +00:00
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 .
*/
2022-10-10 06:43:01 +00:00
class random_t {
2016-07-18 16:39:37 +00:00
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 ;
2022-10-10 06:43:01 +00:00
long long nextBits ( int bits ) {
if ( bits < = 48 ) {
2016-07-18 16:39:37 +00:00
seed = ( seed * multiplier + addend ) & mask ;
2022-10-10 06:43:01 +00:00
return ( long long ) ( seed > > ( 48 - bits ) ) ;
} else {
2016-07-18 16:39:37 +00:00
if ( bits > 63 )
__testlib_fail ( " random_t::nextBits(int bits): n must be less than 64 " ) ;
int lowerBitCount = ( random_t : : version = = 0 ? 31 : 32 ) ;
2022-10-10 06:43:01 +00:00
long long left = ( nextBits ( 31 ) < < 32 ) ;
long long right = nextBits ( lowerBitCount ) ;
return left ^ right ;
2016-07-18 16:39:37 +00:00
}
}
public :
static int version ;
/* New random_t with fixed seed. */
random_t ( )
2022-10-10 06:43:01 +00:00
: seed ( 3905348978240129619LL ) {
2016-07-18 16:39:37 +00:00
}
/* Sets seed by command line. */
2022-10-10 06:43:01 +00:00
void setSeed ( int argc , char * argv [ ] ) {
2016-07-18 16:39:37 +00:00
random_t p ;
seed = 3905348978240129619LL ;
2022-10-10 06:43:01 +00:00
for ( int i = 1 ; i < argc ; i + + ) {
2016-07-18 16:39:37 +00:00
std : : size_t le = std : : strlen ( argv [ i ] ) ;
for ( std : : size_t j = 0 ; j < le ; j + + )
2022-10-10 06:43:01 +00:00
seed = seed * multiplier + ( unsigned int ) ( argv [ i ] [ j ] ) + addend ;
2016-07-18 16:39:37 +00:00
seed + = multiplier / addend ;
}
seed = seed & mask ;
}
2022-10-10 06:43:01 +00:00
/* Sets seed by given value. */
void setSeed ( long long _seed ) {
2016-07-18 16:39:37 +00:00
_seed = ( _seed ^ multiplier ) & mask ;
seed = _seed ;
}
# ifndef __BORLANDC__
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
/* Random string value by given pattern (see pattern documentation). */
2022-10-10 06:43:01 +00:00
std : : string next ( const std : : string & ptrn ) {
2016-07-18 16:39:37 +00:00
pattern p ( ptrn ) ;
return p . next ( * this ) ;
}
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
# 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]. */
2022-10-10 06:43:01 +00:00
int next ( int n ) {
2016-07-18 16:39:37 +00:00
if ( n < = 0 )
__testlib_fail ( " random_t::next(int n): n must be positive " ) ;
if ( ( n & - n ) = = n ) // n is a power of 2
2022-10-10 06:43:01 +00:00
return ( int ) ( ( n * ( long long ) nextBits ( 31 ) ) > > 31 ) ;
2016-07-18 16:39:37 +00:00
const long long limit = INT_MAX / n * n ;
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
long long bits ;
do {
bits = nextBits ( 31 ) ;
} while ( bits > = limit ) ;
return int ( bits % n ) ;
}
/* Random value in range [0, n-1]. */
2022-10-10 06:43:01 +00:00
unsigned int next ( unsigned int n ) {
2016-07-18 16:39:37 +00:00
if ( n > = INT_MAX )
__testlib_fail ( " random_t::next(unsigned int n): n must be less INT_MAX " ) ;
2022-10-10 06:43:01 +00:00
return ( unsigned int ) next ( int ( n ) ) ;
2016-07-18 16:39:37 +00:00
}
/* Random value in range [0, n-1]. */
2022-10-10 06:43:01 +00:00
long long next ( long long n ) {
2016-07-18 16:39:37 +00:00
if ( n < = 0 )
__testlib_fail ( " random_t::next(long long n): n must be positive " ) ;
const long long limit = __TESTLIB_LONGLONG_MAX / n * n ;
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
long long bits ;
do {
bits = nextBits ( 63 ) ;
} while ( bits > = limit ) ;
return bits % n ;
}
/* Random value in range [0, n-1]. */
2022-10-10 06:43:01 +00:00
unsigned long long next ( unsigned long long n ) {
if ( n > = ( unsigned long long ) ( __TESTLIB_LONGLONG_MAX ) )
2016-07-18 16:39:37 +00:00
__testlib_fail ( " random_t::next(unsigned long long n): n must be less LONGLONG_MAX " ) ;
2022-10-10 06:43:01 +00:00
return ( unsigned long long ) next ( ( long long ) ( n ) ) ;
2016-07-18 16:39:37 +00:00
}
/* Random value in range [0, n-1]. */
2022-10-10 06:43:01 +00:00
long next ( long n ) {
return ( long ) next ( ( long long ) ( n ) ) ;
2016-07-18 16:39:37 +00:00
}
/* Random value in range [0, n-1]. */
2022-10-10 06:43:01 +00:00
unsigned long next ( unsigned long n ) {
if ( n > = ( unsigned long ) ( LONG_MAX ) )
2016-07-18 16:39:37 +00:00
__testlib_fail ( " random_t::next(unsigned long n): n must be less LONG_MAX " ) ;
2022-10-10 06:43:01 +00:00
return ( unsigned long ) next ( ( unsigned long long ) ( n ) ) ;
2016-07-18 16:39:37 +00:00
}
/* Returns random value in range [from,to]. */
2022-10-10 06:43:01 +00:00
int next ( int from , int to ) {
return int ( next ( ( long long ) to - from + 1 ) + from ) ;
2016-07-18 16:39:37 +00:00
}
/* Returns random value in range [from,to]. */
2022-10-10 06:43:01 +00:00
unsigned int next ( unsigned int from , unsigned int to ) {
return ( unsigned int ) ( next ( ( long long ) to - from + 1 ) + from ) ;
2016-07-18 16:39:37 +00:00
}
/* Returns random value in range [from,to]. */
2022-10-10 06:43:01 +00:00
long long next ( long long from , long long to ) {
2016-07-18 16:39:37 +00:00
return next ( to - from + 1 ) + from ;
}
/* Returns random value in range [from,to]. */
2022-10-10 06:43:01 +00:00
unsigned long long next ( unsigned long long from , unsigned long long to ) {
2016-07-18 16:39:37 +00:00
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]. */
2022-10-10 06:43:01 +00:00
long next ( long from , long to ) {
2016-07-18 16:39:37 +00:00
return next ( to - from + 1 ) + from ;
}
/* Returns random value in range [from,to]. */
2022-10-10 06:43:01 +00:00
unsigned long next ( unsigned long from , unsigned long to ) {
2016-07-18 16:39:37 +00:00
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). */
2022-10-10 06:43:01 +00:00
double next ( ) {
long long left = ( ( long long ) ( nextBits ( 26 ) ) < < 27 ) ;
long long right = nextBits ( 27 ) ;
return ( double ) ( left + right ) / ( double ) ( 1LL < < 53 ) ;
2016-07-18 16:39:37 +00:00
}
/* Random double value in range [0, n). */
2022-10-10 06:43:01 +00:00
double next ( double n ) {
2016-07-18 16:39:37 +00:00
return n * next ( ) ;
}
/* Random double value in range [from, to). */
2022-10-10 06:43:01 +00:00
double next ( double from , double to ) {
if ( from > to )
__testlib_fail ( " random_t::next(double from, double to): from can't not exceed to " ) ;
2016-07-18 16:39:37 +00:00
return next ( to - from ) + from ;
}
/* Returns random element from container. */
2022-10-10 06:43:01 +00:00
template < typename Container >
typename Container : : value_type any ( const Container & c ) {
2016-07-18 16:39:37 +00:00
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. */
2022-10-10 06:43:01 +00:00
template < typename Iter >
typename Iter : : value_type any ( const Iter & begin , const Iter & end ) {
2016-07-18 16:39:37 +00:00
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
2022-10-10 06:43:01 +00:00
std : : string next ( const char * format , . . . ) {
2016-07-18 16:39:37 +00:00
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 " .
*/
2022-10-10 06:43:01 +00:00
int wnext ( int n , int type ) {
2016-07-18 16:39:37 +00:00
if ( n < = 0 )
__testlib_fail ( " random_t::wnext(int n, int type): n must be positive " ) ;
2022-10-10 06:43:01 +00:00
if ( abs ( type ) < random_t : : lim ) {
2016-07-18 16:39:37 +00:00
int result = next ( n ) ;
for ( int i = 0 ; i < + type ; i + + )
result = __testlib_max ( result , next ( n ) ) ;
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
for ( int i = 0 ; i < - type ; i + + )
result = __testlib_min ( result , next ( n ) ) ;
return result ;
2022-10-10 06:43:01 +00:00
} else {
2016-07-18 16:39:37 +00:00
double p ;
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
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 ) ;
}
}
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
/* See wnext(int, int). It uses the same algorithms. */
2022-10-10 06:43:01 +00:00
long long wnext ( long long n , int type ) {
2016-07-18 16:39:37 +00:00
if ( n < = 0 )
__testlib_fail ( " random_t::wnext(long long n, int type): n must be positive " ) ;
2022-10-10 06:43:01 +00:00
if ( abs ( type ) < random_t : : lim ) {
2016-07-18 16:39:37 +00:00
long long result = next ( n ) ;
for ( int i = 0 ; i < + type ; i + + )
result = __testlib_max ( result , next ( n ) ) ;
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
for ( int i = 0 ; i < - type ; i + + )
result = __testlib_min ( result , next ( n ) ) ;
return result ;
2022-10-10 06:43:01 +00:00
} else {
2016-07-18 16:39:37 +00:00
double p ;
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
if ( type > 0 )
p = std : : pow ( next ( ) + 0.0 , 1.0 / ( type + 1 ) ) ;
else
2022-10-10 06:43:01 +00:00
p = std : : pow ( next ( ) + 0.0 , - type + 1 ) ;
2016-07-18 16:39:37 +00:00
2022-10-10 06:43:01 +00:00
return __testlib_min ( __testlib_max ( ( long long ) ( double ( n ) * p ) , 0LL ) , n - 1LL ) ;
2016-07-18 16:39:37 +00:00
}
}
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
/* See wnext(int, int). It uses the same algorithms. */
2022-10-10 06:43:01 +00:00
double wnext ( int type ) {
if ( abs ( type ) < random_t : : lim ) {
2016-07-18 16:39:37 +00:00
double result = next ( ) ;
for ( int i = 0 ; i < + type ; i + + )
result = __testlib_max ( result , next ( ) ) ;
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
for ( int i = 0 ; i < - type ; i + + )
result = __testlib_min ( result , next ( ) ) ;
return result ;
2022-10-10 06:43:01 +00:00
} else {
2016-07-18 16:39:37 +00:00
double p ;
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
if ( type > 0 )
p = std : : pow ( next ( ) + 0.0 , 1.0 / ( type + 1 ) ) ;
else
2022-10-10 06:43:01 +00:00
p = std : : pow ( next ( ) + 0.0 , - type + 1 ) ;
2016-07-18 16:39:37 +00:00
return p ;
}
}
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
/* See wnext(int, int). It uses the same algorithms. */
2022-10-10 06:43:01 +00:00
double wnext ( double n , int type ) {
2016-07-18 16:39:37 +00:00
if ( n < = 0 )
__testlib_fail ( " random_t::wnext(double n, int type): n must be positive " ) ;
2022-10-10 06:43:01 +00:00
if ( abs ( type ) < random_t : : lim ) {
2016-07-18 16:39:37 +00:00
double result = next ( ) ;
for ( int i = 0 ; i < + type ; i + + )
result = __testlib_max ( result , next ( ) ) ;
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
for ( int i = 0 ; i < - type ; i + + )
result = __testlib_min ( result , next ( ) ) ;
return n * result ;
2022-10-10 06:43:01 +00:00
} else {
2016-07-18 16:39:37 +00:00
double p ;
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
if ( type > 0 )
p = std : : pow ( next ( ) + 0.0 , 1.0 / ( type + 1 ) ) ;
else
2022-10-10 06:43:01 +00:00
p = std : : pow ( next ( ) + 0.0 , - type + 1 ) ;
2016-07-18 16:39:37 +00:00
return n * p ;
}
}
/* See wnext(int, int). It uses the same algorithms. */
2022-10-10 06:43:01 +00:00
unsigned int wnext ( unsigned int n , int type ) {
2016-07-18 16:39:37 +00:00
if ( n > = INT_MAX )
__testlib_fail ( " random_t::wnext(unsigned int n, int type): n must be less INT_MAX " ) ;
2022-10-10 06:43:01 +00:00
return ( unsigned int ) wnext ( int ( n ) , type ) ;
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
/* See wnext(int, int). It uses the same algorithms. */
2022-10-10 06:43:01 +00:00
unsigned long long wnext ( unsigned long long n , int type ) {
if ( n > = ( unsigned long long ) ( __TESTLIB_LONGLONG_MAX ) )
2016-07-18 16:39:37 +00:00
__testlib_fail ( " random_t::wnext(unsigned long long n, int type): n must be less LONGLONG_MAX " ) ;
2022-10-10 06:43:01 +00:00
return ( unsigned long long ) wnext ( ( long long ) ( n ) , type ) ;
2016-07-18 16:39:37 +00:00
}
/* See wnext(int, int). It uses the same algorithms. */
2022-10-10 06:43:01 +00:00
long wnext ( long n , int type ) {
return ( long ) wnext ( ( long long ) ( n ) , type ) ;
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
/* See wnext(int, int). It uses the same algorithms. */
2022-10-10 06:43:01 +00:00
unsigned long wnext ( unsigned long n , int type ) {
if ( n > = ( unsigned long ) ( LONG_MAX ) )
2016-07-18 16:39:37 +00:00
__testlib_fail ( " random_t::wnext(unsigned long n, int type): n must be less LONG_MAX " ) ;
2022-10-10 06:43:01 +00:00
return ( unsigned long ) wnext ( ( unsigned long long ) ( n ) , type ) ;
2016-07-18 16:39:37 +00:00
}
/* Returns weighted random value in range [from, to]. */
2022-10-10 06:43:01 +00:00
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 " ) ;
2016-07-18 16:39:37 +00:00
return wnext ( to - from + 1 , type ) + from ;
}
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
/* Returns weighted random value in range [from, to]. */
2022-10-10 06:43:01 +00:00
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 " ) ;
2016-07-18 16:39:37 +00:00
return int ( wnext ( to - from + 1 , type ) + from ) ;
}
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
/* Returns weighted random value in range [from, to]. */
2022-10-10 06:43:01 +00:00
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 " ) ;
2016-07-18 16:39:37 +00:00
return wnext ( to - from + 1 , type ) + from ;
}
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
/* Returns weighted random value in range [from, to]. */
2022-10-10 06:43:01 +00:00
unsigned long long wnext ( unsigned long long from , unsigned long long to , int type ) {
2016-07-18 16:39:37 +00:00
if ( from > to )
2022-10-10 06:43:01 +00:00
__testlib_fail (
" random_t::wnext(unsigned long long from, unsigned long long to, int type): from can't not exceed to " ) ;
2016-07-18 16:39:37 +00:00
return wnext ( to - from + 1 , type ) + from ;
}
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
/* Returns weighted random value in range [from, to]. */
2022-10-10 06:43:01 +00:00
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 " ) ;
2016-07-18 16:39:37 +00:00
return wnext ( to - from + 1 , type ) + from ;
}
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
/* Returns weighted random value in range [from, to]. */
2022-10-10 06:43:01 +00:00
unsigned long wnext ( unsigned long from , unsigned long to , int type ) {
2016-07-18 16:39:37 +00:00
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 ;
}
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
/* Returns weighted random double value in range [from, to). */
2022-10-10 06:43:01 +00:00
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 " ) ;
2016-07-18 16:39:37 +00:00
return wnext ( to - from , type ) + from ;
}
/* Returns weighted random element from container. */
2022-10-10 06:43:01 +00:00
template < typename Container >
typename Container : : value_type wany ( const Container & c , int type ) {
2016-07-18 16:39:37 +00:00
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. */
2022-10-10 06:43:01 +00:00
template < typename Iter >
typename Iter : : value_type wany ( const Iter & begin , const Iter & end , int type ) {
2016-07-18 16:39:37 +00:00
int size = int ( end - begin ) ;
if ( size < = 0 )
2022-10-10 06:43:01 +00:00
__testlib_fail (
" random_t::any(const Iter& begin, const Iter& end, int type): range must have positive length " ) ;
2016-07-18 16:39:37 +00:00
return * ( begin + wnext ( size , type ) ) ;
}
2022-10-10 06:43:01 +00:00
/* Returns random permutation of the given size (values are between `first` and `first`+size-1)*/
template < typename T , typename E >
std : : vector < E > perm ( T size , E first ) {
if ( size < = 0 )
__testlib_fail ( " random_t::perm(T size, E first = 0): size must be positive " ) ;
std : : vector < E > p ( size ) ;
E current = first ;
for ( T i = 0 ; i < size ; i + + )
p [ i ] = current + + ;
if ( size > 1 )
for ( T i = 1 ; i < size ; i + + )
std : : swap ( p [ i ] , p [ next ( i + 1 ) ] ) ;
return p ;
}
/* Returns random permutation of the given size (values are between 0 and size-1)*/
template < typename T >
std : : vector < T > perm ( T size ) {
return perm ( size , T ( 0 ) ) ;
}
/* Returns `size` unordered (unsorted) distinct numbers between `from` and `to`. */
template < typename T >
std : : vector < T > distinct ( int size , T from , T to ) {
std : : vector < T > result ;
if ( size = = 0 )
return result ;
if ( from > to )
__testlib_fail ( " random_t::distinct expected from <= to " ) ;
if ( size < 0 )
__testlib_fail ( " random_t::distinct expected size >= 0 " ) ;
uint64_t n = to - from + 1 ;
if ( uint64_t ( size ) > n )
__testlib_fail ( " random_t::distinct expected size <= to - from + 1 " ) ;
double expected = 0.0 ;
for ( int i = 1 ; i < = size ; i + + )
expected + = double ( n ) / double ( n - i + 1 ) ;
if ( expected < double ( n ) ) {
std : : set < T > vals ;
while ( int ( vals . size ( ) ) < size ) {
T x = T ( next ( from , to ) ) ;
if ( vals . insert ( x ) . second )
result . push_back ( x ) ;
}
} else {
if ( n > 1000000000 )
__testlib_fail ( " random_t::distinct here expected to - from + 1 <= 1000000000 " ) ;
std : : vector < T > p ( perm ( int ( n ) , from ) ) ;
result . insert ( result . end ( ) , p . begin ( ) , p . begin ( ) + size ) ;
}
return result ;
}
/* Returns `size` unordered (unsorted) distinct numbers between `0` and `upper`-1. */
template < typename T >
std : : vector < T > distinct ( int size , T upper ) {
if ( size < 0 )
__testlib_fail ( " random_t::distinct expected size >= 0 " ) ;
if ( size = = 0 )
return std : : vector < T > ( ) ;
if ( upper < = 0 )
__testlib_fail ( " random_t::distinct expected upper > 0 " ) ;
if ( size > upper )
__testlib_fail ( " random_t::distinct expected size <= upper " ) ;
return distinct ( size , T ( 0 ) , upper - 1 ) ;
}
/* Returns random (unsorted) partition which is a representation of sum as a sum of integers not less than min_part. */
template < typename T >
std : : vector < T > partition ( int size , T sum , T min_part ) {
if ( size < 0 )
__testlib_fail ( " random_t::partition: size < 0 " ) ;
if ( size = = 0 & & sum ! = 0 )
__testlib_fail ( " random_t::partition: size == 0 && sum != 0 " ) ;
if ( min_part * size > sum )
__testlib_fail ( " random_t::partition: min_part * size > sum " ) ;
if ( size = = 0 & & sum = = 0 )
return std : : vector < T > ( ) ;
T sum_ = sum ;
sum - = min_part * size ;
std : : vector < T > septums ( size ) ;
std : : vector < T > d = distinct ( size - 1 , T ( 1 ) , T ( sum + size - 1 ) ) ;
for ( int i = 0 ; i + 1 < size ; i + + )
septums [ i + 1 ] = d [ i ] ;
sort ( septums . begin ( ) , septums . end ( ) ) ;
std : : vector < T > result ( size ) ;
for ( int i = 0 ; i + 1 < size ; i + + )
result [ i ] = septums [ i + 1 ] - septums [ i ] - 1 ;
result [ size - 1 ] = sum + size - 1 - septums . back ( ) ;
for ( std : : size_t i = 0 ; i < result . size ( ) ; i + + )
result [ i ] + = min_part ;
T result_sum = 0 ;
for ( std : : size_t i = 0 ; i < result . size ( ) ; i + + )
result_sum + = result [ i ] ;
if ( result_sum ! = sum_ )
__testlib_fail ( " random_t::partition: partition sum is expected to be the given sum " ) ;
if ( * std : : min_element ( result . begin ( ) , result . end ( ) ) < min_part )
__testlib_fail ( " random_t::partition: partition min is expected to be no less than the given min_part " ) ;
if ( int ( result . size ( ) ) ! = size | | result . size ( ) ! = ( size_t ) size )
__testlib_fail ( " random_t::partition: partition size is expected to be equal to the given size " ) ;
return result ;
}
/* Returns random (unsorted) partition which is a representation of sum as a sum of positive integers. */
template < typename T >
std : : vector < T > partition ( int size , T sum ) {
return partition ( size , sum , T ( 1 ) ) ;
}
2016-07-18 16:39:37 +00:00
} ;
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 */
2022-10-10 06:43:01 +00:00
bool pattern : : matches ( const std : : string & s ) const {
2016-07-18 16:39:37 +00:00
return matches ( s , 0 ) ;
}
2022-10-10 06:43:01 +00:00
static bool __pattern_isSlash ( const std : : string & s , size_t pos ) {
2016-07-18 16:39:37 +00:00
return s [ pos ] = = ' \\ ' ;
}
# ifdef __GNUC__
__attribute__ ( ( pure ) )
# endif
2022-10-10 06:43:01 +00:00
static bool __pattern_isCommandChar ( const std : : string & s , size_t pos , char value ) {
2016-07-18 16:39:37 +00:00
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 ;
}
2022-10-10 06:43:01 +00:00
static char __pattern_getChar ( const std : : string & s , size_t & pos ) {
2016-07-18 16:39:37 +00:00
if ( __pattern_isSlash ( s , pos ) )
pos + = 2 ;
else
pos + + ;
return s [ pos - 1 ] ;
}
# ifdef __GNUC__
__attribute__ ( ( pure ) )
# endif
2022-10-10 06:43:01 +00:00
static int __pattern_greedyMatch ( const std : : string & s , size_t pos , const std : : vector < char > chars ) {
2016-07-18 16:39:37 +00:00
int result = 0 ;
2022-10-10 06:43:01 +00:00
while ( pos < s . length ( ) ) {
2016-07-18 16:39:37 +00:00
char c = s [ pos + + ] ;
if ( ! std : : binary_search ( chars . begin ( ) , chars . end ( ) , c ) )
break ;
else
result + + ;
}
return result ;
}
2022-10-10 06:43:01 +00:00
std : : string pattern : : src ( ) const {
2016-07-18 16:39:37 +00:00
return s ;
}
2022-10-10 06:43:01 +00:00
bool pattern : : matches ( const std : : string & s , size_t pos ) const {
2016-07-18 16:39:37 +00:00
std : : string result ;
2022-10-10 06:43:01 +00:00
if ( to > 0 ) {
2016-07-18 16:39:37 +00:00
int size = __pattern_greedyMatch ( s , pos , chars ) ;
if ( size < from )
return false ;
if ( size > to )
size = to ;
pos + = size ;
}
2022-10-10 06:43:01 +00:00
if ( children . size ( ) > 0 ) {
2016-07-18 16:39:37 +00:00
for ( size_t child = 0 ; child < children . size ( ) ; child + + )
if ( children [ child ] . matches ( s , pos ) )
return true ;
return false ;
2022-10-10 06:43:01 +00:00
} else
2016-07-18 16:39:37 +00:00
return pos = = s . length ( ) ;
}
2022-10-10 06:43:01 +00:00
std : : string pattern : : next ( random_t & rnd ) const {
2016-07-18 16:39:37 +00:00
std : : string result ;
result . reserve ( 20 ) ;
if ( to = = INT_MAX )
__testlib_fail ( " pattern::next(random_t& rnd): can't process character '*' for generation " ) ;
2022-10-10 06:43:01 +00:00
if ( to > 0 ) {
2016-07-18 16:39:37 +00:00
int count = rnd . next ( to - from + 1 ) + from ;
for ( int i = 0 ; i < count ; i + + )
result + = chars [ rnd . next ( int ( chars . size ( ) ) ) ] ;
}
2022-10-10 06:43:01 +00:00
if ( children . size ( ) > 0 ) {
2016-07-18 16:39:37 +00:00
int child = rnd . next ( int ( children . size ( ) ) ) ;
result + = children [ child ] . next ( rnd ) ;
}
return result ;
}
2022-10-10 06:43:01 +00:00
static void __pattern_scanCounts ( const std : : string & s , size_t & pos , int & from , int & to ) {
if ( pos > = s . length ( ) ) {
2016-07-18 16:39:37 +00:00
from = to = 1 ;
return ;
}
2022-10-10 06:43:01 +00:00
if ( __pattern_isCommandChar ( s , pos , ' { ' ) ) {
2016-07-18 16:39:37 +00:00
std : : vector < std : : string > parts ;
std : : string part ;
pos + + ;
2022-10-10 06:43:01 +00:00
while ( pos < s . length ( ) & & ! __pattern_isCommandChar ( s , pos , ' } ' ) ) {
2016-07-18 16:39:37 +00:00
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 ;
2022-10-10 06:43:01 +00:00
for ( size_t i = 0 ; i < parts . size ( ) ; i + + ) {
2016-07-18 16:39:37 +00:00
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 + " \" " ) ;
2022-10-10 06:43:01 +00:00
} else {
if ( __pattern_isCommandChar ( s , pos , ' ? ' ) ) {
2016-07-18 16:39:37 +00:00
from = 0 , to = 1 , pos + + ;
return ;
}
2022-10-10 06:43:01 +00:00
if ( __pattern_isCommandChar ( s , pos , ' * ' ) ) {
2016-07-18 16:39:37 +00:00
from = 0 , to = INT_MAX , pos + + ;
return ;
}
2022-10-10 06:43:01 +00:00
if ( __pattern_isCommandChar ( s , pos , ' + ' ) ) {
2016-07-18 16:39:37 +00:00
from = 1 , to = INT_MAX , pos + + ;
return ;
}
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
from = to = 1 ;
}
}
2022-10-10 06:43:01 +00:00
static std : : vector < char > __pattern_scanCharSet ( const std : : string & s , size_t & pos ) {
2016-07-18 16:39:37 +00:00
if ( pos > = s . length ( ) )
__testlib_fail ( " pattern: Illegal pattern (or part) \" " + s + " \" " ) ;
std : : vector < char > result ;
2022-10-10 06:43:01 +00:00
if ( __pattern_isCommandChar ( s , pos , ' [ ' ) ) {
2016-07-18 16:39:37 +00:00
pos + + ;
bool negative = __pattern_isCommandChar ( s , pos , ' ^ ' ) ;
2022-10-10 06:43:01 +00:00
if ( negative )
pos + + ;
2016-07-18 16:39:37 +00:00
char prev = 0 ;
2022-10-10 06:43:01 +00:00
while ( pos < s . length ( ) & & ! __pattern_isCommandChar ( s , pos , ' ] ' ) ) {
if ( __pattern_isCommandChar ( s , pos , ' - ' ) & & prev ! = 0 ) {
2016-07-18 16:39:37 +00:00
pos + + ;
2022-10-10 06:43:01 +00:00
if ( pos + 1 = = s . length ( ) | | __pattern_isCommandChar ( s , pos , ' ] ' ) ) {
2016-07-18 16:39:37 +00:00
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 ;
2022-10-10 06:43:01 +00:00
} else {
2016-07-18 16:39:37 +00:00
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 + + ;
2022-10-10 06:43:01 +00:00
if ( negative ) {
2016-07-18 16:39:37 +00:00
std : : sort ( result . begin ( ) , result . end ( ) ) ;
std : : vector < char > actuals ;
2022-10-10 06:43:01 +00:00
for ( int code = 0 ; code < 255 ; code + + ) {
2016-07-18 16:39:37 +00:00
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 ( ) ) ;
2022-10-10 06:43:01 +00:00
} else
2016-07-18 16:39:37 +00:00
result . push_back ( __pattern_getChar ( s , pos ) ) ;
return result ;
}
2022-10-10 06:43:01 +00:00
pattern : : pattern ( std : : string s ) : s ( s ) , from ( 0 ) , to ( 0 ) {
2016-07-18 16:39:37 +00:00
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 ;
2022-10-10 06:43:01 +00:00
for ( size_t i = 0 ; i < s . length ( ) ; i + + ) {
if ( __pattern_isCommandChar ( s , i , ' ( ' ) ) {
2016-07-18 16:39:37 +00:00
opened + + ;
continue ;
}
2022-10-10 06:43:01 +00:00
if ( __pattern_isCommandChar ( s , i , ' ) ' ) ) {
2016-07-18 16:39:37 +00:00
opened - - ;
if ( opened = = 0 & & firstClose = = - 1 )
firstClose = int ( i ) ;
continue ;
}
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
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 + " \" " ) ;
2022-10-10 06:43:01 +00:00
if ( seps . size ( ) = = 0 & & firstClose + 1 = = ( int ) s . length ( )
& & __pattern_isCommandChar ( s , 0 , ' ( ' ) & & __pattern_isCommandChar ( s , s . length ( ) - 1 , ' ) ' ) ) {
2016-07-18 16:39:37 +00:00
children . push_back ( pattern ( s . substr ( 1 , s . length ( ) - 2 ) ) ) ;
2022-10-10 06:43:01 +00:00
} else {
if ( seps . size ( ) > 0 ) {
seps . push_back ( int ( s . length ( ) ) ) ;
2016-07-18 16:39:37 +00:00
int last = 0 ;
2022-10-10 06:43:01 +00:00
for ( size_t i = 0 ; i < seps . size ( ) ; i + + ) {
2016-07-18 16:39:37 +00:00
children . push_back ( pattern ( s . substr ( last , seps [ i ] - last ) ) ) ;
last = seps [ i ] + 1 ;
}
2022-10-10 06:43:01 +00:00
} else {
2016-07-18 16:39:37 +00:00
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 ) ) ) ;
}
}
}
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
/* End of pattern implementation */
2022-10-10 06:43:01 +00:00
template < typename C >
inline bool isEof ( C c ) {
return c = = EOFC ;
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
template < typename C >
inline bool isEoln ( C c ) {
2016-07-18 16:39:37 +00:00
return ( c = = LF | | c = = CR ) ;
}
template < typename C >
2022-10-10 06:43:01 +00:00
inline bool isBlanks ( C c ) {
2016-07-18 16:39:37 +00:00
return ( c = = LF | | c = = CR | | c = = SPACE | | c = = TAB ) ;
}
2022-10-10 06:43:01 +00:00
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 ) ;
}
enum TMode {
2016-07-18 16:39:37 +00:00
_input , _output , _answer
} ;
/* Outcomes 6-15 are reserved for future use. */
2022-10-10 06:43:01 +00:00
enum TResult {
2016-07-18 16:39:37 +00:00
_ok = 0 ,
_wa = 1 ,
_pe = 2 ,
_fail = 3 ,
_dirt = 4 ,
_points = 5 ,
_unexpected_eof = 8 ,
_partially = 16
} ;
2022-10-10 06:43:01 +00:00
enum TTestlibMode {
2016-07-18 16:39:37 +00:00
_unknown , _checker , _validator , _generator , _interactor
} ;
# define _pc(exitCode) (TResult(_partially + (exitCode)))
/* Outcomes 6-15 are reserved for future use. */
const std : : string outcomes [ ] = {
2022-10-10 06:43:01 +00:00
" accepted " ,
" wrong-answer " ,
" presentation-error " ,
" fail " ,
" fail " ,
2016-07-18 16:39:37 +00:00
# ifndef PCMS2
2022-10-10 06:43:01 +00:00
" points " ,
2016-07-18 16:39:37 +00:00
# else
2022-10-10 06:43:01 +00:00
" relative-scoring " ,
# endif
" reserved " ,
" reserved " ,
" unexpected-eof " ,
" reserved " ,
" reserved " ,
" reserved " ,
" reserved " ,
" reserved " ,
" reserved " ,
" reserved " ,
" partially-correct "
2016-07-18 16:39:37 +00:00
} ;
2022-10-10 06:43:01 +00:00
class InputStreamReader {
2016-07-18 16:39:37 +00:00
public :
2022-10-10 06:43:01 +00:00
virtual int curChar ( ) = 0 ;
virtual int nextChar ( ) = 0 ;
2016-07-18 16:39:37 +00:00
virtual void skipChar ( ) = 0 ;
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
virtual void unreadChar ( int c ) = 0 ;
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
virtual std : : string getName ( ) = 0 ;
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
virtual bool eof ( ) = 0 ;
2022-10-10 06:43:01 +00:00
virtual void close ( ) = 0 ;
virtual int getLine ( ) = 0 ;
2016-07-18 16:39:37 +00:00
virtual ~ InputStreamReader ( ) = 0 ;
} ;
2022-10-10 06:43:01 +00:00
InputStreamReader : : ~ InputStreamReader ( ) {
2016-07-18 16:39:37 +00:00
// No operations.
}
2022-10-10 06:43:01 +00:00
class StringInputStreamReader : public InputStreamReader {
2016-07-18 16:39:37 +00:00
private :
std : : string s ;
size_t pos ;
public :
2022-10-10 06:43:01 +00:00
StringInputStreamReader ( const std : : string & content ) : s ( content ) , pos ( 0 ) {
2016-07-18 16:39:37 +00:00
// No operations.
}
2022-10-10 06:43:01 +00:00
int curChar ( ) {
2016-07-18 16:39:37 +00:00
if ( pos > = s . length ( ) )
2022-10-10 06:43:01 +00:00
return EOFC ;
2016-07-18 16:39:37 +00:00
else
return s [ pos ] ;
}
2022-10-10 06:43:01 +00:00
int nextChar ( ) {
if ( pos > = s . length ( ) ) {
pos + + ;
return EOFC ;
} else
2016-07-18 16:39:37 +00:00
return s [ pos + + ] ;
}
2022-10-10 06:43:01 +00:00
void skipChar ( ) {
2016-07-18 16:39:37 +00:00
pos + + ;
}
2022-10-10 06:43:01 +00:00
void unreadChar ( int c ) {
2016-07-18 16:39:37 +00:00
if ( pos = = 0 )
__testlib_fail ( " FileFileInputStreamReader::unreadChar(int): pos == 0. " ) ;
pos - - ;
if ( pos < s . length ( ) )
s [ pos ] = char ( c ) ;
}
2022-10-10 06:43:01 +00:00
std : : string getName ( ) {
2016-07-18 16:39:37 +00:00
return __testlib_part ( s ) ;
}
2022-10-10 06:43:01 +00:00
int getLine ( ) {
return - 1 ;
}
bool eof ( ) {
2016-07-18 16:39:37 +00:00
return pos > = s . length ( ) ;
}
2022-10-10 06:43:01 +00:00
void close ( ) {
// No operations.
}
2016-07-18 16:39:37 +00:00
} ;
2022-10-10 06:43:01 +00:00
class FileInputStreamReader : public InputStreamReader {
2016-07-18 16:39:37 +00:00
private :
2022-10-10 06:43:01 +00:00
std : : FILE * file ;
2016-07-18 16:39:37 +00:00
std : : string name ;
2022-10-10 06:43:01 +00:00
int line ;
std : : vector < int > undoChars ;
inline int postprocessGetc ( int getcResult ) {
if ( getcResult ! = EOF )
return getcResult ;
else
return EOFC ;
}
int getc ( FILE * file ) {
int c ;
if ( undoChars . empty ( ) )
c = : : getc ( file ) ;
else {
c = undoChars . back ( ) ;
undoChars . pop_back ( ) ;
}
if ( c = = LF )
line + + ;
return c ;
}
int ungetc ( int c /*, FILE* file*/ ) {
if ( c = = LF )
line - - ;
undoChars . push_back ( c ) ;
return c ;
}
2016-07-18 16:39:37 +00:00
public :
2022-10-10 06:43:01 +00:00
FileInputStreamReader ( std : : FILE * file , const std : : string & name ) : file ( file ) , name ( name ) , line ( 1 ) {
2016-07-18 16:39:37 +00:00
// No operations.
}
2022-10-10 06:43:01 +00:00
int curChar ( ) {
2016-07-18 16:39:37 +00:00
if ( feof ( file ) )
2022-10-10 06:43:01 +00:00
return EOFC ;
else {
2016-07-18 16:39:37 +00:00
int c = getc ( file ) ;
2022-10-10 06:43:01 +00:00
ungetc ( c /*, file*/ ) ;
return postprocessGetc ( c ) ;
2016-07-18 16:39:37 +00:00
}
}
2022-10-10 06:43:01 +00:00
int nextChar ( ) {
2016-07-18 16:39:37 +00:00
if ( feof ( file ) )
2022-10-10 06:43:01 +00:00
return EOFC ;
2016-07-18 16:39:37 +00:00
else
2022-10-10 06:43:01 +00:00
return postprocessGetc ( getc ( file ) ) ;
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
void skipChar ( ) {
2016-07-18 16:39:37 +00:00
getc ( file ) ;
}
2022-10-10 06:43:01 +00:00
void unreadChar ( int c ) {
ungetc ( c /*, file*/ ) ;
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
std : : string getName ( ) {
2016-07-18 16:39:37 +00:00
return name ;
}
2022-10-10 06:43:01 +00:00
int getLine ( ) {
return line ;
}
bool eof ( ) {
if ( NULL = = file | | feof ( file ) )
2016-07-18 16:39:37 +00:00
return true ;
2022-10-10 06:43:01 +00:00
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 ;
2016-07-18 16:39:37 +00:00
}
}
} ;
2022-10-10 06:43:01 +00:00
class BufferedFileInputStreamReader : public InputStreamReader {
2016-07-18 16:39:37 +00:00
private :
static const size_t BUFFER_SIZE ;
2022-10-10 06:43:01 +00:00
static const size_t MAX_UNREAD_COUNT ;
2016-07-18 16:39:37 +00:00
2022-10-10 06:43:01 +00:00
std : : FILE * file ;
2016-07-18 16:39:37 +00:00
std : : string name ;
2022-10-10 06:43:01 +00:00
int line ;
2016-07-18 16:39:37 +00:00
2022-10-10 06:43:01 +00:00
char * buffer ;
bool * isEof ;
int bufferPos ;
size_t bufferSize ;
bool refill ( ) {
2016-07-18 16:39:37 +00:00
if ( NULL = = file )
__testlib_fail ( " BufferedFileInputStreamReader: file == NULL ( " + getName ( ) + " ) " ) ;
2022-10-10 06:43:01 +00:00
if ( bufferPos > = int ( bufferSize ) ) {
2016-07-18 16:39:37 +00:00
size_t readSize = fread (
2022-10-10 06:43:01 +00:00
buffer + MAX_UNREAD_COUNT ,
1 ,
BUFFER_SIZE - MAX_UNREAD_COUNT ,
file
2016-07-18 16:39:37 +00:00
) ;
if ( readSize < BUFFER_SIZE - MAX_UNREAD_COUNT
2022-10-10 06:43:01 +00:00
& & ferror ( file ) )
2016-07-18 16:39:37 +00:00
__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 ;
2022-10-10 06:43:01 +00:00
} else
2016-07-18 16:39:37 +00:00
return true ;
}
2022-10-10 06:43:01 +00:00
char increment ( ) {
char c ;
if ( ( c = buffer [ bufferPos + + ] ) = = LF )
line + + ;
return c ;
}
2016-07-18 16:39:37 +00:00
public :
2022-10-10 06:43:01 +00:00
BufferedFileInputStreamReader ( std : : FILE * file , const std : : string & name ) : file ( file ) , name ( name ) , line ( 1 ) {
2016-07-18 16:39:37 +00:00
buffer = new char [ BUFFER_SIZE ] ;
isEof = new bool [ BUFFER_SIZE ] ;
bufferSize = MAX_UNREAD_COUNT ;
bufferPos = int ( MAX_UNREAD_COUNT ) ;
}
2022-10-10 06:43:01 +00:00
~ BufferedFileInputStreamReader ( ) {
if ( NULL ! = buffer ) {
2016-07-18 16:39:37 +00:00
delete [ ] buffer ;
buffer = NULL ;
}
2022-10-10 06:43:01 +00:00
if ( NULL ! = isEof ) {
2016-07-18 16:39:37 +00:00
delete [ ] isEof ;
isEof = NULL ;
}
}
2022-10-10 06:43:01 +00:00
int curChar ( ) {
2016-07-18 16:39:37 +00:00
if ( ! refill ( ) )
2022-10-10 06:43:01 +00:00
return EOFC ;
2016-07-18 16:39:37 +00:00
2022-10-10 06:43:01 +00:00
return isEof [ bufferPos ] ? EOFC : buffer [ bufferPos ] ;
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
int nextChar ( ) {
2016-07-18 16:39:37 +00:00
if ( ! refill ( ) )
2022-10-10 06:43:01 +00:00
return EOFC ;
2016-07-18 16:39:37 +00:00
2022-10-10 06:43:01 +00:00
return isEof [ bufferPos ] ? EOFC : increment ( ) ;
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
void skipChar ( ) {
increment ( ) ;
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
void unreadChar ( int c ) {
2016-07-18 16:39:37 +00:00
bufferPos - - ;
if ( bufferPos < 0 )
__testlib_fail ( " BufferedFileInputStreamReader::unreadChar(int): bufferPos < 0 " ) ;
2022-10-10 06:43:01 +00:00
isEof [ bufferPos ] = ( c = = EOFC ) ;
buffer [ bufferPos ] = char ( c ) ;
if ( c = = LF )
line - - ;
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
std : : string getName ( ) {
2016-07-18 16:39:37 +00:00
return name ;
}
2022-10-10 06:43:01 +00:00
int getLine ( ) {
return line ;
}
bool eof ( ) {
return ! refill ( ) | | EOFC = = curChar ( ) ;
}
void close ( ) {
if ( NULL ! = file ) {
fclose ( file ) ;
file = NULL ;
}
2016-07-18 16:39:37 +00:00
}
} ;
2022-10-10 06:43:01 +00:00
const size_t BufferedFileInputStreamReader : : BUFFER_SIZE = 2000000 ;
const size_t BufferedFileInputStreamReader : : MAX_UNREAD_COUNT = BufferedFileInputStreamReader : : BUFFER_SIZE / 2 ;
2016-07-18 16:39:37 +00:00
/*
* Streams to be used for reading data in checkers or validators .
* Each read * ( ) method moves pointer to the next character after the
* read value .
*/
2022-10-10 06:43:01 +00:00
struct InStream {
2016-07-18 16:39:37 +00:00
/* Do not use them. */
InStream ( ) ;
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
~ InStream ( ) ;
/* Wrap std::string with InStream. */
2022-10-10 06:43:01 +00:00
InStream ( const InStream & baseStream , std : : string content ) ;
2016-07-18 16:39:37 +00:00
2022-10-10 06:43:01 +00:00
InputStreamReader * reader ;
int lastLine ;
2016-07-18 16:39:37 +00:00
std : : string name ;
TMode mode ;
bool opened ;
bool stdfile ;
bool strict ;
int wordReserveSize ;
std : : string _tmpReadToken ;
2022-10-10 06:43:01 +00:00
int readManyIteration ;
size_t maxFileSize ;
size_t maxTokenLength ;
size_t maxMessageLength ;
2016-07-18 16:39:37 +00:00
void init ( std : : string fileName , TMode mode ) ;
2022-10-10 06:43:01 +00:00
void init ( std : : FILE * f , TMode mode ) ;
/* Moves stream pointer to the first non-white-space character or EOF. */
2016-07-18 16:39:37 +00:00
void skipBlanks ( ) ;
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
/* Returns current character in the stream. Doesn't remove it from stream. */
char curChar ( ) ;
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
/* Moves stream pointer one character forward. */
void skipChar ( ) ;
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
/* Returns current character and moves pointer one character forward. */
char nextChar ( ) ;
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
/* Returns current character and moves pointer one character forward. */
char readChar ( ) ;
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
/* As "readChar()" but ensures that the result is equal to given parameter. */
char readChar ( char c ) ;
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
/* As "readChar()" but ensures that the result is equal to the space (code=32). */
char readSpace ( ) ;
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
/* Puts back the character into the stream. */
void unreadChar ( char c ) ;
/* Reopens stream, you should not use it. */
2022-10-10 06:43:01 +00:00
void reset ( std : : FILE * file = NULL ) ;
2016-07-18 16:39:37 +00:00
/* Checks that current position is EOF. If not it doesn't move stream pointer. */
bool eof ( ) ;
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
/* 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 ( ) ;
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
/* 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 ( ) ;
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
/* The same as "readWord()", it is preffered to use "readToken()". */
std : : string readToken ( ) ;
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
/* The same as "readWord()", but ensures that token matches to given pattern. */
2022-10-10 06:43:01 +00:00
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 ) ;
std : : vector < std : : string > readWords ( int size , int indexBase = 1 ) ;
2016-07-18 16:39:37 +00:00
/* The same as "readToken()", but ensures that token matches to given pattern. */
2022-10-10 06:43:01 +00:00
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 ) ;
2016-07-18 16:39:37 +00:00
2022-10-10 06:43:01 +00:00
std : : vector < std : : string > readTokens ( int size , int indexBase = 1 ) ;
2016-07-18 16:39:37 +00:00
2022-10-10 06:43:01 +00:00
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 = " " ) ;
2016-07-18 16:39:37 +00:00
/*
* Reads new long long value . Ignores white - spaces into the non - strict mode
* ( strict mode is used in validators usually ) .
*/
long long readLong ( ) ;
2022-10-10 06:43:01 +00:00
unsigned long long readUnsignedLong ( ) ;
/*
2016-07-18 16:39:37 +00:00
* Reads new int . Ignores white - spaces into the non - strict mode
* ( strict mode is used in validators usually ) .
*/
int readInteger ( ) ;
2022-10-10 06:43:01 +00:00
/*
2016-07-18 16:39:37 +00:00
* 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]. */
2022-10-10 06:43:01 +00:00
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 ) ;
/* Reads space-separated sequence of long longs. */
std : : vector < long long > readLongs ( int size , 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 ) ;
std : : vector < unsigned long long > readUnsignedLongs ( int size , 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 ) ;
2016-07-18 16:39:37 +00:00
/* As "readInteger()" but ensures that value in the range [minv,maxv]. */
2022-10-10 06:43:01 +00:00
int readInteger ( int minv , int maxv , const std : : string & variableName = " " ) ;
2016-07-18 16:39:37 +00:00
/* As "readInt()" but ensures that value in the range [minv,maxv]. */
2022-10-10 06:43:01 +00:00
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 > readIntegers ( int size , 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 space-separated sequence of integers. */
std : : vector < int > readInts ( int size , int indexBase = 1 ) ;
2016-07-18 16:39:37 +00:00
/*
* Reads new double . Ignores white - spaces into the non - strict mode
* ( strict mode is used in validators usually ) .
*/
double readReal ( ) ;
2022-10-10 06:43:01 +00:00
/*
2016-07-18 16:39:37 +00:00
* Reads new double . Ignores white - spaces into the non - strict mode
* ( strict mode is used in validators usually ) .
*/
double readDouble ( ) ;
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
/* As "readReal()" but ensures that value in the range [minv,maxv]. */
2022-10-10 06:43:01 +00:00
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 ) ;
std : : vector < double > readReals ( int size , int indexBase = 1 ) ;
2016-07-18 16:39:37 +00:00
/* As "readDouble()" but ensures that value in the range [minv,maxv]. */
2022-10-10 06:43:01 +00:00
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 ) ;
std : : vector < double > readDoubles ( int size , int indexBase = 1 ) ;
2016-07-18 16:39:37 +00:00
/*
* 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 ,
2022-10-10 06:43:01 +00:00
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 ) ;
2016-07-18 16:39:37 +00:00
/*
* 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 ,
2022-10-10 06:43:01 +00:00
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 ) ;
2016-07-18 16:39:37 +00:00
/* As readLine(). */
std : : string readString ( ) ;
2022-10-10 06:43:01 +00:00
/* Read many lines. */
std : : vector < std : : string > readStrings ( int size , int indexBase = 1 ) ;
2016-07-18 16:39:37 +00:00
/* See readLine(). */
2022-10-10 06:43:01 +00:00
void readStringTo ( std : : string & result ) ;
2016-07-18 16:39:37 +00:00
/* The same as "readLine()/readString()", but ensures that line matches to the given pattern. */
2022-10-10 06:43:01 +00:00
std : : string readString ( const pattern & p , const std : : string & variableName = " " ) ;
2016-07-18 16:39:37 +00:00
/* The same as "readLine()/readString()", but ensures that line matches to the given pattern. */
2022-10-10 06:43:01 +00:00
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 ) ;
2016-07-18 16:39:37 +00:00
/* The same as "readLine()/readString()", but ensures that line matches to the given pattern. */
2022-10-10 06:43:01 +00:00
void readStringTo ( std : : string & result , const pattern & p , const std : : string & variableName = " " ) ;
2016-07-18 16:39:37 +00:00
/* The same as "readLine()/readString()", but ensures that line matches to the given pattern. */
2022-10-10 06:43:01 +00:00
void readStringTo ( std : : string & result , const std : : string & ptrn , const std : : string & variableName = " " ) ;
2016-07-18 16:39:37 +00:00
/*
* 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 ( ) ;
2022-10-10 06:43:01 +00:00
/* Read many lines. */
std : : vector < std : : string > readLines ( int size , int indexBase = 1 ) ;
2016-07-18 16:39:37 +00:00
/* See readLine(). */
2022-10-10 06:43:01 +00:00
void readLineTo ( std : : string & result ) ;
2016-07-18 16:39:37 +00:00
/* The same as "readLine()", but ensures that line matches to the given pattern. */
2022-10-10 06:43:01 +00:00
std : : string readLine ( const pattern & p , const std : : string & variableName = " " ) ;
2016-07-18 16:39:37 +00:00
/* The same as "readLine()", but ensures that line matches to the given pattern. */
2022-10-10 06:43:01 +00:00
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 ) ;
2016-07-18 16:39:37 +00:00
/* The same as "readLine()", but ensures that line matches to the given pattern. */
2022-10-10 06:43:01 +00:00
void readLineTo ( std : : string & result , const pattern & p , const std : : string & variableName = " " ) ;
2016-07-18 16:39:37 +00:00
/* The same as "readLine()", but ensures that line matches to the given pattern. */
2022-10-10 06:43:01 +00:00
void readLineTo ( std : : string & result , const std : : string & ptrn , const std : : string & variableName = " " ) ;
2016-07-18 16:39:37 +00:00
/* Reads EOLN or fails. Use it in validators. Calls "eoln()" method internally. */
void readEoln ( ) ;
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
/* 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 .
*/
2022-10-10 06:43:01 +00:00
NORETURN void quit ( TResult result , const char * msg ) ;
2016-07-18 16:39:37 +00:00
/*
* Quit - functions aborts program with < result > and < message > :
* input / answer streams replace any result to FAIL .
*/
2022-10-10 06:43:01 +00:00
NORETURN void quitf ( TResult result , const char * msg , . . . ) ;
/*
* Quit - functions aborts program with < result > and < message > :
* input / answer streams replace any result to FAIL .
*/
void quitif ( bool condition , TResult result , const char * msg , . . . ) ;
2016-07-18 16:39:37 +00:00
/*
* Quit - functions aborts program with < result > and < message > :
* input / answer streams replace any result to FAIL .
*/
NORETURN void quits ( TResult result , std : : string msg ) ;
2022-10-10 06:43:01 +00:00
/*
* Checks condition and aborts a program if codition is false .
* Returns _wa for ouf and _fail on any other streams .
*/
# ifdef __GNUC__
__attribute__ ( ( format ( printf , 3 , 4 ) ) )
# endif
void ensuref ( bool cond , const char * format , . . . ) ;
void __testlib_ensure ( bool cond , std : : string message ) ;
2016-07-18 16:39:37 +00:00
void close ( ) ;
2022-10-10 06:43:01 +00:00
const static int NO_INDEX = INT_MAX ;
const static char OPEN_BRACKET = char ( 11 ) ;
const static char CLOSE_BRACKET = char ( 17 ) ;
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 ;
2016-07-18 16:39:37 +00:00
static void textColor ( WORD color ) ;
2022-10-10 06:43:01 +00:00
static void quitscr ( WORD color , const char * msg ) ;
2016-07-18 16:39:37 +00:00
static void quitscrS ( WORD color , std : : string msg ) ;
2022-10-10 06:43:01 +00:00
void xmlSafeWrite ( std : : FILE * file , const char * msg ) ;
2016-07-18 16:39:37 +00:00
private :
2022-10-10 06:43:01 +00:00
InStream ( const InStream & ) ;
InStream & operator = ( const InStream & ) ;
2016-07-18 16:39:37 +00:00
} ;
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 ( ) ;
2022-10-10 06:43:01 +00:00
struct ValidatorBoundsHit {
static const double EPS ;
bool minHit ;
bool maxHit ;
2016-07-18 16:39:37 +00:00
2022-10-10 06:43:01 +00:00
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 )
) ;
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
} ;
2016-07-18 16:39:37 +00:00
2022-10-10 06:43:01 +00:00
const double ValidatorBoundsHit : : EPS = 1E-12 ;
2016-07-18 16:39:37 +00:00
2022-10-10 06:43:01 +00:00
class Validator {
private :
bool _initialized ;
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 ;
}
2016-07-18 16:39:37 +00:00
2022-10-10 06:43:01 +00:00
bool isFeatureNameAnalyzable ( const std : : string & featureName ) {
for ( size_t i = 0 ; i < featureName . length ( ) ; i + + )
if ( featureName [ i ] < ' ' )
return false ;
return true ;
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
public :
Validator ( ) : _initialized ( false ) , _testset ( " tests " ) , _group ( ) {
}
2016-07-18 16:39:37 +00:00
2022-10-10 06:43:01 +00:00
void initialize ( ) {
_initialized = true ;
}
std : : string testset ( ) const {
if ( ! _initialized )
__testlib_fail ( " Validator should be initialized with registerValidation(argc, argv) instead of registerValidation() to support validator.testset() " ) ;
return _testset ;
}
std : : string group ( ) const {
if ( ! _initialized )
__testlib_fail ( " Validator should be initialized with registerValidation(argc, argv) instead of registerValidation() to support validator.group() " ) ;
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 .
2016-07-18 16:39:37 +00:00
*/
2022-10-10 06:43:01 +00:00
void disableFinalizeGuard ( ) {
2016-07-18 16:39:37 +00:00
TestlibFinalizeGuard : : alive = false ;
}
/* Interactor streams.
*/
std : : fstream tout ;
/* implementation
*/
2022-10-10 06:43:01 +00:00
# if __cplusplus > 199711L || defined(_MSC_VER)
template < typename T >
static std : : string vtos ( const T & t , std : : true_type ) {
if ( t = = 0 )
return " 0 " ;
else {
T n ( t ) ;
bool negative = n < 0 ;
std : : string s ;
while ( n ! = 0 ) {
T digit = n % 10 ;
if ( digit < 0 )
digit = - digit ;
s + = char ( ' 0 ' + digit ) ;
n / = 10 ;
}
std : : reverse ( s . begin ( ) , s . end ( ) ) ;
return negative ? " - " + s : s ;
}
}
template < typename T >
static std : : string vtos ( const T & t , std : : false_type ) {
std : : string s ;
static std : : stringstream ss ;
ss . str ( std : : string ( ) ) ;
ss . clear ( ) ;
ss < < t ;
ss > > s ;
return s ;
}
template < typename T >
static std : : string vtos ( const T & t ) {
return vtos ( t , std : : is_integral < T > ( ) ) ;
}
/* signed case. */
template < typename T >
static std : : string toHumanReadableString ( const T & n , std : : false_type ) {
if ( n = = 0 )
return vtos ( n ) ;
int trailingZeroCount = 0 ;
T n_ = n ;
while ( n_ % 10 = = 0 )
n_ / = 10 , trailingZeroCount + + ;
if ( trailingZeroCount > = 7 ) {
if ( n_ = = 1 )
return " 10^ " + vtos ( trailingZeroCount ) ;
else if ( n_ = = - 1 )
return " -10^ " + vtos ( trailingZeroCount ) ;
else
return vtos ( n_ ) + " *10^ " + vtos ( trailingZeroCount ) ;
} else
return vtos ( n ) ;
}
/* unsigned case. */
template < typename T >
static std : : string toHumanReadableString ( const T & n , std : : true_type ) {
if ( n = = 0 )
return vtos ( n ) ;
int trailingZeroCount = 0 ;
T n_ = n ;
while ( n_ % 10 = = 0 )
n_ / = 10 , trailingZeroCount + + ;
if ( trailingZeroCount > = 7 ) {
if ( n_ = = 1 )
return " 10^ " + vtos ( trailingZeroCount ) ;
else
return vtos ( n_ ) + " *10^ " + vtos ( trailingZeroCount ) ;
} else
return vtos ( n ) ;
}
template < typename T >
static std : : string toHumanReadableString ( const T & n ) {
return toHumanReadableString ( n , std : : is_unsigned < T > ( ) ) ;
}
# else
template < typename T >
2016-07-18 16:39:37 +00:00
static std : : string vtos ( const T & t )
{
std : : string s ;
2022-10-10 06:43:01 +00:00
static std : : stringstream ss ;
ss . str ( std : : string ( ) ) ;
ss . clear ( ) ;
2016-07-18 16:39:37 +00:00
ss < < t ;
ss > > s ;
return s ;
}
2022-10-10 06:43:01 +00:00
template < typename T >
static std : : string toHumanReadableString ( const T & n ) {
return vtos ( n ) ;
}
# endif
template < typename T >
static std : : string toString ( const T & t ) {
2016-07-18 16:39:37 +00:00
return vtos ( t ) ;
}
2022-10-10 06:43:01 +00:00
InStream : : InStream ( ) {
reader = NULL ;
lastLine = - 1 ;
opened = false ;
2016-07-18 16:39:37 +00:00
name = " " ;
mode = _input ;
strict = false ;
stdfile = false ;
wordReserveSize = 4 ;
2022-10-10 06:43:01 +00:00
readManyIteration = NO_INDEX ;
maxFileSize = 128 * 1024 * 1024 ; // 128MB.
maxTokenLength = 32 * 1024 * 1024 ; // 32MB.
maxMessageLength = 32000 ;
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
InStream : : InStream ( const InStream & baseStream , std : : string content ) {
2016-07-18 16:39:37 +00:00
reader = new StringInputStreamReader ( content ) ;
2022-10-10 06:43:01 +00:00
lastLine = - 1 ;
2016-07-18 16:39:37 +00:00
opened = true ;
strict = baseStream . strict ;
2022-10-10 06:43:01 +00:00
stdfile = false ;
2016-07-18 16:39:37 +00:00
mode = baseStream . mode ;
name = " based on " + baseStream . name ;
2022-10-10 06:43:01 +00:00
readManyIteration = NO_INDEX ;
maxFileSize = 128 * 1024 * 1024 ; // 128MB.
maxTokenLength = 32 * 1024 * 1024 ; // 32MB.
maxMessageLength = 32000 ;
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
InStream : : ~ InStream ( ) {
if ( NULL ! = reader ) {
reader - > close ( ) ;
2016-07-18 16:39:37 +00:00
delete reader ;
reader = NULL ;
}
}
# ifdef __GNUC__
__attribute__ ( ( const ) )
# endif
2022-10-10 06:43:01 +00:00
int resultExitCode ( TResult r ) {
2016-07-18 16:39:37 +00:00
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 ;
}
2022-10-10 06:43:01 +00:00
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)
2016-07-18 16:39:37 +00:00
HANDLE handle = GetStdHandle ( STD_OUTPUT_HANDLE ) ;
SetConsoleTextAttribute ( handle , color ) ;
# endif
2022-10-10 06:43:01 +00:00
# if !defined(ON_WINDOWS) && defined(__GNUC__)
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
}
2016-07-18 16:39:37 +00:00
2022-10-10 06:43:01 +00:00
NORETURN void halt ( int exitCode ) {
2016-07-18 16:39:37 +00:00
# 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 ) ;
}
2022-10-10 06:43:01 +00:00
static bool __testlib_shouldCheckDirt ( TResult result ) {
return result = = _ok | | result = = _points | | result > = _partially ;
}
static std : : string __testlib_appendMessage ( const std : : string & message , const std : : string & extra ) {
int openPos = - 1 , closePos = - 1 ;
for ( size_t i = 0 ; i < message . length ( ) ; i + + ) {
if ( message [ i ] = = InStream : : OPEN_BRACKET ) {
if ( openPos = = - 1 )
openPos = int ( i ) ;
else
openPos = INT_MAX ;
}
if ( message [ i ] = = InStream : : CLOSE_BRACKET ) {
if ( closePos = = - 1 )
closePos = int ( i ) ;
else
closePos = INT_MAX ;
}
}
if ( openPos ! = - 1 & & openPos ! = INT_MAX
& & closePos ! = - 1 & & closePos ! = INT_MAX
& & openPos < closePos ) {
size_t index = message . find ( extra , openPos ) ;
if ( index = = std : : string : : npos | | int ( index ) > = closePos ) {
std : : string result ( message ) ;
result . insert ( closePos , " , " + extra ) ;
return result ;
}
return message ;
}
return message + " " + InStream : : OPEN_BRACKET + extra + InStream : : CLOSE_BRACKET ;
}
static std : : string __testlib_toPrintableMessage ( const std : : string & message ) {
int openPos = - 1 , closePos = - 1 ;
for ( size_t i = 0 ; i < message . length ( ) ; i + + ) {
if ( message [ i ] = = InStream : : OPEN_BRACKET ) {
if ( openPos = = - 1 )
openPos = int ( i ) ;
else
openPos = INT_MAX ;
}
if ( message [ i ] = = InStream : : CLOSE_BRACKET ) {
if ( closePos = = - 1 )
closePos = int ( i ) ;
else
closePos = INT_MAX ;
}
}
if ( openPos ! = - 1 & & openPos ! = INT_MAX
& & closePos ! = - 1 & & closePos ! = INT_MAX
& & openPos < closePos ) {
std : : string result ( message ) ;
result [ openPos ] = ' ( ' ;
result [ closePos ] = ' ) ' ;
return result ;
}
return message ;
}
NORETURN void InStream : : quit ( TResult result , const char * msg ) {
2016-07-18 16:39:37 +00:00
if ( TestlibFinalizeGuard : : alive )
testlibFinalizeGuard . quitCount + + ;
2022-10-10 06:43:01 +00:00
std : : string message ( msg ) ;
message = trim ( message ) ;
if ( __testlib_hasTestCase ) {
if ( result ! = _ok )
message = __testlib_appendMessage ( message , " test case " + vtos ( __testlib_testCase ) ) ;
else {
if ( __testlib_testCase = = 1 )
message = __testlib_appendMessage ( message , vtos ( __testlib_testCase ) + " test case " ) ;
else
message = __testlib_appendMessage ( message , vtos ( __testlib_testCase ) + " test cases " ) ;
}
}
// You can change maxMessageLength.
// Example: 'inf.maxMessageLength = 1024 * 1024;'.
if ( message . length ( ) > maxMessageLength ) {
std : : string warn = " message length exceeds " + vtos ( maxMessageLength )
+ " , the message is truncated: " ;
message = warn + message . substr ( 0 , maxMessageLength - warn . length ( ) ) ;
}
# ifndef ENABLE_UNEXPECTED_EOF
if ( result = = _unexpected_eof )
result = _pe ;
# endif
if ( mode ! = _output & & result ! = _fail ) {
if ( mode = = _input & & testlibMode = = _validator & & lastLine ! = - 1 )
quits ( _fail , __testlib_appendMessage ( __testlib_appendMessage ( message , name ) , " line " + vtos ( lastLine ) ) ) ;
else
quits ( _fail , __testlib_appendMessage ( message , name ) ) ;
}
2016-07-18 16:39:37 +00:00
2022-10-10 06:43:01 +00:00
std : : FILE * resultFile ;
2016-07-18 16:39:37 +00:00
std : : string errorName ;
2022-10-10 06:43:01 +00:00
if ( __testlib_shouldCheckDirt ( result ) ) {
2016-07-18 16:39:37 +00:00
if ( testlibMode ! = _interactor & & ! ouf . seekEof ( ) )
quit ( _dirt , " Extra information in the output file " ) ;
}
int pctype = result - _partially ;
bool isPartial = false ;
2022-10-10 06:43:01 +00:00
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 " ;
2016-07-18 16:39:37 +00:00
quitscrS ( LightYellow , errorName ) ;
2022-10-10 06:43:01 +00:00
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 ??? " ) ;
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
if ( resultName ! = " " ) {
resultFile = std : : fopen ( resultName . c_str ( ) , " w " ) ;
if ( resultFile = = NULL ) {
resultName = " " ;
2016-07-18 16:39:37 +00:00
quit ( _fail , " Can not write to the result file " ) ;
2022-10-10 06:43:01 +00:00
}
if ( appesMode ) {
2016-07-18 16:39:37 +00:00
std : : fprintf ( resultFile , " <?xml version= \" 1.0 \" encoding= \" windows-1251 \" ?> " ) ;
if ( isPartial )
2022-10-10 06:43:01 +00:00
std : : fprintf ( resultFile , " <result outcome = \" %s \" pctype = \" %d \" > " ,
outcomes [ ( int ) _partially ] . c_str ( ) , pctype ) ;
else {
2016-07-18 16:39:37 +00:00
if ( result ! = _points )
2022-10-10 06:43:01 +00:00
std : : fprintf ( resultFile , " <result outcome = \" %s \" > " , outcomes [ ( int ) result ] . c_str ( ) ) ;
else {
2016-07-18 16:39:37 +00:00
if ( __testlib_points = = std : : numeric_limits < float > : : infinity ( ) )
quit ( _fail , " Expected points, but infinity found " ) ;
std : : string stringPoints = removeDoubleTrailingZeroes ( format ( " %.10f " , __testlib_points ) ) ;
2022-10-10 06:43:01 +00:00
std : : fprintf ( resultFile , " <result outcome = \" %s \" points = \" %s \" > " ,
outcomes [ ( int ) result ] . c_str ( ) , stringPoints . c_str ( ) ) ;
2016-07-18 16:39:37 +00:00
}
}
2022-10-10 06:43:01 +00:00
xmlSafeWrite ( resultFile , __testlib_toPrintableMessage ( message ) . c_str ( ) ) ;
2016-07-18 16:39:37 +00:00
std : : fprintf ( resultFile , " </result> \n " ) ;
2022-10-10 06:43:01 +00:00
} else
std : : fprintf ( resultFile , " %s " , __testlib_toPrintableMessage ( message ) . c_str ( ) ) ;
if ( NULL = = resultFile | | fclose ( resultFile ) ! = 0 ) {
resultName = " " ;
2016-07-18 16:39:37 +00:00
quit ( _fail , " Can not write to the result file " ) ;
2022-10-10 06:43:01 +00:00
}
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
quitscr ( LightGray , __testlib_toPrintableMessage ( message ) . c_str ( ) ) ;
2016-07-18 16:39:37 +00:00
std : : fprintf ( stderr , " \n " ) ;
2022-10-10 06:43:01 +00:00
inf . close ( ) ;
ouf . close ( ) ;
ans . close ( ) ;
2016-07-18 16:39:37 +00:00
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__
2022-10-10 06:43:01 +00:00
__attribute__ ( ( format ( printf , 3 , 4 ) ) )
2016-07-18 16:39:37 +00:00
# endif
2022-10-10 06:43:01 +00:00
NORETURN void InStream : : quitf ( TResult result , const char * msg , . . . ) {
2016-07-18 16:39:37 +00:00
FMT_TO_RESULT ( msg , msg , message ) ;
InStream : : quit ( result , message . c_str ( ) ) ;
}
2022-10-10 06:43:01 +00:00
# ifdef __GNUC__
__attribute__ ( ( format ( printf , 4 , 5 ) ) )
# endif
void InStream : : quitif ( bool condition , TResult result , const char * msg , . . . ) {
if ( condition ) {
FMT_TO_RESULT ( msg , msg , message ) ;
InStream : : quit ( result , message . c_str ( ) ) ;
}
}
NORETURN void InStream : : quits ( TResult result , std : : string msg ) {
2016-07-18 16:39:37 +00:00
InStream : : quit ( result , msg . c_str ( ) ) ;
}
2022-10-10 06:43:01 +00:00
void InStream : : xmlSafeWrite ( std : : FILE * file , const char * msg ) {
2016-07-18 16:39:37 +00:00
size_t lmsg = strlen ( msg ) ;
2022-10-10 06:43:01 +00:00
for ( size_t i = 0 ; i < lmsg ; i + + ) {
if ( msg [ i ] = = ' & ' ) {
2016-07-18 16:39:37 +00:00
std : : fprintf ( file , " %s " , " & " ) ;
continue ;
}
2022-10-10 06:43:01 +00:00
if ( msg [ i ] = = ' < ' ) {
2016-07-18 16:39:37 +00:00
std : : fprintf ( file , " %s " , " < " ) ;
continue ;
}
2022-10-10 06:43:01 +00:00
if ( msg [ i ] = = ' > ' ) {
2016-07-18 16:39:37 +00:00
std : : fprintf ( file , " %s " , " > " ) ;
continue ;
}
2022-10-10 06:43:01 +00:00
if ( msg [ i ] = = ' " ' ) {
2016-07-18 16:39:37 +00:00
std : : fprintf ( file , " %s " , " " " ) ;
continue ;
}
2022-10-10 06:43:01 +00:00
if ( 0 < = msg [ i ] & & msg [ i ] < = 31 ) {
2016-07-18 16:39:37 +00:00
std : : fprintf ( file , " %c " , ' . ' ) ;
continue ;
}
std : : fprintf ( file , " %c " , msg [ i ] ) ;
}
}
2022-10-10 06:43:01 +00:00
void InStream : : quitscrS ( WORD color , std : : string msg ) {
2016-07-18 16:39:37 +00:00
quitscr ( color , msg . c_str ( ) ) ;
}
2022-10-10 06:43:01 +00:00
void InStream : : quitscr ( WORD color , const char * msg ) {
if ( resultName = = " " ) {
2016-07-18 16:39:37 +00:00
textColor ( color ) ;
std : : fprintf ( stderr , " %s " , msg ) ;
textColor ( LightGray ) ;
}
}
2022-10-10 06:43:01 +00:00
void InStream : : reset ( std : : FILE * file ) {
2016-07-18 16:39:37 +00:00
if ( opened & & stdfile )
quit ( _fail , " Can't reset standard handle " ) ;
if ( opened )
close ( ) ;
2022-10-10 06:43:01 +00:00
if ( ! stdfile & & NULL = = file )
if ( NULL = = ( file = std : : fopen ( name . c_str ( ) , " rb " ) ) ) {
2016-07-18 16:39:37 +00:00
if ( mode = = _output )
2022-10-10 06:43:01 +00:00
quits ( _pe , std : : string ( " Output file not found: \" " ) + name + " \" " ) ;
2016-07-18 16:39:37 +00:00
2022-10-10 06:43:01 +00:00
if ( mode = = _answer )
quits ( _fail , std : : string ( " Answer file not found: \" " ) + name + " \" " ) ;
}
2016-07-18 16:39:37 +00:00
2022-10-10 06:43:01 +00:00
if ( NULL ! = file ) {
opened = true ;
__testlib_set_binary ( file ) ;
2016-07-18 16:39:37 +00:00
2022-10-10 06:43:01 +00:00
if ( stdfile )
reader = new FileInputStreamReader ( file , name ) ;
else
reader = new BufferedFileInputStreamReader ( file , name ) ;
} else {
opened = false ;
reader = NULL ;
}
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
void InStream : : init ( std : : string fileName , TMode mode ) {
2016-07-18 16:39:37 +00:00
opened = false ;
2022-10-10 06:43:01 +00:00
name = fileName ;
stdfile = false ;
2016-07-18 16:39:37 +00:00
this - > mode = mode ;
2022-10-10 06:43:01 +00:00
std : : ifstream stream ;
stream . open ( fileName . c_str ( ) , std : : ios : : in ) ;
if ( stream . is_open ( ) ) {
std : : streampos start = stream . tellg ( ) ;
stream . seekg ( 0 , std : : ios : : end ) ;
std : : streampos end = stream . tellg ( ) ;
size_t fileSize = size_t ( end - start ) ;
stream . close ( ) ;
// You can change maxFileSize.
// Example: 'inf.maxFileSize = 256 * 1024 * 1024;'.
if ( fileSize > maxFileSize )
quitf ( _pe , " File size exceeds %d bytes, size is %d " , int ( maxFileSize ) , int ( fileSize ) ) ;
}
2016-07-18 16:39:37 +00:00
reset ( ) ;
}
2022-10-10 06:43:01 +00:00
void InStream : : init ( std : : FILE * f , TMode mode ) {
2016-07-18 16:39:37 +00:00
opened = false ;
name = " untitled " ;
2022-10-10 06:43:01 +00:00
this - > mode = mode ;
2016-07-18 16:39:37 +00:00
if ( f = = stdin )
name = " stdin " , stdfile = true ;
if ( f = = stdout )
name = " stdout " , stdfile = true ;
if ( f = = stderr )
name = " stderr " , stdfile = true ;
2022-10-10 06:43:01 +00:00
reset ( f ) ;
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
char InStream : : curChar ( ) {
return char ( reader - > curChar ( ) ) ;
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
char InStream : : nextChar ( ) {
return char ( reader - > nextChar ( ) ) ;
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
char InStream : : readChar ( ) {
2016-07-18 16:39:37 +00:00
return nextChar ( ) ;
}
2022-10-10 06:43:01 +00:00
char InStream : : readChar ( char c ) {
lastLine = reader - > getLine ( ) ;
2016-07-18 16:39:37 +00:00
char found = readChar ( ) ;
2022-10-10 06:43:01 +00:00
if ( c ! = found ) {
2016-07-18 16:39:37 +00:00
if ( ! isEoln ( found ) )
2022-10-10 06:43:01 +00:00
quit ( _pe , ( " Unexpected character ' " + std : : string ( 1 , found ) + " ', but ' " + std : : string ( 1 , c ) +
" ' expected " ) . c_str ( ) ) ;
2016-07-18 16:39:37 +00:00
else
2022-10-10 06:43:01 +00:00
quit ( _pe , ( " Unexpected character " + ( " # " + vtos ( int ( found ) ) ) + " , but ' " + std : : string ( 1 , c ) +
" ' expected " ) . c_str ( ) ) ;
2016-07-18 16:39:37 +00:00
}
return found ;
}
2022-10-10 06:43:01 +00:00
char InStream : : readSpace ( ) {
2016-07-18 16:39:37 +00:00
return readChar ( ' ' ) ;
}
2022-10-10 06:43:01 +00:00
void InStream : : unreadChar ( char c ) {
2016-07-18 16:39:37 +00:00
reader - > unreadChar ( c ) ;
}
2022-10-10 06:43:01 +00:00
void InStream : : skipChar ( ) {
2016-07-18 16:39:37 +00:00
reader - > skipChar ( ) ;
}
2022-10-10 06:43:01 +00:00
void InStream : : skipBlanks ( ) {
2016-07-18 16:39:37 +00:00
while ( isBlanks ( reader - > curChar ( ) ) )
reader - > skipChar ( ) ;
}
2022-10-10 06:43:01 +00:00
std : : string InStream : : readWord ( ) {
2016-07-18 16:39:37 +00:00
readWordTo ( _tmpReadToken ) ;
return _tmpReadToken ;
}
2022-10-10 06:43:01 +00:00
void InStream : : readWordTo ( std : : string & result ) {
2016-07-18 16:39:37 +00:00
if ( ! strict )
skipBlanks ( ) ;
2022-10-10 06:43:01 +00:00
lastLine = reader - > getLine ( ) ;
2016-07-18 16:39:37 +00:00
int cur = reader - > nextChar ( ) ;
2022-10-10 06:43:01 +00:00
if ( cur = = EOFC )
2016-07-18 16:39:37 +00:00
quit ( _unexpected_eof , " Unexpected end of file - token expected " ) ;
if ( isBlanks ( cur ) )
quit ( _pe , " Unexpected white-space - token expected " ) ;
result . clear ( ) ;
2022-10-10 06:43:01 +00:00
while ( ! ( isBlanks ( cur ) | | cur = = EOFC ) ) {
2016-07-18 16:39:37 +00:00
result + = char ( cur ) ;
2022-10-10 06:43:01 +00:00
// You can change maxTokenLength.
// Example: 'inf.maxTokenLength = 128 * 1024 * 1024;'.
if ( result . length ( ) > maxTokenLength )
quitf ( _pe , " Length of token exceeds %d, token is '%s...' " , int ( maxTokenLength ) ,
__testlib_part ( result ) . c_str ( ) ) ;
2016-07-18 16:39:37 +00:00
cur = reader - > nextChar ( ) ;
}
reader - > unreadChar ( cur ) ;
if ( result . length ( ) = = 0 )
quit ( _unexpected_eof , " Unexpected end of file or white-space - token expected " ) ;
}
2022-10-10 06:43:01 +00:00
std : : string InStream : : readToken ( ) {
2016-07-18 16:39:37 +00:00
return readWord ( ) ;
}
2022-10-10 06:43:01 +00:00
void InStream : : readTokenTo ( std : : string & result ) {
2016-07-18 16:39:37 +00:00
readWordTo ( result ) ;
}
2022-10-10 06:43:01 +00:00
static std : : string __testlib_part ( const std : : string & s ) {
std : : string t ;
for ( size_t i = 0 ; i < s . length ( ) ; i + + )
if ( s [ i ] ! = ' \0 ' )
t + = s [ i ] ;
else
t + = ' ~ ' ;
if ( t . length ( ) < = 64 )
return t ;
2016-07-18 16:39:37 +00:00
else
2022-10-10 06:43:01 +00:00
return t . substr ( 0 , 30 ) + " ... " + t . 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 ( strict & & space & & i + 1 < size ) \
readSpace ( ) ; \
} \
\
readManyIteration = NO_INDEX ; \
return result ; \
std : : string InStream : : readWord ( const pattern & p , const std : : string & variableName ) {
2016-07-18 16:39:37 +00:00
readWordTo ( _tmpReadToken ) ;
2022-10-10 06:43:01 +00:00
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 ( ) ) ;
}
2016-07-18 16:39:37 +00:00
}
return _tmpReadToken ;
}
2022-10-10 06:43:01 +00:00
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 ) ;
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
std : : vector < std : : string > InStream : : readWords ( int size , int indexBase ) {
__testlib_readMany ( readWords , readWord ( ) , std : : string , true ) ;
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
std : : string InStream : : readWord ( const std : : string & ptrn , const std : : string & variableName ) {
return readWord ( pattern ( ptrn ) , variableName ) ;
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
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 : : vector < std : : string > InStream : : readTokens ( int size , int indexBase ) {
__testlib_readMany ( readTokens , readToken ( ) , 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 ) {
2016-07-18 16:39:37 +00:00
readWordTo ( result ) ;
2022-10-10 06:43:01 +00:00
if ( ! p . matches ( result ) ) {
2016-07-18 16:39:37 +00:00
if ( variableName . empty ( ) )
2022-10-10 06:43:01 +00:00
quit ( _wa , ( " Token \" " + __testlib_part ( result ) + " \" doesn't correspond to pattern \" " + p . src ( ) +
" \" " ) . c_str ( ) ) ;
2016-07-18 16:39:37 +00:00
else
2022-10-10 06:43:01 +00:00
quit ( _wa , ( " Token parameter [name= " + variableName + " ] equals to \" " + __testlib_part ( result ) +
" \" , doesn't correspond to pattern \" " + p . src ( ) + " \" " ) . c_str ( ) ) ;
2016-07-18 16:39:37 +00:00
}
}
2022-10-10 06:43:01 +00:00
void InStream : : readWordTo ( std : : string & result , const std : : string & ptrn , const std : : string & variableName ) {
2016-07-18 16:39:37 +00:00
return readWordTo ( result , pattern ( ptrn ) , variableName ) ;
}
2022-10-10 06:43:01 +00:00
void InStream : : readTokenTo ( std : : string & result , const pattern & p , const std : : string & variableName ) {
2016-07-18 16:39:37 +00:00
return readWordTo ( result , p , variableName ) ;
}
2022-10-10 06:43:01 +00:00
void InStream : : readTokenTo ( std : : string & result , const std : : string & ptrn , const std : : string & variableName ) {
2016-07-18 16:39:37 +00:00
return readWordTo ( result , ptrn , variableName ) ;
}
# ifdef __GNUC__
__attribute__ ( ( pure ) )
# endif
2022-10-10 06:43:01 +00:00
static inline bool equals ( long long integer , const char * s ) {
2016-07-18 16:39:37 +00:00
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 ;
2022-10-10 06:43:01 +00:00
while ( integer > 0 ) {
2016-07-18 16:39:37 +00:00
int digit = int ( integer % 10 ) ;
if ( s [ length - 1 ] ! = ' 0 ' + digit )
return false ;
length - - ;
integer / = 10 ;
}
return length = = 0 ;
}
2022-10-10 06:43:01 +00:00
# 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 ) {
2016-07-18 16:39:37 +00:00
double retval ;
size_t length = strlen ( buffer ) ;
int minusCount = 0 ;
int plusCount = 0 ;
int decimalPointCount = 0 ;
int digitCount = 0 ;
int eCount = 0 ;
2022-10-10 06:43:01 +00:00
for ( size_t i = 0 ; i < length ; i + + ) {
2016-07-18 16:39:37 +00:00
if ( ( ' 0 ' < = buffer [ i ] & & buffer [ i ] < = ' 9 ' ) | | buffer [ i ] = = ' . '
2022-10-10 06:43:01 +00:00
| | buffer [ i ] = = ' e ' | | buffer [ i ] = = ' E '
| | buffer [ i ] = = ' - ' | | buffer [ i ] = = ' + ' ) {
2016-07-18 16:39:37 +00:00
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 + + ;
2022-10-10 06:43:01 +00:00
} else
2016-07-18 16:39:37 +00:00
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 ( ) ) ;
2022-10-10 06:43:01 +00:00
char * suffix = new char [ length + 1 ] ;
std : : memset ( suffix , 0 , length + 1 ) ;
2016-07-18 16:39:37 +00:00
int scanned = std : : sscanf ( buffer , " %lf%s " , & retval , suffix ) ;
bool empty = strlen ( suffix ) = = 0 ;
delete [ ] suffix ;
2022-10-10 06:43:01 +00:00
if ( scanned = = 1 | | ( scanned = = 2 & & empty ) ) {
if ( __testlib_isNaN ( retval ) )
2016-07-18 16:39:37 +00:00
in . quit ( _pe , ( " Expected double, but \" " + __testlib_part ( buffer ) + " \" found " ) . c_str ( ) ) ;
return retval ;
2022-10-10 06:43:01 +00:00
} else
2016-07-18 16:39:37 +00:00
in . quit ( _pe , ( " Expected double, but \" " + __testlib_part ( buffer ) + " \" found " ) . c_str ( ) ) ;
}
2022-10-10 06:43:01 +00:00
static inline double stringToDouble ( InStream & in , const std : : string & buffer ) {
for ( size_t i = 0 ; i < buffer . length ( ) ; i + + )
if ( buffer [ i ] = = ' \0 ' )
in . quit ( _pe , ( " Expected double, but \" " + __testlib_part ( buffer ) + " \" found (it contains \\ 0) " ) . c_str ( ) ) ;
return stringToDouble ( in , buffer . c_str ( ) ) ;
}
static inline double stringToStrictDouble ( InStream & in , const char * buffer ,
int minAfterPointDigitCount , int maxAfterPointDigitCount ) {
2016-07-18 16:39:37 +00:00
if ( minAfterPointDigitCount < 0 )
in . quit ( _fail , " stringToStrictDouble: minAfterPointDigitCount should be non-negative. " ) ;
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
if ( minAfterPointDigitCount > maxAfterPointDigitCount )
2022-10-10 06:43:01 +00:00
in . quit ( _fail ,
" stringToStrictDouble: minAfterPointDigitCount should be less or equal to maxAfterPointDigitCount. " ) ;
2016-07-18 16:39:37 +00:00
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 ( ) ) ;
2022-10-10 06:43:01 +00:00
int pointPos = - 1 ;
for ( size_t i = 1 ; i + 1 < length ; i + + ) {
if ( buffer [ i ] = = ' . ' ) {
2016-07-18 16:39:37 +00:00
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 [ "
2022-10-10 06:43:01 +00:00
+ vtos ( minAfterPointDigitCount )
+ " , "
+ vtos ( maxAfterPointDigitCount )
+ " ], but \" " + __testlib_part ( buffer ) + " \" found " ) . c_str ( )
2016-07-18 16:39:37 +00:00
) ;
int firstDigitPos = - 1 ;
for ( size_t i = 0 ; i < length ; i + + )
2022-10-10 06:43:01 +00:00
if ( buffer [ i ] > = ' 0 ' & & buffer [ i ] < = ' 9 ' ) {
2016-07-18 16:39:37 +00:00
firstDigitPos = int ( i ) ;
break ;
}
2022-10-10 06:43:01 +00:00
if ( firstDigitPos > 1 | | firstDigitPos = = - 1 )
2016-07-18 16:39:37 +00:00
in . quit ( _pe , ( " Expected strict double, but \" " + __testlib_part ( buffer ) + " \" found " ) . c_str ( ) ) ;
if ( buffer [ firstDigitPos ] = = ' 0 ' & & firstDigitPos + 1 < int ( length )
2022-10-10 06:43:01 +00:00
& & buffer [ firstDigitPos + 1 ] > = ' 0 ' & & buffer [ firstDigitPos + 1 ] < = ' 9 ' )
2016-07-18 16:39:37 +00:00
in . quit ( _pe , ( " Expected strict double, but \" " + __testlib_part ( buffer ) + " \" found " ) . c_str ( ) ) ;
2022-10-10 06:43:01 +00:00
char * suffix = new char [ length + 1 ] ;
std : : memset ( suffix , 0 , length + 1 ) ;
2016-07-18 16:39:37 +00:00
int scanned = std : : sscanf ( buffer , " %lf%s " , & retval , suffix ) ;
bool empty = strlen ( suffix ) = = 0 ;
delete [ ] suffix ;
2022-10-10 06:43:01 +00:00
if ( scanned = = 1 | | ( scanned = = 2 & & empty ) ) {
2016-07-18 16:39:37 +00:00
if ( __testlib_isNaN ( retval ) | | __testlib_isInfinite ( retval ) )
in . quit ( _pe , ( " Expected double, but \" " + __testlib_part ( buffer ) + " \" found " ) . c_str ( ) ) ;
2022-10-10 06:43:01 +00:00
if ( buffer [ 0 ] = = ' - ' & & retval > = 0 )
in . quit ( _pe , ( " Redundant minus in \" " + __testlib_part ( buffer ) + " \" found " ) . c_str ( ) ) ;
2016-07-18 16:39:37 +00:00
return retval ;
2022-10-10 06:43:01 +00:00
} else
2016-07-18 16:39:37 +00:00
in . quit ( _pe , ( " Expected double, but \" " + __testlib_part ( buffer ) + " \" found " ) . c_str ( ) ) ;
}
2022-10-10 06:43:01 +00:00
static inline double stringToStrictDouble ( InStream & in , const std : : string & buffer ,
int minAfterPointDigitCount , int maxAfterPointDigitCount ) {
for ( size_t i = 0 ; i < buffer . length ( ) ; i + + )
if ( buffer [ i ] = = ' \0 ' )
in . quit ( _pe , ( " Expected double, but \" " + __testlib_part ( buffer ) + " \" found (it contains \\ 0) " ) . c_str ( ) ) ;
return stringToStrictDouble ( in , buffer . c_str ( ) , minAfterPointDigitCount , maxAfterPointDigitCount ) ;
}
static inline long long stringToLongLong ( InStream & in , const char * buffer ) {
2016-07-18 16:39:37 +00:00
if ( strcmp ( buffer , " -9223372036854775808 " ) = = 0 )
return LLONG_MIN ;
bool minus = false ;
size_t length = strlen ( buffer ) ;
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
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 ;
2022-10-10 06:43:01 +00:00
bool processingZeroes = true ;
for ( int i = ( minus ? 1 : 0 ) ; i < int ( length ) ; i + + ) {
2016-07-18 16:39:37 +00:00
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 ( ) ) ;
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
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 ( ) ) ;
}
2022-10-10 06:43:01 +00:00
static inline long long stringToLongLong ( InStream & in , const std : : string & buffer ) {
for ( size_t i = 0 ; i < buffer . length ( ) ; i + + )
if ( buffer [ i ] = = ' \0 ' )
in . quit ( _pe , ( " Expected integer, but \" " + __testlib_part ( buffer ) + " \" found (it contains \\ 0) " ) . c_str ( ) ) ;
return stringToLongLong ( in , buffer . 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 " ) > 0 )
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 ( ) ) ;
}
static inline long long stringToUnsignedLongLong ( InStream & in , const std : : string & buffer ) {
for ( size_t i = 0 ; i < buffer . length ( ) ; i + + )
if ( buffer [ i ] = = ' \0 ' )
in . quit ( _pe , ( " Expected unsigned integer, but \" " + __testlib_part ( buffer ) + " \" found (it contains \\ 0) " ) . c_str ( ) ) ;
return stringToUnsignedLongLong ( in , buffer . c_str ( ) ) ;
}
int InStream : : readInteger ( ) {
2016-07-18 16:39:37 +00:00
if ( ! strict & & seekEof ( ) )
quit ( _unexpected_eof , " Unexpected end of file - int32 expected " ) ;
readWordTo ( _tmpReadToken ) ;
2022-10-10 06:43:01 +00:00
long long value = stringToLongLong ( * this , _tmpReadToken ) ;
2016-07-18 16:39:37 +00:00
if ( value < INT_MIN | | value > INT_MAX )
quit ( _pe , ( " Expected int32, but \" " + __testlib_part ( _tmpReadToken ) + " \" found " ) . c_str ( ) ) ;
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
return int ( value ) ;
}
2022-10-10 06:43:01 +00:00
long long InStream : : readLong ( ) {
if ( ! strict & & seekEof ( ) )
quit ( _unexpected_eof , " Unexpected end of file - int64 expected " ) ;
readWordTo ( _tmpReadToken ) ;
return stringToLongLong ( * this , _tmpReadToken ) ;
}
unsigned long long InStream : : readUnsignedLong ( ) {
2016-07-18 16:39:37 +00:00
if ( ! strict & & seekEof ( ) )
quit ( _unexpected_eof , " Unexpected end of file - int64 expected " ) ;
readWordTo ( _tmpReadToken ) ;
2022-10-10 06:43:01 +00:00
return stringToUnsignedLongLong ( * this , _tmpReadToken ) ;
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
long long InStream : : readLong ( long long minv , long long maxv , const std : : string & variableName ) {
2016-07-18 16:39:37 +00:00
long long result = readLong ( ) ;
2022-10-10 06:43:01 +00:00
if ( result < minv | | result > maxv ) {
if ( readManyIteration = = NO_INDEX ) {
if ( variableName . empty ( ) )
quit ( _wa , ( " Integer " + vtos ( result ) + " violates the range [ " + toHumanReadableString ( minv ) + " , " + toHumanReadableString ( maxv ) +
" ] " ) . c_str ( ) ) ;
else
quit ( _wa , ( " Integer parameter [name= " + std : : string ( variableName ) + " ] equals to " + vtos ( result ) +
" , violates the range [ " + toHumanReadableString ( minv ) + " , " + toHumanReadableString ( maxv ) + " ] " ) . c_str ( ) ) ;
} else {
if ( variableName . empty ( ) )
quit ( _wa , ( " Integer element [index= " + vtos ( readManyIteration ) + " ] equals to " + vtos ( result ) +
" , violates the range [ " + toHumanReadableString ( minv ) + " , " + toHumanReadableString ( maxv ) + " ] " ) . c_str ( ) ) ;
else
quit ( _wa ,
( " Integer element " + std : : string ( variableName ) + " [ " + vtos ( readManyIteration ) + " ] equals to " +
vtos ( result ) + " , violates the range [ " + toHumanReadableString ( minv ) + " , " + toHumanReadableString ( maxv ) + " ] " ) . c_str ( ) ) ;
}
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
if ( strict & & ! variableName . empty ( ) )
validator . addBoundsHit ( variableName , ValidatorBoundsHit ( minv = = result , maxv = = result ) ) ;
2016-07-18 16:39:37 +00:00
return result ;
}
2022-10-10 06:43:01 +00:00
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 )
}
std : : vector < long long > InStream : : readLongs ( int size , int indexBase ) {
__testlib_readMany ( readLongs , readLong ( ) , 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 [ " + toHumanReadableString ( minv ) + " , " + toHumanReadableString ( maxv ) +
" ] " ) . c_str ( ) ) ;
else
quit ( _wa ,
( " Unsigned integer parameter [name= " + std : : string ( variableName ) + " ] equals to " + vtos ( result ) +
" , violates the range [ " + toHumanReadableString ( minv ) + " , " + toHumanReadableString ( maxv ) + " ] " ) . c_str ( ) ) ;
} else {
if ( variableName . empty ( ) )
quit ( _wa ,
( " Unsigned integer element [index= " + vtos ( readManyIteration ) + " ] equals to " + vtos ( result ) +
" , violates the range [ " + toHumanReadableString ( minv ) + " , " + toHumanReadableString ( maxv ) + " ] " ) . c_str ( ) ) ;
else
quit ( _wa , ( " Unsigned integer element " + std : : string ( variableName ) + " [ " + vtos ( readManyIteration ) +
" ] equals to " + vtos ( result ) + " , violates the range [ " + toHumanReadableString ( minv ) + " , " + toHumanReadableString ( 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 )
}
std : : vector < unsigned long long > InStream : : readUnsignedLongs ( int size , int indexBase ) {
__testlib_readMany ( readUnsignedLongs , readUnsignedLong ( ) , 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 ( ) {
2016-07-18 16:39:37 +00:00
return readInteger ( ) ;
}
2022-10-10 06:43:01 +00:00
int InStream : : readInt ( int minv , int maxv , const std : : string & variableName ) {
2016-07-18 16:39:37 +00:00
int result = readInt ( ) ;
2022-10-10 06:43:01 +00:00
if ( result < minv | | result > maxv ) {
if ( readManyIteration = = NO_INDEX ) {
if ( variableName . empty ( ) )
quit ( _wa , ( " Integer " + vtos ( result ) + " violates the range [ " + toHumanReadableString ( minv ) + " , " + toHumanReadableString ( maxv ) +
" ] " ) . c_str ( ) ) ;
else
quit ( _wa , ( " Integer parameter [name= " + std : : string ( variableName ) + " ] equals to " + vtos ( result ) +
" , violates the range [ " + toHumanReadableString ( minv ) + " , " + toHumanReadableString ( maxv ) + " ] " ) . c_str ( ) ) ;
} else {
if ( variableName . empty ( ) )
quit ( _wa , ( " Integer element [index= " + vtos ( readManyIteration ) + " ] equals to " + vtos ( result ) +
" , violates the range [ " + toHumanReadableString ( minv ) + " , " + toHumanReadableString ( maxv ) + " ] " ) . c_str ( ) ) ;
else
quit ( _wa ,
( " Integer element " + std : : string ( variableName ) + " [ " + vtos ( readManyIteration ) + " ] equals to " +
vtos ( result ) + " , violates the range [ " + toHumanReadableString ( minv ) + " , " + toHumanReadableString ( maxv ) + " ] " ) . c_str ( ) ) ;
}
}
if ( strict & & ! variableName . empty ( ) )
validator . addBoundsHit ( variableName , ValidatorBoundsHit ( minv = = result , maxv = = result ) ) ;
2016-07-18 16:39:37 +00:00
return result ;
}
2022-10-10 06:43:01 +00:00
int InStream : : readInteger ( int minv , int maxv , const std : : string & variableName ) {
return readInt ( minv , maxv , variableName ) ;
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
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 : : readInts ( int size , int indexBase ) {
__testlib_readMany ( readInts , readInt ( ) , 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 )
}
std : : vector < int > InStream : : readIntegers ( int size , int indexBase ) {
__testlib_readMany ( readIntegers , readInt ( ) , int , true )
}
double InStream : : readReal ( ) {
2016-07-18 16:39:37 +00:00
if ( ! strict & & seekEof ( ) )
quit ( _unexpected_eof , " Unexpected end of file - double expected " ) ;
2022-10-10 06:43:01 +00:00
return stringToDouble ( * this , readWord ( ) ) ;
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
double InStream : : readDouble ( ) {
2016-07-18 16:39:37 +00:00
return readReal ( ) ;
}
2022-10-10 06:43:01 +00:00
double InStream : : readReal ( double minv , double maxv , const std : : string & variableName ) {
2016-07-18 16:39:37 +00:00
double result = readReal ( ) ;
2022-10-10 06:43:01 +00:00
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 ( ) ) ;
}
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
if ( strict & & ! variableName . empty ( ) )
validator . addBoundsHit ( variableName , ValidatorBoundsHit (
doubleDelta ( minv , result ) < ValidatorBoundsHit : : EPS ,
doubleDelta ( maxv , result ) < ValidatorBoundsHit : : EPS
) ) ;
2016-07-18 16:39:37 +00:00
return result ;
}
2022-10-10 06:43:01 +00:00
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 )
}
std : : vector < double > InStream : : readReals ( int size , int indexBase ) {
__testlib_readMany ( readReals , readReal ( ) , double , true )
}
double InStream : : readDouble ( double minv , double maxv , const std : : string & variableName ) {
2016-07-18 16:39:37 +00:00
return readReal ( minv , maxv , variableName ) ;
2022-10-10 06:43:01 +00:00
}
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 )
}
std : : vector < double > InStream : : readDoubles ( int size , int indexBase ) {
__testlib_readMany ( readDoubles , readDouble ( ) , double , true )
}
2016-07-18 16:39:37 +00:00
double InStream : : readStrictReal ( double minv , double maxv ,
2022-10-10 06:43:01 +00:00
int minAfterPointDigitCount , int maxAfterPointDigitCount ,
const std : : string & variableName ) {
2016-07-18 16:39:37 +00:00
if ( ! strict & & seekEof ( ) )
quit ( _unexpected_eof , " Unexpected end of file - strict double expected " ) ;
2022-10-10 06:43:01 +00:00
double result = stringToStrictDouble ( * this , readWord ( ) , minAfterPointDigitCount , maxAfterPointDigitCount ) ;
2016-07-18 16:39:37 +00:00
2022-10-10 06:43:01 +00:00
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 ( ) ) ;
}
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
if ( strict & & ! variableName . empty ( ) )
validator . addBoundsHit ( variableName , ValidatorBoundsHit (
doubleDelta ( minv , result ) < ValidatorBoundsHit : : EPS ,
doubleDelta ( maxv , result ) < ValidatorBoundsHit : : EPS
) ) ;
2016-07-18 16:39:37 +00:00
return result ;
}
2022-10-10 06:43:01 +00:00
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 )
}
2016-07-18 16:39:37 +00:00
double InStream : : readStrictDouble ( double minv , double maxv ,
2022-10-10 06:43:01 +00:00
int minAfterPointDigitCount , int maxAfterPointDigitCount ,
const std : : string & variableName ) {
2016-07-18 16:39:37 +00:00
return readStrictReal ( minv , maxv ,
2022-10-10 06:43:01 +00:00
minAfterPointDigitCount , maxAfterPointDigitCount ,
variableName ) ;
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
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 )
2016-07-18 16:39:37 +00:00
return true ;
return reader - > eof ( ) ;
}
2022-10-10 06:43:01 +00:00
bool InStream : : seekEof ( ) {
if ( ! strict & & NULL = = reader )
2016-07-18 16:39:37 +00:00
return true ;
skipBlanks ( ) ;
return eof ( ) ;
}
2022-10-10 06:43:01 +00:00
bool InStream : : eoln ( ) {
if ( ! strict & & NULL = = reader )
2016-07-18 16:39:37 +00:00
return true ;
int c = reader - > nextChar ( ) ;
2022-10-10 06:43:01 +00:00
if ( ! strict ) {
if ( c = = EOFC )
2016-07-18 16:39:37 +00:00
return true ;
2022-10-10 06:43:01 +00:00
if ( c = = CR ) {
2016-07-18 16:39:37 +00:00
c = reader - > nextChar ( ) ;
2022-10-10 06:43:01 +00:00
if ( c ! = LF ) {
2016-07-18 16:39:37 +00:00
reader - > unreadChar ( c ) ;
reader - > unreadChar ( CR ) ;
return false ;
2022-10-10 06:43:01 +00:00
} else
2016-07-18 16:39:37 +00:00
return true ;
}
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
if ( c = = LF )
return true ;
reader - > unreadChar ( c ) ;
return false ;
2022-10-10 06:43:01 +00:00
} else {
2016-07-18 16:39:37 +00:00
bool returnCr = false ;
2022-10-10 06:43:01 +00:00
# if (defined(ON_WINDOWS) && !defined(FOR_LINUX)) || defined(FOR_WINDOWS)
if ( c ! = CR ) {
2016-07-18 16:39:37 +00:00
reader - > unreadChar ( c ) ;
return false ;
2022-10-10 06:43:01 +00:00
} else {
2016-07-18 16:39:37 +00:00
if ( ! returnCr )
returnCr = true ;
c = reader - > nextChar ( ) ;
}
2022-10-10 06:43:01 +00:00
# endif
if ( c ! = LF ) {
2016-07-18 16:39:37 +00:00
reader - > unreadChar ( c ) ;
if ( returnCr )
reader - > unreadChar ( CR ) ;
return false ;
}
return true ;
}
}
2022-10-10 06:43:01 +00:00
void InStream : : readEoln ( ) {
lastLine = reader - > getLine ( ) ;
2016-07-18 16:39:37 +00:00
if ( ! eoln ( ) )
quit ( _pe , " Expected EOLN " ) ;
}
2022-10-10 06:43:01 +00:00
void InStream : : readEof ( ) {
lastLine = reader - > getLine ( ) ;
2016-07-18 16:39:37 +00:00
if ( ! eof ( ) )
quit ( _pe , " Expected EOF " ) ;
if ( TestlibFinalizeGuard : : alive & & this = = & inf )
testlibFinalizeGuard . readEofCount + + ;
}
2022-10-10 06:43:01 +00:00
bool InStream : : seekEoln ( ) {
if ( ! strict & & NULL = = reader )
2016-07-18 16:39:37 +00:00
return true ;
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
int cur ;
2022-10-10 06:43:01 +00:00
do {
2016-07-18 16:39:37 +00:00
cur = reader - > nextChar ( ) ;
2022-10-10 06:43:01 +00:00
} while ( cur = = SPACE | | cur = = TAB ) ;
2016-07-18 16:39:37 +00:00
reader - > unreadChar ( cur ) ;
return eoln ( ) ;
}
2022-10-10 06:43:01 +00:00
void InStream : : nextLine ( ) {
2016-07-18 16:39:37 +00:00
readLine ( ) ;
}
2022-10-10 06:43:01 +00:00
void InStream : : readStringTo ( std : : string & result ) {
if ( NULL = = reader )
2016-07-18 16:39:37 +00:00
quit ( _pe , " Expected line " ) ;
result . clear ( ) ;
2022-10-10 06:43:01 +00:00
for ( ; ; ) {
int cur = reader - > curChar ( ) ;
2016-07-18 16:39:37 +00:00
2022-10-10 06:43:01 +00:00
if ( cur = = LF | | cur = = EOFC )
2016-07-18 16:39:37 +00:00
break ;
2022-10-10 06:43:01 +00:00
if ( cur = = CR ) {
cur = reader - > nextChar ( ) ;
if ( reader - > curChar ( ) = = LF ) {
reader - > unreadChar ( cur ) ;
break ;
}
}
2016-07-18 16:39:37 +00:00
2022-10-10 06:43:01 +00:00
lastLine = reader - > getLine ( ) ;
2016-07-18 16:39:37 +00:00
result + = char ( reader - > nextChar ( ) ) ;
}
if ( strict )
readEoln ( ) ;
else
eoln ( ) ;
}
2022-10-10 06:43:01 +00:00
std : : string InStream : : readString ( ) {
2016-07-18 16:39:37 +00:00
readStringTo ( _tmpReadToken ) ;
return _tmpReadToken ;
}
2022-10-10 06:43:01 +00:00
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 ) {
2016-07-18 16:39:37 +00:00
readStringTo ( result ) ;
2022-10-10 06:43:01 +00:00
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 ( ) ) ;
}
2016-07-18 16:39:37 +00:00
}
}
2022-10-10 06:43:01 +00:00
void InStream : : readStringTo ( std : : string & result , const std : : string & ptrn , const std : : string & variableName ) {
2016-07-18 16:39:37 +00:00
readStringTo ( result , pattern ( ptrn ) , variableName ) ;
}
2022-10-10 06:43:01 +00:00
std : : string InStream : : readString ( const pattern & p , const std : : string & variableName ) {
2016-07-18 16:39:37 +00:00
readStringTo ( _tmpReadToken , p , variableName ) ;
return _tmpReadToken ;
}
2022-10-10 06:43:01 +00:00
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 ) {
2016-07-18 16:39:37 +00:00
readStringTo ( _tmpReadToken , ptrn , variableName ) ;
return _tmpReadToken ;
}
2022-10-10 06:43:01 +00:00
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 ) {
2016-07-18 16:39:37 +00:00
readStringTo ( result ) ;
}
2022-10-10 06:43:01 +00:00
std : : string InStream : : readLine ( ) {
2016-07-18 16:39:37 +00:00
return readString ( ) ;
}
2022-10-10 06:43:01 +00:00
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 ) {
2016-07-18 16:39:37 +00:00
readStringTo ( result , p , variableName ) ;
}
2022-10-10 06:43:01 +00:00
void InStream : : readLineTo ( std : : string & result , const std : : string & ptrn , const std : : string & variableName ) {
2016-07-18 16:39:37 +00:00
readStringTo ( result , ptrn , variableName ) ;
}
2022-10-10 06:43:01 +00:00
std : : string InStream : : readLine ( const pattern & p , const std : : string & variableName ) {
2016-07-18 16:39:37 +00:00
return readString ( p , variableName ) ;
}
2022-10-10 06:43:01 +00:00
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 ) {
2016-07-18 16:39:37 +00:00
return readString ( ptrn , variableName ) ;
}
2022-10-10 06:43:01 +00:00
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 )
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
# ifdef __GNUC__
__attribute__ ( ( format ( printf , 3 , 4 ) ) )
# endif
void InStream : : ensuref ( bool cond , const char * format , . . . ) {
if ( ! cond ) {
FMT_TO_RESULT ( format , format , message ) ;
this - > __testlib_ensure ( cond , message ) ;
}
}
void InStream : : __testlib_ensure ( bool cond , std : : string message ) {
if ( ! cond )
this - > quit ( _wa , message . c_str ( ) ) ;
}
void InStream : : close ( ) {
if ( NULL ! = reader ) {
reader - > close ( ) ;
delete reader ;
reader = NULL ;
}
opened = false ;
}
NORETURN void quit ( TResult result , const std : : string & msg ) {
2016-07-18 16:39:37 +00:00
ouf . quit ( result , msg . c_str ( ) ) ;
}
2022-10-10 06:43:01 +00:00
NORETURN void quit ( TResult result , const char * msg ) {
2016-07-18 16:39:37 +00:00
ouf . quit ( result , msg ) ;
}
2022-10-10 06:43:01 +00:00
NORETURN void __testlib_quitp ( double points , const char * message ) {
2016-07-18 16:39:37 +00:00
__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 ( ) ) ;
}
2022-10-10 06:43:01 +00:00
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 = " " ) {
2016-07-18 16:39:37 +00:00
__testlib_quitp ( double ( points ) , message . c_str ( ) ) ;
}
2022-10-10 06:43:01 +00:00
NORETURN void quitp ( double points , const std : : string & message = " " ) {
2016-07-18 16:39:37 +00:00
__testlib_quitp ( points , message . c_str ( ) ) ;
}
2022-10-10 06:43:01 +00:00
NORETURN void quitp ( long double points , const std : : string & message = " " ) {
2016-07-18 16:39:37 +00:00
__testlib_quitp ( double ( points ) , message . c_str ( ) ) ;
}
2022-10-10 06:43:01 +00:00
NORETURN void quitp ( int points , const std : : string & message = " " ) {
__testlib_quitp ( points , message . c_str ( ) ) ;
}
NORETURN void quitpi ( const std : : string & points_info , const std : : string & message = " " ) {
if ( points_info . find ( ' ' ) ! = std : : string : : npos )
quit ( _fail , " Parameter 'points_info' can't contain spaces " ) ;
if ( message . empty ( ) )
quit ( _points , ( " points_info= " + points_info ) . c_str ( ) ) ;
else
quit ( _points , ( " points_info= " + points_info + " " + message ) . c_str ( ) ) ;
}
2016-07-18 16:39:37 +00:00
template < typename F >
# ifdef __GNUC__
__attribute__ ( ( format ( printf , 2 , 3 ) ) )
# endif
2022-10-10 06:43:01 +00:00
NORETURN void quitp ( F points , const char * format , . . . ) {
2016-07-18 16:39:37 +00:00
FMT_TO_RESULT ( format , format , message ) ;
quitp ( points , message ) ;
}
# ifdef __GNUC__
__attribute__ ( ( format ( printf , 2 , 3 ) ) )
# endif
2022-10-10 06:43:01 +00:00
NORETURN void quitf ( TResult result , const char * format , . . . ) {
2016-07-18 16:39:37 +00:00
FMT_TO_RESULT ( format , format , message ) ;
quit ( result , message ) ;
}
# ifdef __GNUC__
__attribute__ ( ( format ( printf , 3 , 4 ) ) )
# endif
2022-10-10 06:43:01 +00:00
void quitif ( bool condition , TResult result , const char * format , . . . ) {
if ( condition ) {
2016-07-18 16:39:37 +00:00
FMT_TO_RESULT ( format , format , message ) ;
quit ( result , message ) ;
}
}
2022-10-10 06:43:01 +00:00
NORETURN void __testlib_help ( ) {
2016-07-18 16:39:37 +00:00
InStream : : textColor ( InStream : : LightCyan ) ;
2022-10-10 06:43:01 +00:00
std : : fprintf ( stderr , " TESTLIB %s, https://github.com/MikeMirzayanov/testlib/ " , VERSION ) ;
std : : fprintf ( stderr , " by Mike Mirzayanov, copyright(c) 2005-2020 \n " ) ;
2016-07-18 16:39:37 +00:00
std : : fprintf ( stderr , " Checker name: \" %s \" \n " , checkerName . c_str ( ) ) ;
InStream : : textColor ( InStream : : LightGray ) ;
std : : fprintf ( stderr , " \n " ) ;
std : : fprintf ( stderr , " Latest features: \n " ) ;
2022-10-10 06:43:01 +00:00
for ( size_t i = 0 ; i < sizeof ( latestFeatures ) / sizeof ( char * ) ; i + + ) {
2016-07-18 16:39:37 +00:00
std : : fprintf ( stderr , " *) %s \n " , latestFeatures [ i ] ) ;
}
std : : fprintf ( stderr , " \n " ) ;
std : : fprintf ( stderr , " Program must be run with the following arguments: \n " ) ;
2022-10-10 06:43:01 +00:00
std : : fprintf ( stderr , " [--testset testset] [--group group] <input-file> <output-file> <answer-file> [<report-file> [<-appes>]] \n \n " ) ;
2016-07-18 16:39:37 +00:00
std : : exit ( FAIL_EXIT_CODE ) ;
}
2022-10-10 06:43:01 +00:00
static void __testlib_ensuresPreconditions ( ) {
2016-07-18 16:39:37 +00:00
// 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 ) ;
2022-10-10 06:43:01 +00:00
// testlib assumes: sizeof(double) = 8.
__TESTLIB_STATIC_ASSERT ( sizeof ( double ) = = 8 ) ;
2016-07-18 16:39:37 +00:00
// 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' " ) ;
}
2022-10-10 06:43:01 +00:00
void registerGen ( int argc , char * argv [ ] , int randomGeneratorVersion ) {
2016-07-18 16:39:37 +00:00
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 ) ;
2022-10-10 06:43:01 +00:00
# if __cplusplus > 199711L || defined(_MSC_VER)
prepareOpts ( argc , argv ) ;
# endif
2016-07-18 16:39:37 +00:00
}
# ifdef USE_RND_AS_BEFORE_087
void registerGen ( int argc , char * argv [ ] )
{
registerGen ( argc , argv , 0 ) ;
}
# else
2022-10-10 06:43:01 +00:00
# ifdef __GNUC__
# if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 4))
__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. " ) ) )
# else
__attribute__ ( ( deprecated ) )
# endif
# 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 [ ] ) {
2016-07-18 16:39:37 +00:00
std : : fprintf ( stderr , " Use registerGen(argc, argv, 0) or registerGen(argc, argv, 1). "
2022-10-10 06:43:01 +00:00
" 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 " ) ;
2016-07-18 16:39:37 +00:00
registerGen ( argc , argv , 0 ) ;
}
# endif
2022-10-10 06:43:01 +00:00
void registerInteraction ( int argc , char * argv [ ] ) {
2016-07-18 16:39:37 +00:00
__testlib_ensuresPreconditions ( ) ;
testlibMode = _interactor ;
__testlib_set_binary ( stdin ) ;
if ( argc > 1 & & ! strcmp ( " --help " , argv [ 1 ] ) )
__testlib_help ( ) ;
2022-10-10 06:43:01 +00:00
if ( argc < 3 | | argc > 6 ) {
2016-07-18 16:39:37 +00:00
quit ( _fail , std : : string ( " Program must be run with the following arguments: " ) +
2022-10-10 06:43:01 +00:00
std : : string ( " <input-file> <output-file> [<answer-file> [<report-file> [<-appes>]]] " ) +
" \n Use \" --help \" to get help information " ) ;
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
if ( argc < = 4 ) {
2016-07-18 16:39:37 +00:00
resultName = " " ;
appesMode = false ;
}
2022-10-10 06:43:01 +00:00
# ifndef EJUDGE
if ( argc = = 5 ) {
2016-07-18 16:39:37 +00:00
resultName = argv [ 4 ] ;
appesMode = false ;
}
2022-10-10 06:43:01 +00:00
if ( argc = = 6 ) {
if ( strcmp ( " -APPES " , argv [ 5 ] ) & & strcmp ( " -appes " , argv [ 5 ] ) ) {
2016-07-18 16:39:37 +00:00
quit ( _fail , std : : string ( " Program must be run with the following arguments: " ) +
" <input-file> <output-file> <answer-file> [<report-file> [<-appes>]] " ) ;
2022-10-10 06:43:01 +00:00
} else {
2016-07-18 16:39:37 +00:00
resultName = argv [ 4 ] ;
appesMode = true ;
}
}
2022-10-10 06:43:01 +00:00
# endif
2016-07-18 16:39:37 +00:00
inf . init ( argv [ 1 ] , _input ) ;
2022-10-10 06:43:01 +00:00
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 ( " ' " ) ) ;
2016-07-18 16:39:37 +00:00
ouf . init ( stdin , _output ) ;
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
if ( argc > = 4 )
ans . init ( argv [ 3 ] , _answer ) ;
else
ans . name = " unopened answer stream " ;
}
2022-10-10 06:43:01 +00:00
void registerValidation ( ) {
2016-07-18 16:39:37 +00:00
__testlib_ensuresPreconditions ( ) ;
testlibMode = _validator ;
__testlib_set_binary ( stdin ) ;
inf . init ( stdin , _input ) ;
inf . strict = true ;
}
2022-10-10 06:43:01 +00:00
void registerValidation ( int argc , char * argv [ ] ) {
registerValidation ( ) ;
validator . initialize ( ) ;
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 ) ;
}
class Checker {
private :
bool _initialized ;
std : : string _testset ;
std : : string _group ;
public :
Checker ( ) : _initialized ( false ) , _testset ( " tests " ) , _group ( ) {
}
void initialize ( ) {
_initialized = true ;
}
std : : string testset ( ) const {
if ( ! _initialized )
__testlib_fail ( " Checker should be initialized with registerTestlibCmd(argc, argv) instead of registerTestlibCmd() to support checker.testset() " ) ;
return _testset ;
}
std : : string group ( ) const {
if ( ! _initialized )
__testlib_fail ( " Checker should be initialized with registerTestlibCmd(argc, argv) instead of registerTestlibCmd() to support checker.group() " ) ;
return _group ;
}
void setTestset ( const char * const testset ) {
_testset = testset ;
}
void setGroup ( const char * const group ) {
_group = group ;
}
} checker ;
void registerTestlibCmd ( int argc , char * argv [ ] ) {
2016-07-18 16:39:37 +00:00
__testlib_ensuresPreconditions ( ) ;
testlibMode = _checker ;
2022-10-10 06:43:01 +00:00
__testlib_set_binary ( stdin ) ;
2016-07-18 16:39:37 +00:00
2022-10-10 06:43:01 +00:00
std : : vector < std : : string > args ( 1 , argv [ 0 ] ) ;
checker . initialize ( ) ;
for ( int i = 1 ; i < argc ; i + + ) {
if ( ! strcmp ( " --testset " , argv [ i ] ) ) {
if ( i + 1 < argc & & strlen ( argv [ i + 1 ] ) > 0 )
checker . setTestset ( argv [ + + i ] ) ;
else
quit ( _fail , std : : string ( " Expected testset after --testset command line parameter " ) ) ;
} else if ( ! strcmp ( " --group " , argv [ i ] ) ) {
if ( i + 1 < argc )
checker . setGroup ( argv [ + + i ] ) ;
else
quit ( _fail , std : : string ( " Expected group after --group command line parameter " ) ) ;
} else
args . push_back ( argv [ i ] ) ;
}
argc = int ( args . size ( ) ) ;
if ( argc > 1 & & " --help " = = args [ 1 ] )
2016-07-18 16:39:37 +00:00
__testlib_help ( ) ;
2022-10-10 06:43:01 +00:00
if ( argc < 4 | | argc > 6 ) {
2016-07-18 16:39:37 +00:00
quit ( _fail , std : : string ( " Program must be run with the following arguments: " ) +
2022-10-10 06:43:01 +00:00
std : : string ( " [--testset testset] [--group group] <input-file> <output-file> <answer-file> [<report-file> [<-appes>]] " ) +
" \n Use \" --help \" to get help information " ) ;
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
if ( argc = = 4 ) {
2016-07-18 16:39:37 +00:00
resultName = " " ;
appesMode = false ;
}
2022-10-10 06:43:01 +00:00
if ( argc = = 5 ) {
resultName = args [ 4 ] ;
2016-07-18 16:39:37 +00:00
appesMode = false ;
}
2022-10-10 06:43:01 +00:00
if ( argc = = 6 ) {
if ( " -APPES " ! = args [ 5 ] & & " -appes " ! = args [ 5 ] ) {
2016-07-18 16:39:37 +00:00
quit ( _fail , std : : string ( " Program must be run with the following arguments: " ) +
" <input-file> <output-file> <answer-file> [<report-file> [<-appes>]] " ) ;
2022-10-10 06:43:01 +00:00
} else {
resultName = args [ 4 ] ;
2016-07-18 16:39:37 +00:00
appesMode = true ;
}
}
2022-10-10 06:43:01 +00:00
inf . init ( args [ 1 ] , _input ) ;
ouf . init ( args [ 2 ] , _output ) ;
ans . init ( args [ 3 ] , _answer ) ;
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
void registerTestlib ( int argc , . . . ) {
if ( argc < 3 | | argc > 5 )
2016-07-18 16:39:37 +00:00
quit ( _fail , std : : string ( " Program must be run with the following arguments: " ) +
2022-10-10 06:43:01 +00:00
" <input-file> <output-file> <answer-file> [<report-file> [<-appes>]] " ) ;
char * * argv = new char * [ argc + 1 ] ;
2016-07-18 16:39:37 +00:00
va_list ap ;
va_start ( ap , argc ) ;
argv [ 0 ] = NULL ;
2022-10-10 06:43:01 +00:00
for ( int i = 0 ; i < argc ; i + + ) {
2016-07-18 16:39:37 +00:00
argv [ i + 1 ] = va_arg ( ap , char * ) ;
}
va_end ( ap ) ;
registerTestlibCmd ( argc + 1 , argv ) ;
delete [ ] argv ;
}
2022-10-10 06:43:01 +00:00
static inline void __testlib_ensure ( bool cond , const std : : string & msg ) {
2016-07-18 16:39:37 +00:00
if ( ! cond )
quit ( _fail , msg . c_str ( ) ) ;
}
2022-10-10 06:43:01 +00:00
# ifdef __GNUC__
__attribute__ ( ( unused ) )
# endif
static inline void __testlib_ensure ( bool cond , const char * msg ) {
2016-07-18 16:39:37 +00:00
if ( ! cond )
quit ( _fail , msg ) ;
}
# define ensure(cond) __testlib_ensure(cond, "Condition failed: \"" #cond "\"")
2022-10-10 06:43:01 +00:00
# define STRINGIZE_DETAIL(x) #x
# define STRINGIZE(x) STRINGIZE_DETAIL(x)
# define ensure_ext(cond) __testlib_ensure(cond, "Line " STRINGIZE(__LINE__) ": Condition failed: \"" #cond "\"")
2016-07-18 16:39:37 +00:00
# ifdef __GNUC__
__attribute__ ( ( format ( printf , 2 , 3 ) ) )
# endif
2022-10-10 06:43:01 +00:00
inline void ensuref ( bool cond , const char * format , . . . ) {
if ( ! cond ) {
2016-07-18 16:39:37 +00:00
FMT_TO_RESULT ( format , format , message ) ;
__testlib_ensure ( cond , message ) ;
}
}
2022-10-10 06:43:01 +00:00
NORETURN static void __testlib_fail ( const std : : string & message ) {
2016-07-18 16:39:37 +00:00
quitf ( _fail , " %s " , message . c_str ( ) ) ;
}
# ifdef __GNUC__
__attribute__ ( ( format ( printf , 1 , 2 ) ) )
# endif
2022-10-10 06:43:01 +00:00
void setName ( const char * format , . . . ) {
2016-07-18 16:39:37 +00:00
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 .
2022-10-10 06:43:01 +00:00
*/
2016-07-18 16:39:37 +00:00
template < typename _RandomAccessIter >
2022-10-10 06:43:01 +00:00
void shuffle ( _RandomAccessIter __first , _RandomAccessIter __last ) {
2016-07-18 16:39:37 +00:00
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 >
2022-10-10 06:43:01 +00:00
# if defined(__GNUC__) && !defined(__clang__)
__attribute__ ( ( error ( " Don't use random_shuffle(), use shuffle() instead " ) ) )
# endif
void random_shuffle ( _RandomAccessIter , _RandomAccessIter ) {
2016-07-18 16:39:37 +00:00
quitf ( _fail , " Don't use random_shuffle(), use shuffle() instead " ) ;
}
# ifdef __GLIBC__
# define RAND_THROW_STATEMENT throw()
# else
# define RAND_THROW_STATEMENT
# endif
2022-10-10 06:43:01 +00:00
# if defined(__GNUC__) && !defined(__clang__)
__attribute__ ( ( error ( " Don't use rand(), use rnd.next() instead " ) ) )
# endif
# ifdef _MSC_VER
# pragma warning( disable : 4273 )
# endif
2016-07-18 16:39:37 +00:00
int rand ( ) RAND_THROW_STATEMENT
{
quitf ( _fail , " Don't use rand(), use rnd.next() instead " ) ;
2022-10-10 06:43:01 +00:00
2016-07-18 16:39:37 +00:00
/* This line never runs. */
//throw "Don't use rand(), use rnd.next() instead";
}
2022-10-10 06:43:01 +00:00
# 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
2016-07-18 16:39:37 +00:00
void srand ( unsigned int seed ) RAND_THROW_STATEMENT
{
2022-10-10 06:43:01 +00:00
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=%u]. " , seed ) ;
2016-07-18 16:39:37 +00:00
}
2022-10-10 06:43:01 +00:00
void startTest ( int test ) {
2016-07-18 16:39:37 +00:00
const std : : string testFileName = vtos ( test ) ;
if ( NULL = = freopen ( testFileName . c_str ( ) , " wt " , stdout ) )
__testlib_fail ( " Unable to write file ' " + testFileName + " ' " ) ;
}
2022-10-10 06:43:01 +00:00
inline std : : string upperCase ( std : : string s ) {
2016-07-18 16:39:37 +00:00
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 ;
}
2022-10-10 06:43:01 +00:00
inline std : : string lowerCase ( std : : string s ) {
2016-07-18 16:39:37 +00:00
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 ;
}
2022-10-10 06:43:01 +00:00
inline std : : string compress ( const std : : string & s ) {
2016-07-18 16:39:37 +00:00
return __testlib_part ( s ) ;
}
2022-10-10 06:43:01 +00:00
inline std : : string englishEnding ( int x ) {
2016-07-18 16:39:37 +00:00
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 " ;
}
2022-10-10 06:43:01 +00:00
template < typename _ForwardIterator , typename _Separator >
std : : string join ( _ForwardIterator first , _ForwardIterator last , _Separator separator ) {
2016-07-18 16:39:37 +00:00
std : : stringstream ss ;
bool repeated = false ;
2022-10-10 06:43:01 +00:00
for ( _ForwardIterator i = first ; i ! = last ; i + + ) {
2016-07-18 16:39:37 +00:00
if ( repeated )
ss < < separator ;
else
repeated = true ;
ss < < * i ;
}
return ss . str ( ) ;
}
2022-10-10 06:43:01 +00:00
template < typename _ForwardIterator >
std : : string join ( _ForwardIterator first , _ForwardIterator last ) {
2016-07-18 16:39:37 +00:00
return join ( first , last , ' ' ) ;
}
2022-10-10 06:43:01 +00:00
template < typename _Collection , typename _Separator >
std : : string join ( const _Collection & collection , _Separator separator ) {
2016-07-18 16:39:37 +00:00
return join ( collection . begin ( ) , collection . end ( ) , separator ) ;
}
2022-10-10 06:43:01 +00:00
template < typename _Collection >
std : : string join ( const _Collection & collection ) {
2016-07-18 16:39:37 +00:00
return join ( collection , ' ' ) ;
}
2022-10-10 06:43:01 +00:00
/**
* 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 ) {
2016-07-18 16:39:37 +00:00
std : : string message ;
if ( strlen ( prepend ) ! = 0 )
message = format ( " %s: expected '%s', but found '%s' " ,
2022-10-10 06:43:01 +00:00
compress ( prepend ) . c_str ( ) , compress ( expected ) . c_str ( ) , compress ( found ) . c_str ( ) ) ;
2016-07-18 16:39:37 +00:00
else
message = format ( " expected '%s', but found '%s' " ,
2022-10-10 06:43:01 +00:00
compress ( expected ) . c_str ( ) , compress ( found ) . c_str ( ) ) ;
2016-07-18 16:39:37 +00:00
quit ( result , message ) ;
}
2022-10-10 06:43:01 +00:00
NORETURN void __testlib_expectedButFound ( TResult result , double expected , double found , const char * prepend ) {
2016-07-18 16:39:37 +00:00
std : : string expectedString = removeDoubleTrailingZeroes ( format ( " %.12f " , expected ) ) ;
std : : string foundString = removeDoubleTrailingZeroes ( format ( " %.12f " , found ) ) ;
__testlib_expectedButFound ( result , expectedString , foundString , prepend ) ;
}
2022-10-10 06:43:01 +00:00
template < typename T >
2016-07-18 16:39:37 +00:00
# ifdef __GNUC__
__attribute__ ( ( format ( printf , 4 , 5 ) ) )
# endif
2022-10-10 06:43:01 +00:00
NORETURN void expectedButFound ( TResult result , T expected , T found , const char * prependFormat = " " , . . . ) {
2016-07-18 16:39:37 +00:00
FMT_TO_RESULT ( prependFormat , prependFormat , prepend ) ;
std : : string expectedString = vtos ( expected ) ;
std : : string foundString = vtos ( found ) ;
__testlib_expectedButFound ( result , expectedString , foundString , prepend . c_str ( ) ) ;
}
2022-10-10 06:43:01 +00:00
template < >
2016-07-18 16:39:37 +00:00
# ifdef __GNUC__
__attribute__ ( ( format ( printf , 4 , 5 ) ) )
# endif
2022-10-10 06:43:01 +00:00
NORETURN void
expectedButFound < std : : string > ( TResult result , std : : string expected , std : : string found , const char * prependFormat , . . . ) {
2016-07-18 16:39:37 +00:00
FMT_TO_RESULT ( prependFormat , prependFormat , prepend ) ;
__testlib_expectedButFound ( result , expected , found , prepend . c_str ( ) ) ;
}
2022-10-10 06:43:01 +00:00
template < >
2016-07-18 16:39:37 +00:00
# ifdef __GNUC__
__attribute__ ( ( format ( printf , 4 , 5 ) ) )
# endif
2022-10-10 06:43:01 +00:00
NORETURN void expectedButFound < double > ( TResult result , double expected , double found , const char * prependFormat , . . . ) {
2016-07-18 16:39:37 +00:00
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 ( ) ) ;
}
2022-10-10 06:43:01 +00:00
template < >
2016-07-18 16:39:37 +00:00
# ifdef __GNUC__
__attribute__ ( ( format ( printf , 4 , 5 ) ) )
# endif
2022-10-10 06:43:01 +00:00
NORETURN void
expectedButFound < const char * > ( TResult result , const char * expected , const char * found , const char * prependFormat ,
. . . ) {
2016-07-18 16:39:37 +00:00
FMT_TO_RESULT ( prependFormat , prependFormat , prepend ) ;
__testlib_expectedButFound ( result , std : : string ( expected ) , std : : string ( found ) , prepend . c_str ( ) ) ;
}
2022-10-10 06:43:01 +00:00
template < >
2016-07-18 16:39:37 +00:00
# ifdef __GNUC__
__attribute__ ( ( format ( printf , 4 , 5 ) ) )
# endif
2022-10-10 06:43:01 +00:00
NORETURN void expectedButFound < float > ( TResult result , float expected , float found , const char * prependFormat , . . . ) {
2016-07-18 16:39:37 +00:00
FMT_TO_RESULT ( prependFormat , prependFormat , prepend ) ;
__testlib_expectedButFound ( result , double ( expected ) , double ( found ) , prepend . c_str ( ) ) ;
}
2022-10-10 06:43:01 +00:00
template < >
2016-07-18 16:39:37 +00:00
# ifdef __GNUC__
__attribute__ ( ( format ( printf , 4 , 5 ) ) )
# endif
2022-10-10 06:43:01 +00:00
NORETURN void
expectedButFound < long double > ( TResult result , long double expected , long double found , const char * prependFormat , . . . ) {
2016-07-18 16:39:37 +00:00
FMT_TO_RESULT ( prependFormat , prependFormat , prepend ) ;
__testlib_expectedButFound ( result , double ( expected ) , double ( found ) , prepend . c_str ( ) ) ;
}
2022-10-10 06:43:01 +00:00
# if __cplusplus > 199711L || defined(_MSC_VER)
template < typename T >
struct is_iterable {
template < typename U >
static char test ( typename U : : iterator * x ) ;
template < typename U >
static long test ( U * x ) ;
static const bool value = sizeof ( test < T > ( 0 ) ) = = 1 ;
} ;
template < bool B , class T = void >
struct __testlib_enable_if {
} ;
template < class T >
struct __testlib_enable_if < true , T > {
typedef T type ;
} ;
template < typename T >
typename __testlib_enable_if < ! is_iterable < T > : : value , void > : : type __testlib_print_one ( const T & t ) {
std : : cout < < t ;
}
template < typename T >
typename __testlib_enable_if < is_iterable < T > : : value , void > : : type __testlib_print_one ( const T & t ) {
bool first = true ;
for ( typename T : : const_iterator i = t . begin ( ) ; i ! = t . end ( ) ; i + + ) {
if ( first )
first = false ;
else
std : : cout < < " " ;
std : : cout < < * i ;
}
}
template < >
typename __testlib_enable_if < is_iterable < std : : string > : : value , void > : : type
__testlib_print_one < std : : string > ( const std : : string & t ) {
std : : cout < < t ;
}
template < typename A , typename B >
void __println_range ( A begin , B end ) {
bool first = true ;
for ( B i = B ( begin ) ; i ! = end ; i + + ) {
if ( first )
first = false ;
else
std : : cout < < " " ;
__testlib_print_one ( * i ) ;
}
std : : cout < < std : : endl ;
}
template < class T , class Enable = void >
struct is_iterator {
static T makeT ( ) ;
typedef void * twoptrs [ 2 ] ;
static twoptrs & test ( . . . ) ;
template < class R >
static typename R : : iterator_category * test ( R ) ;
template < class R >
static void * test ( R * ) ;
static const bool value = sizeof ( test ( makeT ( ) ) ) = = sizeof ( void * ) ;
} ;
template < class T >
struct is_iterator < T , typename __testlib_enable_if < std : : is_array < T > : : value > : : type > {
static const bool value = false ;
} ;
template < typename A , typename B >
typename __testlib_enable_if < ! is_iterator < B > : : value , void > : : type println ( const A & a , const B & b ) {
__testlib_print_one ( a ) ;
std : : cout < < " " ;
__testlib_print_one ( b ) ;
std : : cout < < std : : endl ;
}
template < typename A , typename B >
typename __testlib_enable_if < is_iterator < B > : : value , void > : : type println ( const A & a , const B & b ) {
__println_range ( a , b ) ;
}
template < typename A >
void println ( const A * a , const A * b ) {
__println_range ( a , b ) ;
}
template < >
void println < char > ( const char * a , const char * b ) {
__testlib_print_one ( a ) ;
std : : cout < < " " ;
__testlib_print_one ( b ) ;
std : : cout < < std : : endl ;
}
template < typename T >
void println ( const T & x ) {
__testlib_print_one ( x ) ;
std : : cout < < std : : endl ;
}
template < typename A , typename B , typename C >
void println ( const A & a , const B & b , const C & c ) {
__testlib_print_one ( a ) ;
std : : cout < < " " ;
__testlib_print_one ( b ) ;
std : : cout < < " " ;
__testlib_print_one ( c ) ;
std : : cout < < std : : endl ;
}
template < typename A , typename B , typename C , typename D >
void println ( const A & a , const B & b , const C & c , const D & d ) {
__testlib_print_one ( a ) ;
std : : cout < < " " ;
__testlib_print_one ( b ) ;
std : : cout < < " " ;
__testlib_print_one ( c ) ;
std : : cout < < " " ;
__testlib_print_one ( d ) ;
std : : cout < < std : : endl ;
}
template < typename A , typename B , typename C , typename D , typename E >
void println ( const A & a , const B & b , const C & c , const D & d , const E & e ) {
__testlib_print_one ( a ) ;
std : : cout < < " " ;
__testlib_print_one ( b ) ;
std : : cout < < " " ;
__testlib_print_one ( c ) ;
std : : cout < < " " ;
__testlib_print_one ( d ) ;
std : : cout < < " " ;
__testlib_print_one ( e ) ;
std : : cout < < std : : endl ;
}
template < typename A , typename B , typename C , typename D , typename E , typename F >
void println ( const A & a , const B & b , const C & c , const D & d , const E & e , const F & f ) {
__testlib_print_one ( a ) ;
std : : cout < < " " ;
__testlib_print_one ( b ) ;
std : : cout < < " " ;
__testlib_print_one ( c ) ;
std : : cout < < " " ;
__testlib_print_one ( d ) ;
std : : cout < < " " ;
__testlib_print_one ( e ) ;
std : : cout < < " " ;
__testlib_print_one ( f ) ;
std : : cout < < std : : endl ;
}
template < typename A , typename B , typename C , typename D , typename E , typename F , typename G >
void println ( const A & a , const B & b , const C & c , const D & d , const E & e , const F & f , const G & g ) {
__testlib_print_one ( a ) ;
std : : cout < < " " ;
__testlib_print_one ( b ) ;
std : : cout < < " " ;
__testlib_print_one ( c ) ;
std : : cout < < " " ;
__testlib_print_one ( d ) ;
std : : cout < < " " ;
__testlib_print_one ( e ) ;
std : : cout < < " " ;
__testlib_print_one ( f ) ;
std : : cout < < " " ;
__testlib_print_one ( g ) ;
std : : cout < < std : : endl ;
}
/* opts */
size_t getOptType ( char * s ) {
if ( ! s | | strlen ( s ) < = 1 )
return 0 ;
if ( s [ 0 ] = = ' - ' ) {
if ( isalpha ( s [ 1 ] ) )
return 1 ;
else if ( s [ 1 ] = = ' - ' )
return isalpha ( s [ 2 ] ) ? 2 : 0 ;
}
return 0 ;
}
size_t parseOpt ( size_t argc , char * argv [ ] , size_t index , std : : map < std : : string , std : : string > & opts ) {
if ( index > = argc )
return 0 ;
size_t type = getOptType ( argv [ index ] ) , inc = 1 ;
if ( type > 0 ) {
std : : string key ( argv [ index ] + type ) , val ;
size_t sep = key . find ( ' = ' ) ;
if ( sep ! = std : : string : : npos ) {
val = key . substr ( sep + 1 ) ;
key = key . substr ( 0 , sep ) ;
} else {
if ( index + 1 < argc & & getOptType ( argv [ index + 1 ] ) = = 0 ) {
val = argv [ index + 1 ] ;
inc = 2 ;
} else {
if ( key . length ( ) > 1 & & isdigit ( key [ 1 ] ) ) {
val = key . substr ( 1 ) ;
key = key . substr ( 0 , 1 ) ;
} else {
val = " true " ;
}
}
}
opts [ key ] = val ;
} else {
return inc ;
}
return inc ;
}
std : : vector < std : : string > __testlib_argv ;
std : : map < std : : string , std : : string > __testlib_opts ;
void prepareOpts ( int argc , char * argv [ ] ) {
if ( argc < = 0 )
__testlib_fail ( " Opts: expected argc>=0 but found " + toString ( argc ) ) ;
size_t n = static_cast < size_t > ( argc ) ; // NOLINT(hicpp-use-auto,modernize-use-auto)
__testlib_opts = std : : map < std : : string , std : : string > ( ) ;
for ( size_t index = 1 ; index < n ; index + = parseOpt ( n , argv , index , __testlib_opts ) ) ;
__testlib_argv = std : : vector < std : : string > ( n ) ;
for ( size_t index = 0 ; index < n ; index + + )
__testlib_argv [ index ] = argv [ index ] ;
}
std : : string __testlib_indexToArgv ( int index ) {
if ( index < 0 | | index > = int ( __testlib_argv . size ( ) ) )
__testlib_fail ( " Opts: index ' " + toString ( index ) + " ' is out of range [0, " + toString ( __testlib_argv . size ( ) ) + " ) " ) ;
return __testlib_argv [ size_t ( index ) ] ;
}
std : : string __testlib_keyToOpts ( const std : : string & key ) {
if ( __testlib_opts . count ( key ) = = 0 )
__testlib_fail ( " Opts: unknown key ' " + compress ( key ) + " ' " ) ;
return __testlib_opts [ key ] ;
}
template < typename T >
T optValueToIntegral ( const std : : string & s , bool nonnegative ) ;
long double optValueToLongDouble ( const std : : string & s ) ;
std : : string parseExponentialOptValue ( const std : : string & s ) {
size_t pos = std : : string : : npos ;
for ( size_t i = 0 ; i < s . length ( ) ; i + + )
if ( s [ i ] = = ' e ' | | s [ i ] = = ' E ' ) {
if ( pos ! = std : : string : : npos )
__testlib_fail ( " Opts: expected typical exponential notation but ' " + compress ( s ) + " ' found " ) ;
pos = i ;
}
if ( pos = = std : : string : : npos )
return s ;
std : : string e = s . substr ( pos + 1 ) ;
if ( ! e . empty ( ) & & e [ 0 ] = = ' + ' )
e = e . substr ( 1 ) ;
if ( e . empty ( ) )
__testlib_fail ( " Opts: expected typical exponential notation but ' " + compress ( s ) + " ' found " ) ;
if ( e . length ( ) > 20 )
__testlib_fail ( " Opts: expected typical exponential notation but ' " + compress ( s ) + " ' found " ) ;
int ne = optValueToIntegral < int > ( e , false ) ;
std : : string num = s . substr ( 0 , pos ) ;
if ( num . length ( ) > 20 )
__testlib_fail ( " Opts: expected typical exponential notation but ' " + compress ( s ) + " ' found " ) ;
if ( ! num . empty ( ) & & num [ 0 ] = = ' + ' )
num = num . substr ( 1 ) ;
optValueToLongDouble ( num ) ;
bool minus = false ;
if ( num [ 0 ] = = ' - ' ) {
minus = true ;
num = num . substr ( 1 ) ;
}
for ( int i = 0 ; i < + ne ; i + + ) {
size_t sep = num . find ( ' . ' ) ;
if ( sep = = std : : string : : npos )
num + = ' 0 ' ;
else {
if ( sep + 1 = = num . length ( ) )
num [ sep ] = ' 0 ' ;
else
std : : swap ( num [ sep ] , num [ sep + 1 ] ) ;
}
}
for ( int i = 0 ; i < - ne ; i + + ) {
size_t sep = num . find ( ' . ' ) ;
if ( sep = = std : : string : : npos )
num . insert ( num . begin ( ) + int ( num . length ( ) ) - 1 , ' . ' ) ;
else {
if ( sep = = 0 )
num . insert ( num . begin ( ) + 1 , ' 0 ' ) ;
else
std : : swap ( num [ sep - 1 ] , num [ sep ] ) ;
}
}
while ( ! num . empty ( ) & & num [ 0 ] = = ' 0 ' )
num = num . substr ( 1 ) ;
while ( num . find ( ' . ' ) ! = std : : string : : npos & & num . back ( ) = = ' 0 ' )
num = num . substr ( 0 , num . length ( ) - 1 ) ;
if ( ! num . empty ( ) & & num . back ( ) = = ' . ' )
num = num . substr ( 0 , num . length ( ) - 1 ) ;
if ( ( ! num . empty ( ) & & num [ 0 ] = = ' . ' ) | | num . empty ( ) )
num . insert ( num . begin ( ) , ' 0 ' ) ;
return ( minus ? " - " : " " ) + num ;
}
template < typename T >
T optValueToIntegral ( const std : : string & s_ , bool nonnegative ) {
std : : string s ( parseExponentialOptValue ( s_ ) ) ;
if ( s . empty ( ) )
__testlib_fail ( " Opts: expected integer but ' " + compress ( s_ ) + " ' found " ) ;
T value = 0 ;
long double about = 0.0 ;
signed char sign = + 1 ;
size_t pos = 0 ;
if ( s [ pos ] = = ' - ' ) {
if ( nonnegative )
__testlib_fail ( " Opts: expected non-negative integer but ' " + compress ( s_ ) + " ' found " ) ;
sign = - 1 ;
pos + + ;
}
for ( size_t i = pos ; i < s . length ( ) ; i + + ) {
if ( s [ i ] < ' 0 ' | | s [ i ] > ' 9 ' )
__testlib_fail ( " Opts: expected integer but ' " + compress ( s_ ) + " ' found " ) ;
value = value * 10 + s [ i ] - ' 0 ' ;
about = about * 10 + s [ i ] - ' 0 ' ;
}
value * = sign ;
about * = sign ;
if ( fabsl ( value - about ) > 0.1 )
__testlib_fail ( " Opts: integer overflow: expected integer but ' " + compress ( s_ ) + " ' found " ) ;
return value ;
}
long double optValueToLongDouble ( const std : : string & s_ ) {
std : : string s ( parseExponentialOptValue ( s_ ) ) ;
if ( s . empty ( ) )
__testlib_fail ( " Opts: expected float number but ' " + compress ( s_ ) + " ' found " ) ;
long double value = 0.0 ;
signed char sign = + 1 ;
size_t pos = 0 ;
if ( s [ pos ] = = ' - ' ) {
sign = - 1 ;
pos + + ;
}
bool period = false ;
long double mul = 1.0 ;
for ( size_t i = pos ; i < s . length ( ) ; i + + ) {
if ( s [ i ] = = ' . ' ) {
if ( period )
__testlib_fail ( " Opts: expected float number but ' " + compress ( s_ ) + " ' found " ) ;
else {
period = true ;
continue ;
}
}
if ( period )
mul * = 10.0 ;
if ( s [ i ] < ' 0 ' | | s [ i ] > ' 9 ' )
__testlib_fail ( " Opts: expected float number but ' " + compress ( s_ ) + " ' found " ) ;
if ( period )
value + = ( s [ i ] - ' 0 ' ) / mul ;
else
value = value * 10 + s [ i ] - ' 0 ' ;
}
value * = sign ;
return value ;
}
bool has_opt ( const std : : string key ) {
return __testlib_opts . count ( key ) ! = 0 ;
}
template < typename T >
T opt ( std : : false_type , int index ) ;
template < >
std : : string opt ( std : : false_type , int index ) {
return __testlib_indexToArgv ( index ) ;
}
template < typename T >
T opt ( std : : true_type , int index ) {
return T ( optValueToLongDouble ( __testlib_indexToArgv ( index ) ) ) ;
}
template < typename T , typename U >
T opt ( std : : false_type , U , int index ) {
return opt < T > ( std : : is_floating_point < T > ( ) , index ) ;
}
template < typename T >
T opt ( std : : true_type , std : : false_type , int index ) {
return optValueToIntegral < T > ( __testlib_indexToArgv ( index ) , false ) ;
}
template < typename T >
T opt ( std : : true_type , std : : true_type , int index ) {
return optValueToIntegral < T > ( __testlib_indexToArgv ( index ) , true ) ;
}
template < >
bool opt ( std : : true_type , std : : true_type , int index ) {
std : : string value = __testlib_indexToArgv ( index ) ;
if ( value = = " true " | | value = = " 1 " )
return true ;
if ( value = = " false " | | value = = " 0 " )
return false ;
__testlib_fail ( " Opts: opt by index ' " + toString ( index ) + " ': expected bool true/false or 0/1 but ' " + compress ( value ) + " ' found " ) ;
}
template < typename T >
T opt ( int index ) {
return opt < T > ( std : : is_integral < T > ( ) , std : : is_unsigned < T > ( ) , index ) ;
}
std : : string opt ( int index ) {
return opt < std : : string > ( index ) ;
}
template < typename T >
T opt ( std : : false_type , const std : : string & key ) ;
template < >
std : : string opt ( std : : false_type , const std : : string & key ) {
return __testlib_keyToOpts ( key ) ;
}
template < typename T >
T opt ( std : : true_type , const std : : string & key ) {
return T ( optValueToLongDouble ( __testlib_keyToOpts ( key ) ) ) ;
}
template < typename T , typename U >
T opt ( std : : false_type , U , const std : : string & key ) {
return opt < T > ( std : : is_floating_point < T > ( ) , key ) ;
}
template < typename T >
T opt ( std : : true_type , std : : false_type , const std : : string & key ) {
return optValueToIntegral < T > ( __testlib_keyToOpts ( key ) , false ) ;
}
template < typename T >
T opt ( std : : true_type , std : : true_type , const std : : string & key ) {
return optValueToIntegral < T > ( __testlib_keyToOpts ( key ) , true ) ;
}
template < >
bool opt ( std : : true_type , std : : true_type , const std : : string & key ) {
if ( ! has_opt ( key ) )
return false ;
std : : string value = __testlib_keyToOpts ( key ) ;
if ( value = = " true " | | value = = " 1 " )
return true ;
if ( value = = " false " | | value = = " 0 " )
return false ;
__testlib_fail ( " Opts: key ' " + compress ( key ) + " ': expected bool true/false or 0/1 but ' " + compress ( value ) + " ' found " ) ;
}
template < typename T >
T opt ( const std : : string key ) {
return opt < T > ( std : : is_integral < T > ( ) , std : : is_unsigned < T > ( ) , key ) ;
}
std : : string opt ( const std : : string key ) {
return opt < std : : string > ( key ) ;
}
# endif
2016-07-18 16:39:37 +00:00
# endif