#include <cstdio>

#include <stdlib.h>

#include <string.h>

#include <intrin.h>


size_t strlen_ex(char* s); // to do


#define LEN        99999

#define STRLEN     (LEN+1)

#define LOOP_COUNT 50000


int main()

{

    char temp[STRLEN];

    for (int i = 0; i < LEN; ++i) temp[i] = i % 255 + 1;

    temp[LEN] = 0;


    size_t len1, len2;

    unsigned long long begin1, begin2, min1, min2, end1, end2, base;

    base = min2 = min1 = -1LL;


    for (int i = 0; i < 100; ++i)

    {

        begin1 = __rdtsc();

        end1 = __rdtsc();

        if (base > end1 - begin1) base = end1 - begin1;

    }


    int strlen_win = 0;

    int strlen_ex_win = 0;

    for (int i = 0; i < LOOP_COUNT; ++i)

    {

        begin1 = __rdtsc();

        len1 = strlen(temp);

        end1 = __rdtsc();

        temp[LEN] = 0;

        begin2 = __rdtsc();

        len2 = strlen_ex(temp);

        end2 = __rdtsc();

        temp[LEN] = 0;

        if (end1 - begin1 < min1) min1 = end1 - begin1;

        if (end2 - begin2 < min2) min2 = end2 - begin2;

    }


    printf("strlen    %u %u clock\n",

        (unsigned int)len1, (unsigned int)(min1 - base));

    printf("strlen_ex %u %u clock\n",

        (unsigned int)len2, (unsigned int)(min2 - base));

    system("pause");

    return 0;

}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


#define s_return(n)                                                            \

        if (!s[n]) return n


#define w_init                                                                 \

        w = (step_t*)                                                          \

            (((step_t)s & ((step_t)-1 - (sizeof(step_t) - 1))) + sizeof(step_t))


#define w_check(n)                                                             \

        if (w[n] - (step_t)0x0101010101010101ULL &                             \

                   (step_t)0x8080808080808080ULL & ~w[n])                      \

        {   w += n; break; }


#define w_add                                                                  \

        w += sizeof(step_t) * 2;


#define w_return(n)                                                            \

        if (!(w[0] & (step_t)(0xFFULL << (8 * n))))                            \

        return (size_t)w - (size_t)s + n


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


#define s_returns_32                                                           \

        step_t* w;                                                             \

        s_return(0); s_return(1); s_return(2); s_return(3)


#define w_checks_32                                                            \

        w_check( 0); w_check( 1); w_check( 2); w_check( 3);                    \

        w_check( 4); w_check( 5); w_check( 6); w_check( 7)


#define w_returns_32                                                           \

        w_return(0); w_return(1); w_return(2); w_return(3)


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


#if _WIN64

    typedef unsigned long long step_t;


    #define s_returns_64                                                       \

        s_return(4); s_return(5); s_return(6); s_return(7)


    #define w_checks_64                                                        \

        w_check( 8); w_check( 9); w_check(10); w_check(11);                    \

        w_check(12); w_check(13); w_check(14); w_check(15);


    #define w_returns_64                                                       \

        w_return(4); w_return(5); w_return(6); w_return(7)                  


#else

    typedef unsigned int step_t;


    #define w_returns_64

    #define w_checks_64

    #define s_returns_64

#endif


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


size_t strlen_ex(char* s)

{

    s_returns_32;

    s_returns_64;

    w_init;


    while (1)

    {

        w_checks_32;

        w_checks_64;

        w_add;

    }

#if _WIN64

    w_returns_32;

    w_returns_64;

#else

    __asm

    {

        and eax, 0x80808080

        bsf eax, eax

        shr eax, 3

        add eax, w

        sub eax, s

    }

#endif

}