//=============================================================================
// performance.h --------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#define CSTR // constructor place holder
#define DSTR // destructor place holder
#define _____ // place holder
using i8 = char;
using u8 = unsigned char;
using i16 = short;
using u16 = unsigned short;
using i32 = int;
using i64 = long long;
using u32 = unsigned int;
using u64 = unsigned long long;
using f32 = float;
using f64 = double;
#ifdef _MSC_VER
#include <intrin.h>
#else
#include <x86intrin.h>
#define CHAR_BIT 8
#endif
#define SYS_BITS ( sizeof( size_t ) * CHAR_BIT )
//-----------------------------------------------------------------------------
class RUNNER
{
private:
const char* function_name;
u64 elapsed;
protected:
bool is_success;
public:
CSTR RUNNER
(
const char* function_name,
void( *on_pre )( ),
void( *on_run )( ),
bool( *on_post )( )
)
: function_name( function_name )
, on_pre( on_pre )
, on_run( on_run )
, on_post( on_post )
{
init();
}
DSTR virtual ~RUNNER()
{};
virtual void init()
{
elapsed = -1;
is_success = on_run != NULL;
}
void( *on_pre )( );
void( *on_run )( );
bool( *on_post )( );
void check()
{
if( !on_run )
return;
if( on_pre )
on_pre();
u64 begin = __rdtsc();
on_run();
u64 duration = __rdtsc() - begin;
elapsed = std::min( elapsed, duration );
if( on_post )
is_success &= on_post();
}
const auto set_length( const char* str, const size_t size )
{
static char temp[ 80 ];
size_t index;
for( index = 0; str[ index ]; ++index ) temp[ index ] = str[ index ];
for( ; index < size; ++index ) temp[ index ] = ' ';
temp[ index ] = 0;
return temp;
}
const auto report()
{
const char* judge_strings[] = { " FAILED ", " PASSED " };
static char temp[ 80 ];
sprintf( temp, "[%s] %s %15llu clocks", judge_strings[ is_success ],
set_length( function_name, 20 ), elapsed );
return temp;
}
const auto elapsed_clocks()
{
return elapsed;
}
const auto name()
{
return function_name;
}
};
//-----------------------------------------------------------------------------
#include <vector>
template < size_t REPEAT_COUNT = 1 >
class BENCH
{
private:
std::vector< RUNNER* > runner_list;
public:
CSTR BENCH()
{};
DSTR ~BENCH()
{};
void add( RUNNER* runner )
{
runner_list.push_back( runner );
}
void run()
{
if( runner_list.size() == 0 ) return;
printf( "< %d bits > %d trials", (int)SYS_BITS, (int)REPEAT_COUNT );
puts( "" );
puts( "-------------------------------------------------------------" );
puts( "| CHECKER | Function name | minimum clocks |" );
puts( "-------------------------------------------------------------" );
u64 min_value = -1;
u64 max_value = 0;
u32 min_index = 0;
u32 max_index = 0;
for( u32 test_case = 0; test_case < runner_list.size(); ++test_case )
{
runner_list[ test_case ]->init();
for( u32 test_count = 0; test_count < REPEAT_COUNT; ++test_count )
runner_list[ test_case ]->check();
puts( runner_list[ test_case ]->report() );
if( min_value > runner_list[ test_case ]->elapsed_clocks() )
{
min_index = test_case;
min_value = runner_list[ test_case ]->elapsed_clocks();
}
if( max_value < runner_list[ test_case ]->elapsed_clocks() )
{
max_index = test_case;
max_value = runner_list[ test_case ]->elapsed_clocks();
}
}
puts( "-------------------------------------------------------------" );
printf( "Winner is %s ( %.2f times faster than loooser )",
runner_list[ min_index ]->name(),
float( runner_list[ max_index ]->elapsed_clocks() ) /
runner_list[ min_index ]->elapsed_clocks() );
puts( "" );
}
};
//-----------------------------------------------------------------------------
#define COOL_FUN( function_name, ... ) \
new RUNNER( #function_name, nil, []{ function_name(__VA_ARGS__); }, nil )
#define SO_FUN( pre, function_name, ... ) \
new RUNNER( #function_name, pre, []{ function_name(__VA_ARGS__); }, nil )
#define FUN( pre, run, post, function_name ) \
new RUNNER( #function_name, pre, run, post )
//=============================================================================
// kukyakya
#include <memory>
#include <cassert>
using byte = char;
using word = std::size_t;
word merge_word( const word& w1, const word& w2, std::size_t byte_offset )
{
assert( byte_offset && ( byte_offset < sizeof( word ) ) );
const std::size_t shift_1 = CHAR_BIT * byte_offset;
const std::size_t shift_2 = CHAR_BIT * sizeof( word ) - shift_1;
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
return ( w1 >> shift_1 ) | ( w2 << shift_2 );
#else
return ( w1 << shift_1 ) | ( w2 >> shift_2 );
#endif // __BYTE_ORDER
}
std::size_t get_byte_offset( const word* ptr )
{
void *p = (void*)ptr;
std::size_t sz = -1;
std::align( alignof( word ), 0, p, sz );
const auto diff = (char*)p - (char*)ptr;
return ( diff == 0 ) ? 0 : ( sizeof( word ) - diff );
}
byte* copy_byte( byte* dest, const byte* src, std::size_t n_byte )
{
// Don't fuck with loop-unrolling, just trust your compiler
while( n_byte-- )
*dest++ = *src++;
return dest;
}
word* copy_word_both_aligned( word* dest, const word* src, std::size_t n_word )
{
/* */ word* d = (word*)dest;
const word* s = (const word*)src;
while( n_word-- )
*d++ = *s++;
return dest;
}
// src is not aligned
word* copy_word_dest_aligned( word* dest, const word* src, std::size_t n_word )
{
word *d = dest;
const word *s = src;
// get byte-offset of src
std::size_t src_offset = get_byte_offset( s );
// if src is aligned, call copy_word_both_aligned
if( src_offset == 0 )
{
return copy_word_both_aligned( d, s, n_word );
}
const word* aligned_src = (const word*)( (char*)s - src_offset );
assert( get_byte_offset( aligned_src ) == 0 );
word buf = *aligned_src++;
while( n_word-- )
{
word buf2 = *aligned_src++;
*d++ = merge_word( buf, buf2, src_offset );
buf = buf2;
}
return dest;
}
void *kukyakya_memcpy( void* dest, const void* src, std::size_t n )
{
/* */ void* d = dest;
const void* s = src;
std::size_t sz = n;
if( !std::align( alignof( word ), 0, d, sz ) )
{
return copy_byte( (byte*)dest, (const byte*)src, n );
}
s = (const byte*)s + ( n - sz );
// byte copy until dest is aligned
copy_byte( (byte*)dest, (const byte*)src, n - sz );
// copy words
const std::size_t n_word = sz / sizeof( word );
copy_word_dest_aligned( (word*)d, (const word*)s, n_word );
d = /* */ (word*)d + n_word;
s = (const word*)s + n_word;
sz -= sizeof( word ) * n_word;
// copy remaining bytes
copy_byte( (byte*)d, (const byte*)s, sz );
return dest;
}
void *kukyakya_memcpy_unaligned( void* dest, const void* src, std::size_t n_byte )
{
/* */ word *d = (/* */ word*)dest;
const word* s = (const word*)src;
// copy word
const std::size_t n_word = n_byte / sizeof( word );
copy_word_both_aligned( d, s, n_word );
d += n_word;
s += n_word;
n_byte -= n_word * sizeof( word );
// copy remaining bytes
copy_byte( (byte*)d, (const byte*)s, n_byte );
return dest;
}
void *my_memcpy_byte_only( void* dest, const void* src, std::size_t n )
{
return copy_byte( (byte*)dest, (const byte*)src, n );
}
//-----------------------------------------------------------------------------
void* codesafer_memcpy_unaligned1( void* dst, const void* src, std::size_t size )
{
using step_t = u32;
_____ step_t* d = (step_t*)dst;
const step_t* s = (step_t*)src;
const std::size_t step_count = size / sizeof(step_t);
const u32 off_road = size % sizeof(step_t);
for( std::size_t i = 0; i < step_count; ++i )
d[i] = s[i];
u8* db = (u8*)( d + step_count );
u8* sb = (u8*)( s + step_count );
for( u32 i = 0; i < off_road; ++i )
db[i] = sb[i];
return dst;
}
//=============================================================================
// test case
const int test_count = 1000;
const int test_size = 1000000;
#ifdef _MSC_VER
__declspec( align( 4 ) ) char src[ test_size + 4 ];
__declspec( align( 4 ) ) char dst[ test_size + 4 ];
#else
char src[ test_size + 4 ] __attribute__((aligned(4)));
char dst[ test_size + 4 ] __attribute__((aligned(4)));
#endif
int result1, result2, result3, result4;
void init()
{
}
void pre()
{
}
void test1()
{
result1 += (int)kukyakya_memcpy( dst + 1, src + 3, test_size );
}
void test2()
{
result2 += (int)kukyakya_memcpy_unaligned( dst + 1, src + 3, test_size );
}
void test3()
{
result3 += (int)memcpy( dst + 1, src + 3, test_size );
}
void test4()
{
result4 += (int)codesafer_memcpy_unaligned1( dst + 1, src + 3, test_size );
}
bool post()
{
return true;
}
//-----------------------------------------------------------------------------
#include <iostream>
using namespace std;
int main()
{
init();
BENCH< test_count > bench;
bench.add( FUN( pre, test1, post, kukyakya_aligned ) );
bench.add( FUN( pre, test2, post, kukyakya_unaligned ) );
bench.add( FUN( pre, test3, post, std_memcpy ) );
bench.add( FUN( pre, test4, post, codesafer_unaligned1 ) );
bench.run();
getchar();
return 0;
}
//-----------------------------------------------------------------------------
Ly89PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQovLyBwZXJmb3JtYW5jZS5oIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojaW5jbHVkZSA8c3RkaW8uaD4KI2luY2x1ZGUgPHN0ZGxpYi5oPgojaW5jbHVkZSA8c3RyaW5nLmg+CiNpbmNsdWRlIDxhbGdvcml0aG0+CgojZGVmaW5lIENTVFIgICAgLy8gY29uc3RydWN0b3IgcGxhY2UgaG9sZGVyCiNkZWZpbmUgRFNUUiAgICAvLyBkZXN0cnVjdG9yIHBsYWNlIGhvbGRlcgojZGVmaW5lIF9fX19fICAgLy8gcGxhY2UgaG9sZGVyCgp1c2luZyAgIGk4ICA9IGNoYXI7CnVzaW5nICAgdTggID0gdW5zaWduZWQgY2hhcjsKdXNpbmcgICBpMTYgPSBzaG9ydDsKdXNpbmcgICB1MTYgPSB1bnNpZ25lZCBzaG9ydDsKdXNpbmcgICBpMzIgPSBpbnQ7CnVzaW5nICAgaTY0ID0gbG9uZyBsb25nOwp1c2luZyAgIHUzMiA9IHVuc2lnbmVkIGludDsKdXNpbmcgICB1NjQgPSB1bnNpZ25lZCBsb25nIGxvbmc7CnVzaW5nICAgZjMyID0gZmxvYXQ7CnVzaW5nICAgZjY0ID0gZG91YmxlOwoKI2lmZGVmIF9NU0NfVkVSCiNpbmNsdWRlIDxpbnRyaW4uaD4KI2Vsc2UKI2luY2x1ZGUgPHg4NmludHJpbi5oPgojZGVmaW5lIENIQVJfQklUCQkJCTgKI2VuZGlmCgojZGVmaW5lIFNZU19CSVRTICAgICggc2l6ZW9mKCBzaXplX3QgKSAqIENIQVJfQklUICkKCi8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCmNsYXNzICAgICAgICAgICAgICAgICAgICAgICAgICAgUlVOTkVSCnsKcHJpdmF0ZToKICAgIGNvbnN0ICAgY2hhciogICAgICAgICAgICAgICBmdW5jdGlvbl9uYW1lOwogICAgdTY0ICAgICAgICAgICAgICAgICAgICAgICAgIGVsYXBzZWQ7Cgpwcm90ZWN0ZWQ6CiAgICBib29sICAgICAgICAgICAgICAgICAgICAgICAgaXNfc3VjY2VzczsKCnB1YmxpYzoKICAgIENTVFIgICAgICAgICAgICAgICAgICAgICAgICBSVU5ORVIKICAgICAgICAoCiAgICAgICAgICAgIGNvbnN0IGNoYXIqIGZ1bmN0aW9uX25hbWUsCiAgICAgICAgICAgIHZvaWQoICpvbl9wcmUgKSggKSwKICAgICAgICAgICAgdm9pZCggKm9uX3J1biApKCApLAogICAgICAgICAgICBib29sKCAqb25fcG9zdCApKCApCiAgICAgICAgICAgICkKICAgICAgICA6IGZ1bmN0aW9uX25hbWUoIGZ1bmN0aW9uX25hbWUgKQogICAgICAgICwgb25fcHJlKCBvbl9wcmUgKQogICAgICAgICwgb25fcnVuKCBvbl9ydW4gKQogICAgICAgICwgb25fcG9zdCggb25fcG9zdCApCiAgICB7CiAgICAgICAgaW5pdCgpOwogICAgfQogICAgRFNUUiAgICB2aXJ0dWFsICAgICAgICAgICAgflJVTk5FUigpCiAgICB7fTsKCiAgICB2aXJ0dWFsIHZvaWQgICAgICAgICAgICAgICAgaW5pdCgpCiAgICB7CiAgICAgICAgZWxhcHNlZCA9IC0xOwogICAgICAgIGlzX3N1Y2Nlc3MgPSBvbl9ydW4gIT0gTlVMTDsKICAgIH0KCiAgICB2b2lkKCAqb25fcHJlICkoICk7CiAgICB2b2lkKCAqb25fcnVuICkoICk7CiAgICBib29sKCAqb25fcG9zdCApKCApOwoKICAgIHZvaWQgICAgICAgICAgICAgICAgICAgICAgICBjaGVjaygpCiAgICB7CiAgICAgICAgaWYoICFvbl9ydW4gKQogICAgICAgICAgICByZXR1cm47CiAgICAgICAgaWYoIG9uX3ByZSApCiAgICAgICAgICAgIG9uX3ByZSgpOwoKICAgICAgICB1NjQgICAgIGJlZ2luID0gX19yZHRzYygpOwogICAgICAgIG9uX3J1bigpOwogICAgICAgIHU2NCAgICAgZHVyYXRpb24gPSBfX3JkdHNjKCkgLSBiZWdpbjsKICAgICAgICBlbGFwc2VkID0gc3RkOjptaW4oIGVsYXBzZWQsIGR1cmF0aW9uICk7CgogICAgICAgIGlmKCBvbl9wb3N0ICkKICAgICAgICAgICAgaXNfc3VjY2VzcyAmPSBvbl9wb3N0KCk7CiAgICB9CiAgICBjb25zdCAgIGF1dG8gICAgICAgICAgICAgICAgc2V0X2xlbmd0aCggY29uc3QgY2hhciogc3RyLCBjb25zdCBzaXplX3Qgc2l6ZSApCiAgICB7CiAgICAgICAgc3RhdGljICBjaGFyICAgIHRlbXBbIDgwIF07CiAgICAgICAgc2l6ZV90ICAgICAgICAgIGluZGV4OwogICAgICAgIGZvciggaW5kZXggPSAwOyBzdHJbIGluZGV4IF07ICsraW5kZXggKSB0ZW1wWyBpbmRleCBdID0gc3RyWyBpbmRleCBdOwogICAgICAgIGZvciggOyBpbmRleCA8IHNpemU7ICsraW5kZXggKSB0ZW1wWyBpbmRleCBdID0gJyAnOwogICAgICAgIHRlbXBbIGluZGV4IF0gPSAwOwogICAgICAgIHJldHVybiAgdGVtcDsKICAgIH0KICAgIGNvbnN0ICAgYXV0byAgICAgICAgICAgICAgICByZXBvcnQoKQogICAgewogICAgICAgIGNvbnN0ICAgY2hhcioganVkZ2Vfc3RyaW5nc1tdID0geyAiIEZBSUxFRCAgICAgICAgIiwgIiAgICAgICAgUEFTU0VEICIgfTsKICAgICAgICBzdGF0aWMgIGNoYXIgdGVtcFsgODAgXTsKICAgICAgICBzcHJpbnRmKCB0ZW1wLCAiWyVzXSAlcyAlMTVsbHUgY2xvY2tzIiwganVkZ2Vfc3RyaW5nc1sgaXNfc3VjY2VzcyBdLAogICAgICAgICAgICAgICAgIHNldF9sZW5ndGgoIGZ1bmN0aW9uX25hbWUsIDIwICksIGVsYXBzZWQgKTsKICAgICAgICByZXR1cm4gIHRlbXA7CiAgICB9CiAgICBjb25zdCAgIGF1dG8gICAgICAgICAgICAgICAgZWxhcHNlZF9jbG9ja3MoKQogICAgewogICAgICAgIHJldHVybiAgZWxhcHNlZDsKICAgIH0KICAgIGNvbnN0ICAgYXV0byAgICAgICAgICAgICAgICBuYW1lKCkKICAgIHsKICAgICAgICByZXR1cm4gIGZ1bmN0aW9uX25hbWU7CiAgICB9Cgp9OwovLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojaW5jbHVkZSA8dmVjdG9yPgp0ZW1wbGF0ZSA8IHNpemVfdCBSRVBFQVRfQ09VTlQgPSAxID4KY2xhc3MgICAgICAgICAgICAgICAgICAgICAgICAgICBCRU5DSAp7CnByaXZhdGU6CiAgICBzdGQ6OnZlY3RvcjwgUlVOTkVSKiA+ICAgICAgcnVubmVyX2xpc3Q7CgpwdWJsaWM6CiAgICBDU1RSICAgICAgICAgICAgICAgICAgICAgICAgQkVOQ0goKQogICAge307CiAgICBEU1RSICAgICAgICAgICAgICAgICAgICAgICB+QkVOQ0goKQogICAge307CgogICAgdm9pZCAgICAgICAgICAgICAgICAgICAgICAgIGFkZCggUlVOTkVSKiBydW5uZXIgKQogICAgewogICAgICAgIHJ1bm5lcl9saXN0LnB1c2hfYmFjayggcnVubmVyICk7CiAgICB9CgogICAgdm9pZCAgICAgICAgICAgICAgICAgICAgICAgIHJ1bigpCiAgICB7CiAgICAgICAgaWYoIHJ1bm5lcl9saXN0LnNpemUoKSA9PSAwICkgcmV0dXJuOwogICAgICAgIHByaW50ZiggIjwgJWQgYml0cyA+ICVkIHRyaWFscyIsIChpbnQpU1lTX0JJVFMsIChpbnQpUkVQRUFUX0NPVU5UICk7CiAgICAgICAgcHV0cyggIiIgKTsKICAgICAgICBwdXRzKCAiLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSIgKTsKICAgICAgICBwdXRzKCAifCAgQ0hFQ0tFUiAgICAgIHwgRnVuY3Rpb24gIG5hbWUgICAgICB8ICAgbWluaW11bSAgY2xvY2tzICAgfCIgKTsKICAgICAgICBwdXRzKCAiLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSIgKTsKICAgICAgICB1NjQgbWluX3ZhbHVlID0gLTE7CiAgICAgICAgdTY0IG1heF92YWx1ZSA9IDA7CiAgICAgICAgdTMyIG1pbl9pbmRleCA9IDA7CiAgICAgICAgdTMyIG1heF9pbmRleCA9IDA7CiAgICAgICAgZm9yKCB1MzIgdGVzdF9jYXNlID0gMDsgdGVzdF9jYXNlIDwgcnVubmVyX2xpc3Quc2l6ZSgpOyArK3Rlc3RfY2FzZSApCiAgICAgICAgewogICAgICAgICAgICBydW5uZXJfbGlzdFsgdGVzdF9jYXNlIF0tPmluaXQoKTsKICAgICAgICAgICAgZm9yKCB1MzIgdGVzdF9jb3VudCA9IDA7IHRlc3RfY291bnQgPCBSRVBFQVRfQ09VTlQ7ICsrdGVzdF9jb3VudCApCiAgICAgICAgICAgICAgICBydW5uZXJfbGlzdFsgdGVzdF9jYXNlIF0tPmNoZWNrKCk7CiAgICAgICAgICAgIHB1dHMoIHJ1bm5lcl9saXN0WyB0ZXN0X2Nhc2UgXS0+cmVwb3J0KCkgKTsKICAgICAgICAgICAgaWYoIG1pbl92YWx1ZSA+IHJ1bm5lcl9saXN0WyB0ZXN0X2Nhc2UgXS0+ZWxhcHNlZF9jbG9ja3MoKSApCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIG1pbl9pbmRleCA9IHRlc3RfY2FzZTsKICAgICAgICAgICAgICAgIG1pbl92YWx1ZSA9IHJ1bm5lcl9saXN0WyB0ZXN0X2Nhc2UgXS0+ZWxhcHNlZF9jbG9ja3MoKTsKICAgICAgICAgICAgfQogICAgICAgICAgICBpZiggbWF4X3ZhbHVlIDwgcnVubmVyX2xpc3RbIHRlc3RfY2FzZSBdLT5lbGFwc2VkX2Nsb2NrcygpICkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgbWF4X2luZGV4ID0gdGVzdF9jYXNlOwogICAgICAgICAgICAgICAgbWF4X3ZhbHVlID0gcnVubmVyX2xpc3RbIHRlc3RfY2FzZSBdLT5lbGFwc2VkX2Nsb2NrcygpOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHB1dHMoICItLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIiApOwogICAgICAgIHByaW50ZiggIldpbm5lciBpcyAlcyAgKCAlLjJmIHRpbWVzIGZhc3RlciB0aGFuIGxvb29zZXIgKSIsCiAgICAgICAgICAgICAgICBydW5uZXJfbGlzdFsgbWluX2luZGV4IF0tPm5hbWUoKSwKICAgICAgICAgICAgICAgIGZsb2F0KCBydW5uZXJfbGlzdFsgbWF4X2luZGV4IF0tPmVsYXBzZWRfY2xvY2tzKCkgKSAvCiAgICAgICAgICAgICAgICBydW5uZXJfbGlzdFsgbWluX2luZGV4IF0tPmVsYXBzZWRfY2xvY2tzKCkgKTsKICAgICAgICBwdXRzKCAiIiApOwogICAgfQp9OwovLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojZGVmaW5lIENPT0xfRlVOKCBmdW5jdGlvbl9uYW1lLCAuLi4gKSBcCiAgICBuZXcgUlVOTkVSKCAjZnVuY3Rpb25fbmFtZSwgbmlsLCBbXXsgZnVuY3Rpb25fbmFtZShfX1ZBX0FSR1NfXyk7IH0sIG5pbCApCgojZGVmaW5lIFNPX0ZVTiggcHJlLCBmdW5jdGlvbl9uYW1lLCAuLi4gKSBcCiAgICBuZXcgUlVOTkVSKCAjZnVuY3Rpb25fbmFtZSwgcHJlLCBbXXsgZnVuY3Rpb25fbmFtZShfX1ZBX0FSR1NfXyk7IH0sIG5pbCApCgojZGVmaW5lIEZVTiggcHJlLCBydW4sIHBvc3QsIGZ1bmN0aW9uX25hbWUgKSBcCiAgICBuZXcgUlVOTkVSKCAjZnVuY3Rpb25fbmFtZSwgcHJlLCBydW4sIHBvc3QgKQoKLy89PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQovLyBrdWt5YWt5YQoKI2luY2x1ZGUgPG1lbW9yeT4KI2luY2x1ZGUgPGNhc3NlcnQ+Cgp1c2luZyBieXRlID0gY2hhcjsKdXNpbmcgd29yZCA9IHN0ZDo6c2l6ZV90OwoKd29yZCBtZXJnZV93b3JkKCBjb25zdCB3b3JkJiB3MSwgY29uc3Qgd29yZCYgdzIsIHN0ZDo6c2l6ZV90IGJ5dGVfb2Zmc2V0ICkKewogICAgYXNzZXJ0KCBieXRlX29mZnNldCAmJiAoIGJ5dGVfb2Zmc2V0IDwgc2l6ZW9mKCB3b3JkICkgKSApOwoKICAgIGNvbnN0IHN0ZDo6c2l6ZV90IHNoaWZ0XzEgPSBDSEFSX0JJVCAqIGJ5dGVfb2Zmc2V0OwogICAgY29uc3Qgc3RkOjpzaXplX3Qgc2hpZnRfMiA9IENIQVJfQklUICogc2l6ZW9mKCB3b3JkICkgLSBzaGlmdF8xOwoKI2lmIF9fQllURV9PUkRFUl9fID09IF9fT1JERVJfTElUVExFX0VORElBTl9fCiAgICByZXR1cm4gKCB3MSA+PiBzaGlmdF8xICkgfCAoIHcyIDw8IHNoaWZ0XzIgKTsKI2Vsc2UKICAgIHJldHVybiAoIHcxIDw8IHNoaWZ0XzEgKSB8ICggdzIgPj4gc2hpZnRfMiApOwojZW5kaWYgLy8gX19CWVRFX09SREVSCn0KCnN0ZDo6c2l6ZV90IGdldF9ieXRlX29mZnNldCggY29uc3Qgd29yZCogcHRyICkKewogICAgdm9pZCAqcCA9ICh2b2lkKilwdHI7CiAgICBzdGQ6OnNpemVfdCBzeiA9IC0xOwoKICAgIHN0ZDo6YWxpZ24oIGFsaWdub2YoIHdvcmQgKSwgMCwgcCwgc3ogKTsKCiAgICBjb25zdCBhdXRvIGRpZmYgPSAoY2hhciopcCAtIChjaGFyKilwdHI7CgogICAgcmV0dXJuICggZGlmZiA9PSAwICkgPyAwIDogKCBzaXplb2YoIHdvcmQgKSAtIGRpZmYgKTsKfQoKYnl0ZSogY29weV9ieXRlKCBieXRlKiBkZXN0LCBjb25zdCBieXRlKiBzcmMsIHN0ZDo6c2l6ZV90IG5fYnl0ZSApCnsKICAgIC8vIERvbid0IGZ1Y2sgd2l0aCBsb29wLXVucm9sbGluZywganVzdCB0cnVzdCB5b3VyIGNvbXBpbGVyCiAgICB3aGlsZSggbl9ieXRlLS0gKQogICAgICAgICpkZXN0KysgPSAqc3JjKys7CgogICAgcmV0dXJuIGRlc3Q7Cn0KCndvcmQqIGNvcHlfd29yZF9ib3RoX2FsaWduZWQoIHdvcmQqIGRlc3QsIGNvbnN0IHdvcmQqIHNyYywgc3RkOjpzaXplX3Qgbl93b3JkICkKewogICAgLyogKi8gd29yZCogZCA9ICh3b3JkKilkZXN0OwogICAgY29uc3Qgd29yZCogcyA9IChjb25zdCB3b3JkKilzcmM7CiAgICB3aGlsZSggbl93b3JkLS0gKQogICAgICAgICpkKysgPSAqcysrOwoKICAgIHJldHVybiBkZXN0Owp9CgovLyBzcmMgaXMgbm90IGFsaWduZWQKd29yZCogY29weV93b3JkX2Rlc3RfYWxpZ25lZCggd29yZCogZGVzdCwgY29uc3Qgd29yZCogc3JjLCBzdGQ6OnNpemVfdCBuX3dvcmQgKQp7CiAgICB3b3JkICpkID0gZGVzdDsKICAgIGNvbnN0IHdvcmQgKnMgPSBzcmM7CgogICAgLy8gZ2V0IGJ5dGUtb2Zmc2V0IG9mIHNyYwogICAgc3RkOjpzaXplX3Qgc3JjX29mZnNldCA9IGdldF9ieXRlX29mZnNldCggcyApOwoKICAgIC8vIGlmIHNyYyBpcyBhbGlnbmVkLCBjYWxsIGNvcHlfd29yZF9ib3RoX2FsaWduZWQKICAgIGlmKCBzcmNfb2Zmc2V0ID09IDAgKQogICAgewogICAgICAgIHJldHVybiBjb3B5X3dvcmRfYm90aF9hbGlnbmVkKCBkLCBzLCBuX3dvcmQgKTsKICAgIH0KCiAgICBjb25zdCB3b3JkKiBhbGlnbmVkX3NyYyA9IChjb25zdCB3b3JkKikoIChjaGFyKilzIC0gc3JjX29mZnNldCApOwogICAgYXNzZXJ0KCBnZXRfYnl0ZV9vZmZzZXQoIGFsaWduZWRfc3JjICkgPT0gMCApOwoKICAgIHdvcmQgYnVmID0gKmFsaWduZWRfc3JjKys7CiAgICB3aGlsZSggbl93b3JkLS0gKQogICAgewogICAgICAgIHdvcmQgYnVmMiA9ICphbGlnbmVkX3NyYysrOwogICAgICAgICpkKysgPSBtZXJnZV93b3JkKCBidWYsIGJ1ZjIsIHNyY19vZmZzZXQgKTsKICAgICAgICBidWYgPSBidWYyOwogICAgfQoKICAgIHJldHVybiBkZXN0Owp9Cgp2b2lkICprdWt5YWt5YV9tZW1jcHkoIHZvaWQqIGRlc3QsIGNvbnN0IHZvaWQqIHNyYywgc3RkOjpzaXplX3QgbiApCnsKICAgIC8qICovIHZvaWQqIGQgPSBkZXN0OwogICAgY29uc3Qgdm9pZCogcyA9IHNyYzsKICAgIHN0ZDo6c2l6ZV90IHN6ID0gbjsKCiAgICBpZiggIXN0ZDo6YWxpZ24oIGFsaWdub2YoIHdvcmQgKSwgMCwgZCwgc3ogKSApCiAgICB7CiAgICAgICAgcmV0dXJuIGNvcHlfYnl0ZSggKGJ5dGUqKWRlc3QsIChjb25zdCBieXRlKilzcmMsIG4gKTsKICAgIH0KICAgIHMgPSAoY29uc3QgYnl0ZSopcyArICggbiAtIHN6ICk7CgogICAgLy8gYnl0ZSBjb3B5IHVudGlsIGRlc3QgaXMgYWxpZ25lZAogICAgY29weV9ieXRlKCAoYnl0ZSopZGVzdCwgKGNvbnN0IGJ5dGUqKXNyYywgbiAtIHN6ICk7CgogICAgLy8gY29weSB3b3JkcwogICAgY29uc3Qgc3RkOjpzaXplX3Qgbl93b3JkID0gc3ogLyBzaXplb2YoIHdvcmQgKTsKICAgIGNvcHlfd29yZF9kZXN0X2FsaWduZWQoICh3b3JkKilkLCAoY29uc3Qgd29yZCopcywgbl93b3JkICk7CiAgICBkID0gLyogKi8gKHdvcmQqKWQgKyBuX3dvcmQ7CiAgICBzID0gKGNvbnN0IHdvcmQqKXMgKyBuX3dvcmQ7CiAgICBzeiAtPSBzaXplb2YoIHdvcmQgKSAgICogbl93b3JkOwoKICAgIC8vIGNvcHkgcmVtYWluaW5nIGJ5dGVzCiAgICBjb3B5X2J5dGUoIChieXRlKilkLCAoY29uc3QgYnl0ZSopcywgc3ogKTsKCiAgICByZXR1cm4gZGVzdDsKfQoKdm9pZCAqa3VreWFreWFfbWVtY3B5X3VuYWxpZ25lZCggdm9pZCogZGVzdCwgY29uc3Qgdm9pZCogc3JjLCBzdGQ6OnNpemVfdCBuX2J5dGUgKQp7CiAgICAvKiAqLyB3b3JkICpkID0gKC8qICovIHdvcmQqKWRlc3Q7CiAgICBjb25zdCB3b3JkKiBzID0gKGNvbnN0IHdvcmQqKXNyYzsKCiAgICAvLyBjb3B5IHdvcmQKICAgIGNvbnN0IHN0ZDo6c2l6ZV90IG5fd29yZCA9IG5fYnl0ZSAvIHNpemVvZiggd29yZCApOwogICAgY29weV93b3JkX2JvdGhfYWxpZ25lZCggZCwgcywgbl93b3JkICk7CgogICAgZCArPSBuX3dvcmQ7CiAgICBzICs9IG5fd29yZDsKICAgIG5fYnl0ZSAtPSBuX3dvcmQgKiBzaXplb2YoIHdvcmQgKTsKCiAgICAvLyBjb3B5IHJlbWFpbmluZyBieXRlcwogICAgY29weV9ieXRlKCAoYnl0ZSopZCwgKGNvbnN0IGJ5dGUqKXMsIG5fYnl0ZSApOwoKICAgIHJldHVybiBkZXN0Owp9Cgp2b2lkICpteV9tZW1jcHlfYnl0ZV9vbmx5KCB2b2lkKiBkZXN0LCBjb25zdCB2b2lkKiBzcmMsIHN0ZDo6c2l6ZV90IG4gKQp7CiAgICByZXR1cm4gY29weV9ieXRlKCAoYnl0ZSopZGVzdCwgKGNvbnN0IGJ5dGUqKXNyYywgbiApOwp9Ci8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCnZvaWQqIGNvZGVzYWZlcl9tZW1jcHlfdW5hbGlnbmVkMSggdm9pZCogZHN0LCBjb25zdCB2b2lkKiBzcmMsIHN0ZDo6c2l6ZV90IHNpemUgKQp7CiAgICB1c2luZyAgIHN0ZXBfdCAgICA9IHUzMjsKCiAgICBfX19fXyAgIHN0ZXBfdCogZCA9IChzdGVwX3QqKWRzdDsKICAgIGNvbnN0ICAgc3RlcF90KiBzID0gKHN0ZXBfdCopc3JjOwogICAgY29uc3QgICBzdGQ6OnNpemVfdCBzdGVwX2NvdW50ICA9IHNpemUgLyBzaXplb2Yoc3RlcF90KTsKICAgIGNvbnN0ICAgdTMyICAgICAgICAgb2ZmX3JvYWQgICAgPSBzaXplICUgc2l6ZW9mKHN0ZXBfdCk7CgogICAgZm9yKCBzdGQ6OnNpemVfdCBpID0gMDsgaSA8IHN0ZXBfY291bnQ7ICsraSApCiAgICAgICAgZFtpXSA9IHNbaV07CgogICAgdTgqIGRiID0gKHU4KikoIGQgKyBzdGVwX2NvdW50ICk7CiAgICB1OCogc2IgPSAodTgqKSggcyArIHN0ZXBfY291bnQgKTsKCiAgICBmb3IoIHUzMiBpID0gMDsgaSA8IG9mZl9yb2FkOyArK2kgKQogICAgICAgIGRiW2ldID0gc2JbaV07CgogICAgcmV0dXJuICBkc3Q7Cn0KLy89PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQovLyB0ZXN0IGNhc2UKCmNvbnN0IGludCAgIHRlc3RfY291bnQgPSAxMDAwOwpjb25zdCBpbnQgICB0ZXN0X3NpemUgID0gMTAwMDAwMDsKCiNpZmRlZiBfTVNDX1ZFUgpfX2RlY2xzcGVjKCBhbGlnbiggNCApICkgICBjaGFyIHNyY1sgdGVzdF9zaXplICsgNCBdOwpfX2RlY2xzcGVjKCBhbGlnbiggNCApICkgICBjaGFyIGRzdFsgdGVzdF9zaXplICsgNCBdOwojZWxzZQpjaGFyIHNyY1sgdGVzdF9zaXplICsgNCBdIF9fYXR0cmlidXRlX18oKGFsaWduZWQoNCkpKTsKY2hhciBkc3RbIHRlc3Rfc2l6ZSArIDQgXSBfX2F0dHJpYnV0ZV9fKChhbGlnbmVkKDQpKSk7CiNlbmRpZgoKaW50ICAgICAgICAgcmVzdWx0MSwgcmVzdWx0MiwgcmVzdWx0MywgcmVzdWx0NDsKCnZvaWQgaW5pdCgpCnsKfQoKdm9pZCBwcmUoKQp7Cn0KCnZvaWQgdGVzdDEoKQp7CiAgICByZXN1bHQxICs9IChpbnQpa3VreWFreWFfbWVtY3B5KCBkc3QgKyAxLCBzcmMgKyAzLCB0ZXN0X3NpemUgKTsKfQoKdm9pZCB0ZXN0MigpCnsKICAgIHJlc3VsdDIgKz0gKGludClrdWt5YWt5YV9tZW1jcHlfdW5hbGlnbmVkKCBkc3QgKyAxLCBzcmMgKyAzLCB0ZXN0X3NpemUgKTsKfQoKdm9pZCB0ZXN0MygpCnsKICAgIHJlc3VsdDMgKz0gKGludCltZW1jcHkoIGRzdCArIDEsIHNyYyArIDMsIHRlc3Rfc2l6ZSApOwp9Cgp2b2lkIHRlc3Q0KCkKewogICAgcmVzdWx0NCArPSAoaW50KWNvZGVzYWZlcl9tZW1jcHlfdW5hbGlnbmVkMSggZHN0ICsgMSwgc3JjICsgMywgdGVzdF9zaXplICk7Cn0KCmJvb2wgcG9zdCgpCnsKICAgIHJldHVybiAgdHJ1ZTsKfQovLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojaW5jbHVkZSA8aW9zdHJlYW0+Cgp1c2luZyAgIG5hbWVzcGFjZSAgIHN0ZDsKCmludCBtYWluKCkKewogICAgaW5pdCgpOwogICAgQkVOQ0g8IHRlc3RfY291bnQgPiBiZW5jaDsKICAgIGJlbmNoLmFkZCggRlVOKCBwcmUsIHRlc3QxLCBwb3N0LCBrdWt5YWt5YV9hbGlnbmVkICkgKTsKICAgIGJlbmNoLmFkZCggRlVOKCBwcmUsIHRlc3QyLCBwb3N0LCBrdWt5YWt5YV91bmFsaWduZWQgKSApOwogICAgYmVuY2guYWRkKCBGVU4oIHByZSwgdGVzdDMsIHBvc3QsIHN0ZF9tZW1jcHkgKSApOwogICAgYmVuY2guYWRkKCBGVU4oIHByZSwgdGVzdDQsIHBvc3QsIGNvZGVzYWZlcl91bmFsaWduZWQxICkgKTsKICAgIGJlbmNoLnJ1bigpOwoKCWdldGNoYXIoKTsKICAgIHJldHVybiAgMDsKfQovLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCg==