// File: 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:
pushq %rbp
movq %rsp, %rbp
subq $0x90, %rsp
movq %rdi, -0x20(%rbp)
movq -0x20(%rbp), %rax
movq %rax, -0x70(%rbp)
cmpq $0x18, 0x8(%rax)
jae 0x69903
jmp 0x69eb2
movq -0x70(%rbp), %rax
movq (%rax), %rdi
addq $0x8, %rdi
leaq -0x24(%rbp), %rsi
callq 0x5d360
movq -0x70(%rbp), %rax
movq 0x8(%rax), %rax
movl -0x24(%rbp), %ecx
addq $0x18, %rcx
cmpq %rcx, %rax
jae 0x69930
jmp 0x69eb2
movq -0x70(%rbp), %rcx
movl -0x24(%rbp), %eax
addq $0x18, %rax
movq %rax, 0x10(%rcx)
movq (%rcx), %rax
movb 0x1(%rax), %al
movb %al, 0x1a(%rcx)
movb $0x1, %al
cmpb $0x9, 0x1a(%rcx)
movb %al, -0x71(%rbp)
je 0x699d7
movq -0x70(%rbp), %rcx
movb $0x1, %al
cmpb $0xd, 0x1a(%rcx)
movb %al, -0x71(%rbp)
je 0x699d7
movq -0x70(%rbp), %rcx
movb $0x11, %al
cmpb 0x1a(%rcx), %al
ja 0x69980
movq -0x70(%rbp), %rcx
movb $0x1, %al
cmpb $0x1a, 0x1a(%rcx)
movb %al, -0x71(%rbp)
jbe 0x699d7
movq -0x70(%rbp), %rcx
movb $0x1, %al
cmpb $0x1e, 0x1a(%rcx)
movb %al, -0x71(%rbp)
je 0x699d7
movq -0x70(%rbp), %rcx
movb $0x1, %al
cmpb $0x24, 0x1a(%rcx)
movb %al, -0x71(%rbp)
je 0x699d7
movq -0x70(%rbp), %rdx
xorl %eax, %eax
movb $0x41, %cl
cmpb 0x1a(%rdx), %cl
movb %al, -0x72(%rbp)
ja 0x699d1
movq -0x70(%rbp), %rcx
xorl %eax, %eax
cmpb $0x4b, 0x1a(%rcx)
movb %al, -0x72(%rbp)
ja 0x699d1
movq -0x70(%rbp), %rax
movzbl 0x1a(%rax), %eax
andl $0x1, %eax
cmpl $0x0, %eax
setne %al
movb %al, -0x72(%rbp)
movb -0x72(%rbp), %al
movb %al, -0x71(%rbp)
movq -0x70(%rbp), %rax
movb -0x71(%rbp), %cl
andb $0x1, %cl
movb %cl, 0x1b(%rax)
movq (%rax), %rdi
addq $0x2, %rdi
leaq -0x26(%rbp), %rsi
callq 0x5d3a0
movzwl -0x26(%rbp), %eax
cmpq $0xfa, %rax
jbe 0x69a05
jmp 0x69eb2
movq -0x70(%rbp), %rax
movq (%rax), %rax
movb 0x4(%rax), %al
movb %al, -0x27(%rbp)
movl -0x24(%rbp), %eax
movzwl -0x26(%rbp), %ecx
movzbl -0x27(%rbp), %edx
addl %edx, %ecx
cmpl %ecx, %eax
jae 0x69a28
jmp 0x69eb2
movzwl -0x26(%rbp), %eax
cmpl $0x0, %eax
jle 0x69a69
movq -0x70(%rbp), %rax
movq (%rax), %rax
movzbl -0x27(%rbp), %ecx
addq $0x18, %rcx
addq %rcx, %rax
movq %rax, -0x40(%rbp)
leaq -0x38(%rbp), %rdi
leaq -0x40(%rbp), %rsi
leaq -0x26(%rbp), %rdx
callq 0x76810
movq -0x70(%rbp), %rdi
addq $0x20, %rdi
leaq -0x38(%rbp), %rsi
callq 0x51450
movq -0x70(%rbp), %rsi
movq (%rsi), %rdi
addq $0x10, %rdi
addq $0x30, %rsi
callq 0x76850
movl -0x24(%rbp), %eax
movzwl -0x26(%rbp), %ecx
subl %ecx, %eax
movzbl -0x27(%rbp), %ecx
subl %ecx, %eax
movl %eax, %eax
movq %rax, -0x48(%rbp)
cmpq $0x1e00000, -0x48(%rbp) # imm = 0x1E00000
jbe 0x69aab
movq -0x70(%rbp), %rax
movw $0x3, 0x18(%rax)
jmp 0x69eb2
cmpq $0x0, -0x48(%rbp)
jbe 0x69af1
movq -0x70(%rbp), %rax
movq (%rax), %rax
movzbl -0x27(%rbp), %ecx
addq $0x18, %rcx
movzwl -0x26(%rbp), %edx
addq %rdx, %rcx
addq %rcx, %rax
movq %rax, -0x60(%rbp)
leaq -0x58(%rbp), %rdi
leaq -0x60(%rbp), %rsi
leaq -0x48(%rbp), %rdx
callq 0x76890
movq -0x70(%rbp), %rdi
addq $0x48, %rdi
leaq -0x58(%rbp), %rsi
callq 0x51450
movq -0x70(%rbp), %rax
movq (%rax), %rcx
addq $0x18, %rcx
movq %rcx, -0x68(%rbp)
movzbl 0x1a(%rax), %eax
movq %rax, -0x80(%rbp)
subq $0x50, %rax
ja 0x69e98
movq -0x80(%rbp), %rax
leaq 0x135b3(%rip), %rcx     # 0x7d0d0
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movzbl -0x27(%rbp), %eax
cmpl $0x0, %eax
je 0x69b3d
movzbl -0x27(%rbp), %eax
cmpl $0x4, %eax
je 0x69b3d
jmp 0x69eb2
movzwl -0x26(%rbp), %eax
cmpl $0x0, %eax
je 0x69b4d
cmpq $0x0, -0x48(%rbp)
jbe 0x69b52
jmp 0x69eb2
movzbl -0x27(%rbp), %eax
cmpl $0x4, %eax
jne 0x69b71
movq -0x68(%rbp), %rdi
callq 0x69ec0
movq %rax, %rcx
movq -0x70(%rbp), %rax
movq %rcx, 0x40(%rax)
jmp 0x69b7d
movq -0x70(%rbp), %rax
movq $-0x1, 0x40(%rax)
jmp 0x69ea8
movzbl -0x27(%rbp), %eax
cmpl $0x8, %eax
jne 0x69b9b
movzwl -0x26(%rbp), %eax
cmpl $0x0, %eax
je 0x69b9b
cmpq $0x0, -0x48(%rbp)
jne 0x69ba0
jmp 0x69eb2
movq -0x70(%rbp), %rsi
movq -0x68(%rbp), %rdi
addq $0x38, %rsi
callq 0x5d360
movq -0x68(%rbp), %rdi
addq $0x4, %rdi
callq 0x69ec0
movq %rax, %rcx
movq -0x70(%rbp), %rax
movq %rcx, 0x40(%rax)
jmp 0x69ea8
movzbl -0x27(%rbp), %eax
cmpl $0x0, %eax
jne 0x69be7
movzwl -0x26(%rbp), %eax
cmpl $0x0, %eax
je 0x69be7
cmpq $0x0, -0x48(%rbp)
jbe 0x69bec
jmp 0x69eb2
jmp 0x69ea8
movzbl -0x27(%rbp), %eax
cmpl $0x14, %eax
jne 0x69c0a
movzwl -0x26(%rbp), %eax
cmpl $0x0, %eax
je 0x69c0a
cmpq $0x0, -0x48(%rbp)
jbe 0x69c0f
jmp 0x69eb2
movq -0x70(%rbp), %rsi
movq -0x68(%rbp), %rdi
addq $0x58, %rsi
callq 0x76850
movq -0x70(%rbp), %rsi
movq -0x68(%rbp), %rdi
addq $0x8, %rdi
addq $0x60, %rsi
callq 0x76850
movq -0x68(%rbp), %rdi
addq $0x10, %rdi
callq 0x69ec0
movq %rax, %rcx
movq -0x70(%rbp), %rax
movq %rcx, 0x40(%rax)
jmp 0x69ea8
movzwl -0x26(%rbp), %eax
cmpl $0x0, %eax
je 0x69c6b
movzbl -0x27(%rbp), %eax
cmpl $0x4, %eax
jne 0x69c6b
cmpq $0x0, -0x48(%rbp)
je 0x69c70
jmp 0x69eb2
movq -0x68(%rbp), %rdi
callq 0x69ec0
movq %rax, %rcx
movq -0x70(%rbp), %rax
movq %rcx, 0x40(%rax)
jmp 0x69ea8
movzbl -0x27(%rbp), %eax
cmpl $0x0, %eax
je 0x69ca0
movzbl -0x27(%rbp), %eax
cmpl $0x4, %eax
je 0x69ca0
jmp 0x69eb2
movzwl -0x26(%rbp), %eax
cmpl $0x0, %eax
jne 0x69cb0
cmpq $0x0, -0x48(%rbp)
jbe 0x69cb5
jmp 0x69eb2
movzbl -0x27(%rbp), %eax
cmpl $0x4, %eax
jne 0x69cd7
movq -0x68(%rbp), %rdi
callq 0x69ec0
movq %rax, %rcx
movq -0x70(%rbp), %rax
movq %rcx, 0x40(%rax)
jmp 0x69d5d
leaq 0x462e2(%rip), %rax     # 0xaffc0
movq %rax, -0x8(%rbp)
movl $0x0, -0xc(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0x90(%rbp)
movl -0xc(%rbp), %edi
movl $0xffff, %esi           # imm = 0xFFFF
callq 0x104e0
movl %eax, -0x10(%rbp)
movl -0xc(%rbp), %eax
movl %eax, -0x84(%rbp)
decl %eax
subl $0x2, %eax
jb 0x69d33
jmp 0x69d16
movl -0x84(%rbp), %eax
subl $0x5, %eax
je 0x69d43
jmp 0x69d23
movq -0x90(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x18(%rbp)
jmp 0x69d51
movq -0x90(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x18(%rbp)
jmp 0x69d51
movq -0x90(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x18(%rbp)
movq -0x70(%rbp), %rax
movq -0x18(%rbp), %rcx
movq %rcx, 0x40(%rax)
jmp 0x69ea8
movzbl -0x27(%rbp), %eax
cmpl $0x0, %eax
jne 0x69d7b
movzwl -0x26(%rbp), %eax
cmpl $0x0, %eax
je 0x69d7b
cmpq $0x0, -0x48(%rbp)
jne 0x69d80
jmp 0x69eb2
jmp 0x69ea8
movzbl -0x27(%rbp), %eax
cmpl $0x0, %eax
jne 0x69d9e
movzwl -0x26(%rbp), %eax
cmpl $0x0, %eax
je 0x69d9e
cmpq $0x0, -0x48(%rbp)
jbe 0x69da3
jmp 0x69eb2
jmp 0x69ea8
movzbl -0x27(%rbp), %eax
cmpl $0x0, %eax
jne 0x69db8
cmpq $0x0, -0x48(%rbp)
je 0x69dbd
jmp 0x69eb2
movzwl -0x26(%rbp), %eax
cmpl $0x8, %eax
jne 0x69df5
movq -0x68(%rbp), %rax
movq (%rax), %rax
movabsq $0x73676e6974746573, %rcx # imm = 0x73676E6974746573
subq %rcx, %rax
setne %al
movzbl %al, %eax
cmpl $0x0, %eax
jne 0x69df5
movq -0x70(%rbp), %rax
movl $0x1, 0x68(%rax)
jmp 0x69e80
movzwl -0x26(%rbp), %eax
cmpl $0x5, %eax
jne 0x69e4e
movq -0x68(%rbp), %rdi
leaq 0x14231(%rip), %rsi     # 0x7e03a
movl $0x5, %edx
callq 0x8280
cmpl $0x0, %eax
jne 0x69e25
movq -0x70(%rbp), %rax
movl $0x2, 0x68(%rax)
jmp 0x69e4c
movq -0x68(%rbp), %rdi
leaq 0x13d40(%rip), %rsi     # 0x7db70
movl $0x5, %edx
callq 0x8280
cmpl $0x0, %eax
jne 0x69e4a
movq -0x70(%rbp), %rax
movl $0x3, 0x68(%rax)
jmp 0x69e4c
jmp 0x69e7e
movzwl -0x26(%rbp), %eax
cmpl $0x3, %eax
jne 0x69e7c
movq -0x68(%rbp), %rdi
leaq 0x13d14(%rip), %rsi     # 0x7db76
movl $0x3, %edx
callq 0x8280
cmpl $0x0, %eax
jne 0x69e7c
movq -0x70(%rbp), %rax
movl $0x4, 0x68(%rax)
jmp 0x69e7e
jmp 0x69e80
jmp 0x69ea8
movzbl -0x27(%rbp), %eax
cmpl $0x0, %eax
jne 0x69e92
cmpq $0x0, -0x48(%rbp)
jbe 0x69e94
jmp 0x69eb2
jmp 0x69ea8
jmp 0x69ea8
movq -0x70(%rbp), %rax
movb $0x51, 0x1a(%rax)
movw $0x81, 0x18(%rax)
jmp 0x69eb2
movq -0x70(%rbp), %rax
movw $0x0, 0x18(%rax)
addq $0x90, %rsp
popq %rbp
retq
nopl (%rax,%rax)