#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef unsigned long long      i64u;

// Benchmark ----------------------------------------------------------------

#ifdef _MSC_VER
    #include <intrin.h>
#else
	#define CHAR_BIT 8
    inline unsigned long long __rdtsc()
    {
        i64u tick;
        __asm volatile ( ".byte 0x0f, 0x31" : "=A" ( tick ) );
        return tick;
    }
#endif

#define _min( a, b )            ( (a) < (b)? (a): (b) )
#define _max( a, b )            ( (a) > (b)? (a): (b) )
#define update_min( a, b )      ( (a) = _min( (a), (b) ) )
#define update_max( a, b )      ( (a) = _max( (a), (b) ) )

//---------------------------------------------------------------------------

class                           SOME_RUNNER
{
private:
    const   char*               function_name;
    i64u                        elapsed;

protected:
    i64u                        sum;

public:
                                SOME_RUNNER( const char* function_name )
        : function_name( function_name ) { init(); }
    virtual                    ~SOME_RUNNER() {};
    virtual void                init()
    {
        sum = 0;
        elapsed = -1;
    }
    virtual void                run() = 0;
    void                        check()
    {
        i64u    begin    = __rdtsc();
        run();
        i64u    duration = __rdtsc() - begin;
        update_min( elapsed, duration );
    }
    const   char*               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   char*               report()
    {
        static  char temp[80];
        sprintf( temp, "[%15llu] %s %15llu clocks", sum,
            set_length( function_name, 20 ), elapsed );
        return  temp;
    }
    const   i64u                elapsed_clocks(){ return elapsed; }
    const   char*               name(){ return function_name; }
};
//---------------------------------------------------------------------------

#include <vector>
template < size_t LOOP_COUNT >
class                           BENCH
{
private:
    std::vector< SOME_RUNNER* > runner_list;

public:
    /*con*/                     BENCH() {};
    /*des*/                    ~BENCH() {};

    void                        add( SOME_RUNNER* runner )
    {
        runner_list.push_back( runner );
    }

    void                        run()
    {
        printf( "< %d bits > %d trials", sizeof( size_t ) * CHAR_BIT, LOOP_COUNT );
        puts( "" );
        puts( "-------------------------------------------------------------" );
        puts( "|  CHECKER      | Function  name      |   minimum  clocks   |" );
        puts( "-------------------------------------------------------------" );
        i64u    min = -1;
        i64u    max = 0;
        size_t  min_index = 0;
        size_t  max_index = 0;
        for( size_t test_case = 0; test_case < runner_list.size(); ++test_case )
        {
            runner_list[test_case]->init();
            for( size_t test_count = 0; test_count < LOOP_COUNT; ++ test_count )
                runner_list[test_case]->check();
            puts( runner_list[test_case]->report() );
            if( min > runner_list[test_case]->elapsed_clocks() )
            {
                min_index = test_case;
                min = runner_list[test_case]->elapsed_clocks();
            }
            if( max < runner_list[test_case]->elapsed_clocks() )
            {
                max_index = test_case;
                max = runner_list[test_case]->elapsed_clocks();
            }
        }
        puts( "-------------------------------------------------------------" );
        printf( "Winner is %s  ( %.2f times faster than looser )",
            runner_list[min_index]->name(),
            float( runner_list[max_index]->elapsed_clocks() ) /
            runner_list[min_index]->elapsed_clocks() );
        puts( "" );
    }
};
//---------------------------------------------------------------------------

