#if _MSC_VER
#pragma warning(disable: 4996)  // _CRT_SECURE_NO_WARNINGS
#include <intrin.h>
#else
#include <x86intrin.h>
#endif

#include <iostream>
#include <stdio.h>              // printf
#include <string.h>             // memcmp
#define min_( a, b )            ( (a) < (b) ? (a) : (b) )

//------------------------------+---------------------------------------------------------------

#ifndef SYS_BITS
#define CHAR_BITS               8
#define SYS_BYTES               sizeof( std::size_t )
#define SYS_BITS                ( SYS_BYTES * CHAR_BITS )
#endif

//------------------------------+---------------------------------------------------------------

using   ON_RUN      =           void( & )( void* );
using   ON_PREPARE  =           void( & )( void* );
using   ON_COMPARE  =           bool( & )( void*, void*, std::size_t );

//------------------------------+---------------------------------------------------------------
//  BENCH 에 의해서만 접근되기 때문에 모든 멤버가 private ( class default ) 입니다
class                           RUNNER
{
friend  class                   BENCH;
    const   char*               name;
    unsigned long long          elapsed;
    const   ON_RUN              on_run;
    void*                       result;

                                RUNNER( const char* name, ON_RUN&& on_run, void* result )
    :   name( name )
    ,   on_run( on_run )
    ,   elapsed( -1 )
    ,   result( result )
    {
    }

    void                        run()
    {
        auto    begin   = __rdtsc();
        on_run( result );
        elapsed         = min_( elapsed, __rdtsc() - begin );
    }
};
///-----------------------------+---------------------------------------------------------------

#include <vector>

class                           BENCH
{
private:
    const   char*               title;
    std::vector< RUNNER* >      runners;
    ON_PREPARE                  on_prepare;
    ON_COMPARE                  on_compare;
    void*                       answer;
    std::size_t                 answer_size;
    const   unsigned int        trial;

public:
                                BENCH( const char* title, const int trial,
                                       ON_PREPARE&& prepare, ON_COMPARE&& compare
    )
    :   title( title )
    ,   trial( trial )
    ,   on_prepare( prepare )
    ,   on_compare( compare )
    {
    };
                               ~BENCH()
    {
        for( auto runner : runners )
            delete[] runner;
        runners.clear();
    }

    auto                        record( unsigned int index ) const
    {
        return  runners[ index ]->elapsed;
    }

    auto                        runner_count() const
    {
        return  runners.size();
    }

    void                        solution( ON_RUN&& correct_function,
                                          void* result, const std::size_t bytes )
    {
        answer      = result;
        answer_size = bytes;
        on_prepare( result );
        correct_function( result );
    }

    template< typename T >
    void                        solution( ON_RUN&& correct_function,
                                          T& result, const std::size_t bytes )
    {
        solution( correct_function, &result, bytes );
    }

    void                        add( const char* name, ON_RUN&& on_run, void* result )
    {
        runners.emplace_back( new RUNNER( name, on_run, result ) );
    }

    template< typename T >
    void                        add( const char* name, ON_RUN&& on_run, T& result )
    {
        add( name, on_run, &result );
    }

    void                        run() const
    {
        if( runners.empty() )
            return;

        printf( "\n   < %d bits %d trial >    %s\n", (int)SYS_BITS, trial, title );
        puts( "   ----------------+---------------------------------+-----------------------" );
        puts( "   |    CHECKER    |          function name          |    minimum clocks    |" );
        puts( "   ----------------+---------------------------------+-----------------------" );

        unsigned long long  min_clocks = -1;
        unsigned long long  max_clocks = 0;
        RUNNER* min_runner = runners[ 0 ];
        RUNNER* max_runner = runners[ 0 ];

        for( const  auto    runner : runners )
        {
            int     pass_count = 0;
            for( unsigned int i = 0; i < trial; ++i )
            {
                on_prepare( runner->result );
                runner->run();
                pass_count += on_compare( runner->result, answer, answer_size );
            }

            if( min_clocks > runner->elapsed )
            {
                min_runner = runner;
                min_clocks = runner->elapsed;
            }
            if( max_clocks < runner->elapsed )
            {
                max_runner = runner;
                max_clocks = runner->elapsed;
            }

            char    temp[ 14 ];
            if( trial == pass_count )
                sprintf( temp, "       PASSED" );
            else
                sprintf( temp, "FAILED%7d", trial - pass_count );

            printf( "   [ %s ] %32s %15llu clocks\n", temp, runner->name, runner->elapsed );
        }
        puts( "   --------------------------------------------------------------------------" );
        printf( "   Winner is %s  ( %.2f times faster )\n\n",
                min_runner->name, float( max_clocks ) / min_clocks );
    }
};

