// File: /workspace/github_cpp_makefile_star2_O3/cybozu[P]yrmcds/src/memcache/memcache.cpp
// Function: yrmcds::memcache::binary_request::parse()
void binary_request::parse() noexcept {
    if( m_len < BINARY_HEADER_SIZE ) return; // incomplete
    std::uint32_t total_len;
    cybozu::ntoh(m_p + 8, total_len);
    if( m_len < (BINARY_HEADER_SIZE + total_len) ) return; // incomplete
    m_request_len = BINARY_HEADER_SIZE + total_len;

    // Opcode parsing
    m_command = (binary_command)*(const unsigned char*)(m_p+1);
    m_quiet = ( m_command == binary_command::GetQ ||
                m_command == binary_command::GetKQ ||
                (binary_command::SetQ <= m_command &&
                 m_command <= binary_command::PrependQ) ||
                m_command == binary_command::GaTQ ||
                m_command == binary_command::GaTKQ ||
                (binary_command::LockQ <= m_command &&
                 m_command <= binary_command::RaUQ &&
                 ((unsigned char)m_command) & 1) );

    std::uint16_t key_len;
    cybozu::ntoh(m_p + 2, key_len);
    if( key_len > MAX_KEY_LENGTH )
        return; // invalid
    std::uint8_t extras_len = *(const unsigned char*)(m_p + 4);
    if( total_len < (key_len + extras_len) )
        return; // invalid
    if( key_len > 0 )
        m_key = item(m_p + (BINARY_HEADER_SIZE + extras_len), key_len);

    cybozu::ntoh(m_p + 16, m_cas_unique);

    std::size_t data_len = total_len - key_len - extras_len;
    if( data_len > MAX_REQUEST_LENGTH ) {
        m_status = binary_status::TooLargeValue;
        return;
    }
    if( data_len > 0 )
        m_data = item(m_p + (BINARY_HEADER_SIZE + extras_len + key_len),
                      data_len);

    const char* const p_extra = m_p + BINARY_HEADER_SIZE;

    switch( m_command ) {
    case binary_command::Get:
    case binary_command::GetQ:
    case binary_command::GetK:
    case binary_command::GetKQ:
    case binary_command::GaT:
    case binary_command::GaTQ:
    case binary_command::GaTK:
    case binary_command::GaTKQ:
    case binary_command::LaG:
    case binary_command::LaGQ:
    case binary_command::LaGK:
    case binary_command::LaGKQ:
        if( extras_len != 0 && extras_len != 4 )
            return; // invalid
        if( key_len == 0 || data_len > 0 )
            return; // invalid
        if( extras_len == 4 ) {
            m_exptime = binary_exptime(p_extra);
        } else {
            m_exptime = EXPTIME_NONE;
        }
        break;
    case binary_command::Set:
    case binary_command::SetQ:
    case binary_command::Add:
    case binary_command::AddQ:
    case binary_command::Replace:
    case binary_command::ReplaceQ:
    case binary_command::RaU:
    case binary_command::RaUQ:
        if( extras_len != 8 || key_len == 0 || data_len == 0 )
            return; // invalid
        cybozu::ntoh(p_extra, m_flags);
        m_exptime = binary_exptime(p_extra + 4);
        break;
    case binary_command::Delete:
    case binary_command::DeleteQ:
        if( extras_len != 0 || key_len == 0 || data_len > 0 )
            return; // invalid
        break;
    case binary_command::Increment:
    case binary_command::IncrementQ:
    case binary_command::Decrement:
    case binary_command::DecrementQ:
        if( extras_len != 20 || key_len == 0 || data_len > 0 )
            return; // invalid
        cybozu::ntoh(p_extra, m_value);
        cybozu::ntoh(p_extra + sizeof(std::uint64_t), m_initial);
        m_exptime = binary_exptime(p_extra + sizeof(std::uint64_t)*2);
        break;
    case binary_command::Touch:
        if( key_len == 0 || extras_len != 4 || data_len != 0 )
            return; // invalid
        m_exptime = binary_exptime(p_extra);
        break;
    case binary_command::Flush:
    case binary_command::FlushQ:
        if( extras_len != 0 && extras_len != 4 )
            return; // invalid
        if( key_len != 0 || data_len > 0 )
            return; // invalid
        if( extras_len == 4 ) { // yrmcds extension
            m_exptime = binary_exptime(p_extra);
        } else {
            m_exptime = g_current_time.load(relaxed);
        }
        break;
    case binary_command::Append:
    case binary_command::AppendQ:
    case binary_command::Prepend:
    case binary_command::PrependQ:
        if( extras_len != 0 || key_len == 0 || data_len == 0 )
            return; // invalid
        break;
    case binary_command::Lock:
    case binary_command::LockQ:
    case binary_command::Unlock:
    case binary_command::UnlockQ:
        if( extras_len != 0 || key_len == 0 || data_len > 0 )
            return; // invalid
        break;
    case binary_command::Stat:
        if( extras_len != 0 || data_len != 0 )
            return; // invalid
        if( key_len == 8 &&
            std::memcmp(p_extra, "settings", 8) == 0 ) {
            m_stats = stats_t::SETTINGS;
        } else if( key_len == 5 ) {
            if( std::memcmp(p_extra, "items", 5) == 0 ) {
                m_stats = stats_t::ITEMS;
            } else if( std::memcmp(p_extra, "sizes", 5) == 0 ) {
                m_stats = stats_t::SIZES;
            }
        } else if( key_len == 3 &&
                   std::memcmp(p_extra, "ops", 3) == 0 ) {
            m_stats = stats_t::OPS;
        }
        break;
    case binary_command::Keys:
        if( extras_len != 0 || data_len > 0 )
            return; // invalid
        break;
    case binary_command::Quit:
    case binary_command::QuitQ:
    case binary_command::Version:
    case binary_command::Noop:
    case binary_command::UnlockAll:
    case binary_command::UnlockAllQ:
        // no validation.
        // this is intentional violation against the protocol definition.
        break;
    default:
        m_command = binary_command::Unknown;
        m_status = binary_status::UnknownCommand;
        return;
    }

    m_status = binary_status::OK;
}

