// File: /workspace/github_cpp_makefile_star2_O2/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), %rcx
cmpq $0x18, %rcx
jb 0x21316
pushq %r14
pushq %rbx
pushq %rax
movq %rdi, %rbx
movq (%rdi), %rdi
movl 0x8(%rdi), %eax
bswapl %eax
leaq 0x18(%rax), %rdx
cmpq %rdx, %rcx
jb 0x2130f
movq %rdx, 0x10(%rbx)
movzbl 0x1(%rdi), %esi
movb %sil, 0x1a(%rbx)
movb $0x1, %cl
movl %esi, %edx
orl $0x4, %edx
cmpl $0xd, %edx
jne 0x21262
movb %cl, 0x1b(%rbx)
movzwl 0x2(%rdi), %r10d
movl %r10d, %r9d
rolw $0x8, %r9w
cmpw $0xfa, %r9w
ja 0x2130f
movzbl 0x4(%rdi), %edx
movzwl %r9w, %r11d
leal (%rdx,%r11), %ecx
movl %eax, %r14d
subl %ecx, %r14d
jb 0x2130f
testw %r10w, %r10w
je 0x211e0
leaq (%rdi,%rdx), %r8
addq $0x18, %r8
movq %r8, 0x28(%rbx)
movq %r11, 0x20(%rbx)
movq 0x10(%rdi), %r8
bswapq %r8
movq %r8, 0x30(%rbx)
movw $0x3, %r8w
cmpl $0x1e00000, %r14d       # imm = 0x1E00000
ja 0x2130a
cmpl %ecx, %eax
je 0x21214
leaq (%rdi,%rdx), %r8
addq %r11, %r8
addq $0x18, %r8
movq %r8, 0x50(%rbx)
movq %r14, 0x48(%rbx)
cmpl $0x50, %esi
ja 0x2135b
leaq 0x18(%rdi), %r14
movl %esi, %esi
leaq 0x79e6(%rip), %r8       # 0x28c10
movslq (%r8,%rsi,4), %rsi
addq %r8, %rsi
jmpq *%rsi
testw %r10w, %r10w
je 0x2130f
movl %edx, %esi
andb $-0x5, %sil
jne 0x2130f
cmpl %ecx, %eax
jne 0x2130f
cmpl $0x4, %edx
jne 0x21302
movq %r14, %rdi
jmp 0x212e7
leal -0x11(%rsi), %edx
cmpb $0xa, %dl
jb 0x21196
cmpl $0x1e, %esi
je 0x21196
cmpl $0x24, %esi
je 0x21196
leal -0x41(%rsi), %ecx
cmpb $0xb, %cl
setb %cl
andb %sil, %cl
jmp 0x21196
testw %r10w, %r10w
je 0x2130f
cmpb $0x8, %dl
jne 0x2130f
cmpl %ecx, %eax
je 0x2130f
movl 0x18(%rdi), %eax
bswapl %eax
movl %eax, 0x38(%rbx)
addq $0x1c, %rdi
jmp 0x212e7
testw %r10w, %r10w
je 0x2130f
testb %dl, %dl
jne 0x2130f
cmpl %ecx, %eax
je 0x21307
jmp 0x2130f
testw %r10w, %r10w
je 0x2130f
cmpb $0x14, %dl
jne 0x2130f
cmpl %ecx, %eax
jne 0x2130f
movq 0x18(%rdi), %rax
bswapq %rax
movq %rax, 0x58(%rbx)
movq 0x20(%rdi), %rax
bswapq %rax
movq %rax, 0x60(%rbx)
addq $0x28, %rdi
callq 0x21410
movq %rax, 0x40(%rbx)
jmp 0x21307
testw %r10w, %r10w
je 0x2130f
testb %dl, %dl
jne 0x2130f
cmpl %ecx, %eax
jne 0x21307
jmp 0x2130f
orq $-0x1, 0x40(%rbx)
xorl %r8d, %r8d
movw %r8w, 0x18(%rbx)
addq $0x8, %rsp
popq %rbx
popq %r14
retq
testb $-0x5, %dl
jne 0x2130f
testw %r10w, %r10w
jne 0x2130f
cmpl %ecx, %eax
jne 0x2130f
cmpl $0x4, %edx
je 0x2125a
leaq 0x1ab4a(%rip), %rax     # 0x3be80
movq (%rax), %rax
jmp 0x212ec
testw %r10w, %r10w
je 0x2130f
cmpb $0x4, %dl
jne 0x2130f
cmpl %ecx, %eax
je 0x2125a
jmp 0x2130f
testq %rdx, %rdx
je 0x212b8
jmp 0x2130f
movb $0x51, 0x1a(%rbx)
movw $0x81, %r8w
jmp 0x2130a
testq %rdx, %rdx
jne 0x2130f
cmpl %ecx, %eax
jne 0x2130f
cmpb $0x3, %r9b
je 0x213de
movzbl %r9b, %eax
cmpl $0x5, %eax
je 0x213a2
cmpl $0x8, %eax
jne 0x21307
movabsq $0x73676e6974746573, %rax # imm = 0x73676E6974746573
cmpq %rax, (%r14)
jne 0x21307
movl $0x1, 0x68(%rbx)
jmp 0x21307
leaq 0x8821(%rip), %rsi      # 0x29bca
pushq $0x5
popq %rdx
movq %r14, %rdi
callq 0x7530
testl %eax, %eax
je 0x21404
leaq 0x8341(%rip), %rsi      # 0x29700
pushq $0x5
popq %rdx
movq %r14, %rdi
callq 0x7530
testl %eax, %eax
jne 0x21307
movl $0x3, 0x68(%rbx)
jmp 0x21307
leaq 0x8321(%rip), %rsi      # 0x29706
pushq $0x3
popq %rdx
movq %r14, %rdi
callq 0x7530
testl %eax, %eax
jne 0x21307
movl $0x4, 0x68(%rbx)
jmp 0x21307
movl $0x2, 0x68(%rbx)
jmp 0x21307