#define FUN( function_name )    #function_name, function_name

//==============================================================================================
//------------------------------+---------------------------------------------------------------

using   SOURCE = char;
using   RESULT = char;

SOURCE  src[ 1<<20 ];

constexpr   std::size_t SIZE = sizeof src / sizeof *src;

RESULT  dst0[ SIZE ], dst1[ SIZE ], dst2[ SIZE ], dst3[ SIZE ];

//------------------------------+---------------------------------------------------------------
//  테스트전에 불려질 초기화 함수
void    prepare( void* result )
{
	for( auto& v : src )
		v = 'a';
	src[ sizeof src - 1 ] = 0;
//    memcpy( result, src, sizeof src );
}
//  테스트후에 불려질 점검 함수
bool    compare( void* result, void* answer, std::size_t bytes )
{
    return  *(int*)result == *(int*)answer;
//    return  memcmp( result, answer, bytes ) == 0;
}
//------------------------------+---------------------------------------------------------------
//  테스트할 함수들

namespace	cose_new
{

constexpr       std::size_t  finder = ( std::size_t )0x0101010101010101ULL;
constexpr       std::size_t  masker = ( std::size_t )0x8080808080808080ULL;

constexpr       std::size_t  has_zero_7bit( const std::size_t n )
{
    return  ( n - finder ) & masker;
}

constexpr       std::size_t  has_zero_8bit( const std::size_t n )
{
    return  has_zero_7bit( n ) & ~n;
}

inline	auto    where_zero( const std::size_t* w )
{
	auto*   p = (const char*)w;
	while( *p++ );
    return  p - 1;
}

template< int bits >
auto            strend_bit( const char* s )
{
    const int  step     = sizeof finder == 4 ? 8 : 4;
    const auto has_zero = bits == 7 ? has_zero_7bit : has_zero_8bit;
    
    if( has_zero( *(std::size_t*)s ) )
        return  where_zero( (std::size_t*)s );

    auto    w = (std::size_t*)( (std::size_t)s & ~std::size_t( sizeof finder - 1 ) ) + 1;

    while( 1 )
    {
        if( has_zero( w[ 0 ] ) ) return  where_zero( w     );
        if( has_zero( w[ 1 ] ) ) return  where_zero( w + 1 );
        if( has_zero( w[ 2 ] ) ) return  where_zero( w + 2 );
        if( has_zero( w[ 3 ] ) ) return  where_zero( w + 3 );
        if( sizeof finder == 4 )
        {
        if( has_zero( w[ 4 ] ) ) return  where_zero( w + 4 );
        if( has_zero( w[ 5 ] ) ) return  where_zero( w + 5 );
        if( has_zero( w[ 6 ] ) ) return  where_zero( w + 6 );
        if( has_zero( w[ 7 ] ) ) return  where_zero( w + 7 );
        }
        w += step;
    }
}

auto            strlen_fast( const char* s )
{
    return  strend_bit< 8 >( strend_bit< 7 >( s ) ) - s;
}

void            run( void* dst )
{
	*(int*)dst = strlen_fast( src );
}

}

void	        run( void* dst )
{
	*(int*)dst = strlen( src );
}
//------------------------------+---------------------------------------------------------------

int main()
{
    BENCH bench( "strlen", 1000, prepare, compare );
    bench.solution( run, dst0, sizeof dst0 );

    bench.add( FUN( run ), dst1 );
    bench.add( FUN( cose_new::run  ), dst2 );

    bench.run();

    getchar();
    return  0;
}