// Assembly:
movq 0x8(%rdi), %rdx
cmpq $0x18, %rdx
jb 0x26411
pushq %r14
pushq %rbx
movq (%rdi), %rax
movl 0x8(%rax), %ecx
bswapl %ecx
leaq 0x18(%rcx), %rsi
cmpq %rsi, %rdx
jb 0x2640e
movq %rsi, 0x10(%rdi)
movzbl 0x1(%rax), %r8d
movb %r8b, 0x1a(%rdi)
movb $0x1, %dl
movl %r8d, %esi
orl $0x4, %esi
cmpl $0xd, %esi
jne 0x26319
movb %dl, 0x1b(%rdi)
movzwl 0x2(%rax), %r11d
movl %r11d, %r10d
rolw $0x8, %r10w
movzwl %r10w, %ebx
cmpl $0xfa, %ebx
ja 0x2640e
movzbl 0x4(%rax), %esi
leal (%rsi,%rbx), %edx
movl %ecx, %r14d
subl %edx, %r14d
jb 0x2640e
testw %r11w, %r11w
je 0x26297
leaq (%rax,%rsi), %r9
addq $0x18, %r9
movq %r9, 0x28(%rdi)
movq %rbx, 0x20(%rdi)
movq 0x10(%rax), %r9
bswapq %r9
movq %r9, 0x30(%rdi)
movw $0x3, %r9w
cmpl $0x1e00000, %r14d       # imm = 0x1E00000
ja 0x26409
cmpl %edx, %ecx
je 0x262cb
leaq (%rax,%rsi), %r9
addq %rbx, %r9
addq $0x18, %r9
movq %r9, 0x50(%rdi)
movq %r14, 0x48(%rdi)
cmpl $0x50, %r8d
ja 0x26458
movl %r8d, %r8d
leaq 0x109a1(%rip), %r9      # 0x36c80
movslq (%r9,%r8,4), %r8
addq %r9, %r8
jmpq *%r8
testw %r11w, %r11w
je 0x2640e
movl %esi, %r8d
andb $-0x5, %r8b
jne 0x2640e
cmpl %edx, %ecx
jne 0x2640e
cmpl $0x4, %esi
jne 0x263f1
movl 0x18(%rax), %ecx
jmp 0x263b8
leal -0x11(%r8), %esi
cmpb $0xa, %sil
jb 0x2624e
cmpl $0x1e, %r8d
je 0x2624e
cmpl $0x24, %r8d
je 0x2624e
leal -0x41(%r8), %edx
cmpb $0xb, %dl
setb %dl
andb %r8b, %dl
jmp 0x2624e
testw %r11w, %r11w
je 0x2640e
cmpb $0x8, %sil
jne 0x2640e
cmpl %edx, %ecx
je 0x2640e
movl 0x18(%rax), %ecx
bswapl %ecx
movl %ecx, 0x38(%rdi)
movl 0x1c(%rax), %ecx
jmp 0x263b8
testw %r11w, %r11w
je 0x2640e
testb %sil, %sil
jne 0x2640e
cmpl %edx, %ecx
je 0x26406
jmp 0x2640e
testw %r11w, %r11w
je 0x2640e
cmpb $0x14, %sil
jne 0x2640e
cmpl %edx, %ecx
jne 0x2640e
movq 0x18(%rax), %rcx
bswapq %rcx
movq %rcx, 0x58(%rdi)
movq 0x20(%rax), %rcx
bswapq %rcx
movq %rcx, 0x60(%rdi)
movl 0x28(%rax), %ecx
testl %ecx, %ecx
je 0x263ed
cmpl $-0x1, %ecx
je 0x263fb
bswapl %ecx
movl %ecx, %eax
cmpl $0x278d00, %ecx         # imm = 0x278D00
ja 0x26402
leaq 0x20aac(%rip), %rcx     # 0x46e80
movq (%rcx), %rcx
addq %rcx, %rax
jmp 0x26402
testw %r11w, %r11w
je 0x2640e
testb %sil, %sil
jne 0x2640e
cmpl %edx, %ecx
jne 0x26406
jmp 0x2640e
xorl %eax, %eax
jmp 0x26402
movq $-0x1, 0x40(%rdi)
jmp 0x26406
movq $-0x1, %rax
movq %rax, 0x40(%rdi)
xorl %r9d, %r9d
movw %r9w, 0x18(%rdi)
popq %rbx
popq %r14
retq
testb $-0x5, %sil
jne 0x2640e
testw %r11w, %r11w
jne 0x2640e
cmpl %edx, %ecx
jne 0x2640e
cmpl $0x4, %esi
je 0x26311
leaq 0x20a4e(%rip), %rax     # 0x46e80
movq (%rax), %rax
jmp 0x26402
testw %r11w, %r11w
je 0x2640e
cmpb $0x4, %sil
jne 0x2640e
cmpl %edx, %ecx
je 0x26311
jmp 0x2640e
testq %rsi, %rsi
je 0x26389
jmp 0x2640e
movb $0x51, 0x1a(%rdi)
movw $0x81, %r9w
jmp 0x26409
testq %rsi, %rsi
jne 0x2640e
cmpl %edx, %ecx
jne 0x2640e
cmpb $0x3, %r10b
je 0x264d6
movzbl %r10b, %ecx
cmpl $0x5, %ecx
je 0x264a0
cmpl $0x8, %ecx
jne 0x26406
movabsq $0x73676e6974746573, %rcx # imm = 0x73676E6974746573
cmpq %rcx, 0x18(%rax)
jne 0x26406
movl $0x1, 0x68(%rdi)
jmp 0x26406
movl $0x6d657469, %ecx       # imm = 0x6D657469
xorl 0x18(%rax), %ecx
movzbl 0x1c(%rax), %edx
xorl $0x73, %edx
orl %ecx, %edx
je 0x264fc
movl $0x657a6973, %ecx       # imm = 0x657A6973
xorl 0x18(%rax), %ecx
movzbl 0x1c(%rax), %eax
xorl $0x73, %eax
orl %ecx, %eax
jne 0x26406
movl $0x3, 0x68(%rdi)
jmp 0x26406
movzwl 0x18(%rax), %ecx
xorl $0x706f, %ecx           # imm = 0x706F
movzbl 0x1a(%rax), %eax
xorl $0x73, %eax
orw %cx, %ax
jne 0x26406
movl $0x4, 0x68(%rdi)
jmp 0x26406
movl $0x2, 0x68(%rdi)
jmp 0x26406