// File: /workspace/github_cpp_makefile_star2_O1/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 0x26e0b
pushq %r14
pushq %rbx
movq (%rdi), %rax
movl 0x8(%rax), %ecx
bswapl %ecx
leaq 0x18(%rcx), %rsi
cmpq %rsi, %rdx
jb 0x26e08
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 0x26d13
movb %dl, 0x1b(%rdi)
movzwl 0x2(%rax), %r11d
movl %r11d, %r9d
rolw $0x8, %r9w
movzwl %r9w, %ebx
cmpl $0xfa, %ebx
ja 0x26e08
movzbl 0x4(%rax), %esi
leal (%rsi,%rbx), %edx
movl %ecx, %r14d
subl %edx, %r14d
jb 0x26e08
testw %r11w, %r11w
je 0x26c91
leaq (%rax,%rsi), %r10
addq $0x18, %r10
movq %r10, 0x28(%rdi)
movq %rbx, 0x20(%rdi)
movq 0x10(%rax), %r10
bswapq %r10
movq %r10, 0x30(%rdi)
movw $0x3, %r10w
cmpl $0x1e00000, %r14d       # imm = 0x1E00000
ja 0x26e03
cmpl %edx, %ecx
je 0x26cc5
leaq (%rax,%rsi), %r10
addq %rbx, %r10
addq $0x18, %r10
movq %r10, 0x50(%rdi)
movq %r14, 0x48(%rdi)
cmpl $0x50, %r8d
ja 0x26e52
movl %r8d, %r8d
leaq 0xfff7(%rip), %r10      # 0x36cd0
movslq (%r10,%r8,4), %r8
addq %r10, %r8
jmpq *%r8
testw %r11w, %r11w
je 0x26e08
movl %esi, %r8d
andb $-0x5, %r8b
jne 0x26e08
cmpl %edx, %ecx
jne 0x26e08
cmpl $0x4, %esi
jne 0x26deb
movl 0x18(%rax), %ecx
jmp 0x26db2
leal -0x11(%r8), %esi
cmpb $0xa, %sil
jb 0x26c48
cmpl $0x1e, %r8d
je 0x26c48
cmpl $0x24, %r8d
je 0x26c48
leal -0x41(%r8), %edx
cmpb $0xb, %dl
setb %dl
andb %r8b, %dl
jmp 0x26c48
testw %r11w, %r11w
je 0x26e08
cmpb $0x8, %sil
jne 0x26e08
cmpl %edx, %ecx
je 0x26e08
movl 0x18(%rax), %ecx
bswapl %ecx
movl %ecx, 0x38(%rdi)
movl 0x1c(%rax), %ecx
jmp 0x26db2
testw %r11w, %r11w
je 0x26e08
testb %sil, %sil
jne 0x26e08
cmpl %edx, %ecx
je 0x26e00
jmp 0x26e08
testw %r11w, %r11w
je 0x26e08
cmpb $0x14, %sil
jne 0x26e08
cmpl %edx, %ecx
jne 0x26e08
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 0x26de7
cmpl $-0x1, %ecx
je 0x26df5
bswapl %ecx
movl %ecx, %eax
cmpl $0x278d00, %ecx         # imm = 0x278D00
ja 0x26dfc
leaq 0x200b2(%rip), %rcx     # 0x46e80
movq (%rcx), %rcx
addq %rcx, %rax
jmp 0x26dfc
testw %r11w, %r11w
je 0x26e08
testb %sil, %sil
jne 0x26e08
cmpl %edx, %ecx
jne 0x26e00
jmp 0x26e08
xorl %eax, %eax
jmp 0x26dfc
movq $-0x1, 0x40(%rdi)
jmp 0x26e00
movq $-0x1, %rax
movq %rax, 0x40(%rdi)
xorl %r10d, %r10d
movw %r10w, 0x18(%rdi)
popq %rbx
popq %r14
retq
testb $-0x5, %sil
jne 0x26e08
testw %r11w, %r11w
jne 0x26e08
cmpl %edx, %ecx
jne 0x26e08
cmpl $0x4, %esi
je 0x26d0b
leaq 0x20054(%rip), %rax     # 0x46e80
movq (%rax), %rax
jmp 0x26dfc
testw %r11w, %r11w
je 0x26e08
cmpb $0x4, %sil
jne 0x26e08
cmpl %edx, %ecx
je 0x26d0b
jmp 0x26e08
testq %rsi, %rsi
je 0x26d83
jmp 0x26e08
movb $0x51, 0x1a(%rdi)
movw $0x81, %r10w
jmp 0x26e03
testq %rsi, %rsi
jne 0x26e08
cmpl %edx, %ecx
jne 0x26e08
cmpb $0x3, %r9b
je 0x26ed3
movzbl %r9b, %ecx
cmpl $0x5, %ecx
je 0x26e9d
cmpl $0x8, %ecx
jne 0x26e00
movabsq $0x73676e6974746573, %rcx # imm = 0x73676E6974746573
cmpq %rcx, 0x18(%rax)
je 0x26f05
cmpb $0x3, %r9b
je 0x26ed3
movzbl %r9b, %ecx
cmpl $0x5, %ecx
jne 0x26e00
movl $0x6d657469, %ecx       # imm = 0x6D657469
xorl 0x18(%rax), %ecx
movzbl 0x1c(%rax), %edx
xorl $0x73, %edx
orl %ecx, %edx
je 0x26ef9
movl $0x657a6973, %ecx       # imm = 0x657A6973
xorl 0x18(%rax), %ecx
movzbl 0x1c(%rax), %eax
xorl $0x73, %eax
orl %ecx, %eax
jne 0x26e00
movl $0x3, 0x68(%rdi)
jmp 0x26e00
movzwl 0x18(%rax), %ecx
xorl $0x706f, %ecx           # imm = 0x706F
movzbl 0x1a(%rax), %eax
xorl $0x73, %eax
orw %cx, %ax
jne 0x26e00
movl $0x4, 0x68(%rdi)
jmp 0x26e00
movl $0x2, 0x68(%rdi)
jmp 0x26e00
movl $0x1, 0x68(%rdi)
jmp 0x26e00
nop