#define DEFINE_FUNCTION(return_type, function, ...) \
    (SOME_RUNNER*)new RUNNER<return_type>( std::bind(function, __VA_ARGS__), #function )

//---------------------------------------------------------------------------

#include <functional>
template< typename RET_TYPE >
class                           RUNNER  : public    SOME_RUNNER
{
public:
    /*con*/                     RUNNER( std::function< RET_TYPE() > function,
        const char* function_name )
        : test( function ), SOME_RUNNER( function_name ) {}
    void                        run()
    {
        sum += (i64u)test();
    }
    std::function< RET_TYPE() > test;
};

template< >
class                           RUNNER< void > : public    SOME_RUNNER
{
public:
    /*con*/                     RUNNER( std::function< void() > function,
        const char* function_name )
        : test( function ), SOME_RUNNER( function_name ) {}
    void                        run()
    {
        sum++;
        test();
    }
    std::function< void() >     test;
};
//---------------------------------------------------------------------------

size_t  strlen_boost( const char* s );
size_t  strlen_hybrid( const char* s );

int main()
{
    #define     STRING_LENGTH           1000000

    char*       test_string = new char[STRING_LENGTH + 1];
    for( int i = 0; i < STRING_LENGTH; ++i )
    {
        test_string[i] = rand() % 127 + 1;
//        test_string[i] = rand() % 255 + 1;
    }
    test_string[STRING_LENGTH] = 0;

    BENCH< 100 > bench;
    bench.add( DEFINE_FUNCTION( size_t, strlen,           test_string ) );
    bench.add( DEFINE_FUNCTION( size_t, strlen_boost,     test_string ) );
    bench.add( DEFINE_FUNCTION( size_t, strlen_hybrid,    test_string ) );
    bench.run();

    getchar();
    return 0;
}

// Codesafer ----------------------------------------------------------------

typedef size_t  step_t;

inline  step_t  has_zero_7( const step_t n )
{
    const   step_t  finder = (step_t)0x0101010101010101ULL;
    const   step_t  masker = (step_t)0x8080808080808080ULL;
    return  ( n - finder ) & masker;
}

inline  step_t  has_zero_8( const step_t n )
{
    return  has_zero_7( n ) & ~n;
}

const   char*   where_zero( const char* s )
{
    size_t  i;
    if( ( i = 0, !s[0] ) ||
        ( i = 1, !s[1] ) ||
        ( i = 2, !s[2] ) ||
        ( sizeof( step_t ) == 8 && (
            ( i = 3, !s[3] ) ||
            ( i = 4, !s[4] ) ||
            ( i = 5, !s[5] ) ||
            ( i = 6, !s[6] ) ) ) )
        return s + i;
    return s + ( sizeof( step_t ) - 1 );
}

size_t  strlen_7( const char* s )
{
    if( has_zero_7( *(step_t*)s ) ) return  where_zero( s ) - s;

    step_t* w = (step_t*)( (size_t)s & ~size_t( sizeof( step_t ) - 1 ) ) + 1;
    while( 1 )
    {
        if( has_zero_7( w[0] ) ) return  where_zero( (char*)( w ) ) - s;
        if( has_zero_7( w[1] ) ) return  where_zero( (char*)( w + 1 ) ) - s;
        if( has_zero_7( w[2] ) ) return  where_zero( (char*)( w + 2 ) ) - s;
        if( has_zero_7( w[3] ) ) return  where_zero( (char*)( w + 3 ) ) - s;
        if( sizeof( step_t ) == 4 )
        {
            if( has_zero_7( w[4] ) ) return  where_zero( (char*)( w + 4 ) ) - s;
            if( has_zero_7( w[5] ) ) return  where_zero( (char*)( w + 5 ) ) - s;
            if( has_zero_7( w[6] ) ) return  where_zero( (char*)( w + 6 ) ) - s;
            if( has_zero_7( w[7] ) ) return  where_zero( (char*)( w + 7 ) ) - s;
        }
        w += sizeof( 0LL ) + sizeof( 0L ) - sizeof( step_t );
    }
}

size_t  strlen_boost( const char* s )
{
    if( has_zero_8( *(step_t*)s ) ) return  where_zero( s ) - s;

    step_t* w = (step_t*)( (size_t)s & ~size_t( sizeof( step_t ) - 1 ) ) + 1;
    while( 1 )
    {
        if( has_zero_8( w[0] ) ) return  where_zero( (char*)( w ) ) - s;
        if( has_zero_8( w[1] ) ) return  where_zero( (char*)( w + 1 ) ) - s;
        if( has_zero_8( w[2] ) ) return  where_zero( (char*)( w + 2 ) ) - s;
        if( has_zero_8( w[3] ) ) return  where_zero( (char*)( w + 3 ) ) - s;
        if( sizeof( step_t ) == 4 )
        {
            if( has_zero_8( w[4] ) ) return  where_zero( (char*)( w + 4 ) ) - s;
            if( has_zero_8( w[5] ) ) return  where_zero( (char*)( w + 5 ) ) - s;
            if( has_zero_8( w[6] ) ) return  where_zero( (char*)( w + 6 ) ) - s;
            if( has_zero_8( w[7] ) ) return  where_zero( (char*)( w + 7 ) ) - s;
        }
        w += sizeof( 0LL ) + sizeof( 0L ) - sizeof( step_t );
    }
}

size_t  strlen_hybrid( const char* s )
{
    const   size_t  len = strlen_7( s );
    return  len + strlen_boost( s + len );
}
//---------------------------------------------------------------------------
