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

using   i8                      = char;
using   u8                      = unsigned char;
using   i16                     = short;
using   u16                     = unsigned short;
using   i32                     = int;
using   u32                     = unsigned int;
using   i64                     = long long;
using   u64                     = unsigned long long;

using   f32                     = float;
using   f64                     = double;

#define rigid                   constexpr

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

rigid   u32 CHAR_BITS           = 8;

// 특정 타입의 most significant bit의 위치를 리턴
// ex ) 32bit type -> 31
template< typename T >
inline  rigid   auto    msb()
{
    return  sizeof( T ) * CHAR_BITS - 1;
}

// 특정 타입의 most significant bit를 1로 둔 값을 리턴
// ex ) 32bit type -> 0x80000000
template< typename T >
inline  rigid   auto    msb_value()
{
    return  (T)1 << msb< T >();
}

// 특정 타입의 most significant bit를 제외시키는 마스크를 리턴
// ex ) 32bit type -> 0x7FFFFFFF
template< typename T >
inline  rigid   auto    msb_mask()
{
    return  (T)~msb_value< T >();
}

// 편하게 쓰자
#define msb_pos( var ) msb< decltype( var ) >()
#define msb_val( var ) msb_value< decltype( var ) >()

// dst 의 가장 큰값 위치에 bits 값을 얹는다
template< typename T0, typename T1 >
inline  void    set_msbs( T0& dst, const T1 bits )
{
    *( (T1*)&dst + ( sizeof dst / sizeof bits - 1 ) ) |= bits;
}
//---------------------------------------------------------------------------------------

// 문자열로부터 부호없는 연속한 숫자를 리턴
// 포인터를 숫자의 끝 다음으로 이동시킴
inline  u32     atou32( char*& s )
{
    u32 value;
    for( value = 0; *s <= '9' && *s >= '0'; ++s )
        value = value * 10 + ( *s - '0' );
    return  value;
}

// 문자열로부터 부호있는 연속한 숫자를 리턴
// 포인터를 숫자의 끝 다음으로 이동시킴
inline  i32     atoi32( char*& s )
{
    if( *s == '-' )
        return  -(i32)atou32( ++s );
    return  (i32)atou32( s );
}

#include <cmath>
// 문자열로부터 부호처리된 부동소수 및 지수값을 리턴
// 포인터를 숫자의 끝 다음으로 이동시킴
template< typename T = f64 >
inline  T       atof( char*& s )
{
    char* p     = s;
    u32 sign    = 0;
    T   digit   = 0.;
    T   base    = 1.;
    T   step    = 1.;

    for( i8 token; token = *p++; )
    {
        switch( token )
        {
        case '-':
            sign = msb_val( sign );
            break;
        case '.':
            step = 10;
            break;
        case 'E':
        case 'e':
            digit *= std::pow( 10., (f64)atof< T >( s = p ) );
            goto exit;
        default:
            if( token <= '9' && token >= '0' )
            {
                digit = digit * (T)10. + ( token & 0xF );
                base *= step;
                continue;
            }
            goto exit;
        }
    }
    exit:
    if( s < p - 1 ) s = p - 1;
    set_msbs( digit, sign );
    return  T( digit / base );
}

// 편하게 쓰자
inline  auto    atof32( char*& s )
{
    return  atof< f32 >( s );
}

inline  auto    atof64( char*& s )
{
    return  atof< f64 >( s );
}
//---------------------------------------------------------------------------------------

#include <type_traits>
// 타입에 맞게 문자열의 숫자를 해독해서 param 에 넣음
template< typename T >
inline  char*   parse_number( const char* string, T& param )
{
    char* s = (char*)string;
    while( *s == ' ' || *s == '\t' || *s == '\n' ) s++;

    if( std::is_same< T, i32 >::value )
        param = (T)atoi32( s );
    if( std::is_same< T, u32 >::value )
        param = (T)atou32( s );
    if( std::is_same< T, f32 >::value )
        param = (T)atof32( s );
    if( std::is_same< T, f64 >::value )
        param = (T)atof64( s );

    return  s;
}

// 복수 params
template< typename T, typename... Ts >
inline  char*   parse_number( const char* string, T& param1, Ts&... rest )
{
    return  parse_number( parse_number( string, param1 ), rest... );
}
//---------------------------------------------------------------------------------------

#include <iostream>
using namespace std;

int main()
{
    i32 a, b;
    u32 c, d;
    f64 e;
    f32 f;
    
    parse_number( "-1 0 1 2 1.23e2 1.23456", a, b, c, d, e, f );
    cout << a << " " << b << " " << c << " " << d << " " << e << " " << f << endl;

    return 0;
}