StatusOr ZipList::Next()

in src/storage/rdb/rdb_ziplist.cc [40:122]


StatusOr<std::string> ZipList::Next() {
  auto prev_entry_encoded_size = getEncodedLengthSize(pre_entry_len_);
  pos_ += prev_entry_encoded_size;
  GET_OR_RET(peekOK(1));
  auto encoding = static_cast<uint8_t>(input_[pos_]);
  if (encoding < ZIP_STR_MASK) {
    encoding &= ZIP_STR_MASK;
  }

  uint32_t len = 0, len_bytes = 0;
  std::string value;
  if ((encoding) < ZIP_STR_MASK) {
    // For integer type, needs to convert to uint8_t* to avoid signed extension
    auto data = reinterpret_cast<const uint8_t *>(input_.data());
    if ((encoding) == ZIP_STR_06B) {
      len_bytes = 1;
      len = data[pos_] & 0x3F;
    } else if ((encoding) == ZIP_STR_14B) {
      GET_OR_RET(peekOK(2));
      len_bytes = 2;
      len = ((static_cast<uint32_t>(data[pos_]) & 0x3F) << 8) | static_cast<uint32_t>(data[pos_ + 1]);
    } else if ((encoding) == ZIP_STR_32B) {
      GET_OR_RET(peekOK(5));
      len_bytes = 5;
      len = (static_cast<uint32_t>(data[pos_ + 1]) << 24) | (static_cast<uint32_t>(data[pos_ + 2]) << 16) |
            (static_cast<uint32_t>(data[pos_ + 3]) << 8) | static_cast<uint32_t>(data[pos_ + 4]);
    } else {
      return {Status::NotOK, "invalid ziplist encoding"};
    }
    pos_ += len_bytes;
    GET_OR_RET(peekOK(len));
    value = input_.substr(pos_, len);
    pos_ += len;
    setPreEntryLen(len_bytes + len + prev_entry_encoded_size);
  } else {
    GET_OR_RET(peekOK(1));
    pos_ += 1 /* the number bytes of length*/;
    if ((encoding) == ZIP_INT_8B) {
      GET_OR_RET(peekOK(1));
      setPreEntryLen(2);  // 1byte for encoding and 1byte for the prev entry length
      return std::to_string(input_[pos_++]);
    } else if ((encoding) == ZIP_INT_16B) {
      GET_OR_RET(peekOK(2));
      int16_t i16 = 0;
      memcpy(&i16, input_.data() + pos_, sizeof(int16_t));
      memrev16ifbe(&i16);
      setPreEntryLen(3);  // 2byte for encoding and 1byte for the prev entry length
      pos_ += sizeof(int16_t);
      return std::to_string(i16);
    } else if ((encoding) == ZIP_INT_24B) {
      GET_OR_RET(peekOK(3));
      int32_t i32 = 0;
      memcpy(reinterpret_cast<uint8_t *>(&i32) + 1, input_.data() + pos_, sizeof(int32_t) - 1);
      memrev32ifbe(&i32);
      i32 >>= 8;
      setPreEntryLen(4);  // 3byte for encoding and 1byte for the prev entry length
      pos_ += sizeof(int32_t) - 1;
      return std::to_string(i32);
    } else if ((encoding) == ZIP_INT_32B) {
      GET_OR_RET(peekOK(4));
      int32_t i32 = 0;
      memcpy(&i32, input_.data() + pos_, sizeof(int32_t));
      memrev32ifbe(&i32);
      setPreEntryLen(5);  // 4byte for encoding and 1byte for the prev entry length
      pos_ += sizeof(int32_t);
      return std::to_string(i32);
    } else if ((encoding) == ZIP_INT_64B) {
      GET_OR_RET(peekOK(8));
      int64_t i64 = 0;
      memcpy(&i64, input_.data() + pos_, sizeof(int64_t));
      memrev64ifbe(&i64);
      setPreEntryLen(9);  // 8byte for encoding and 1byte for the prev entry length
      pos_ += sizeof(int64_t);
      return std::to_string(i64);
    } else if (encoding >= ZIP_INT_IMM_MIN && encoding <= ZIP_INT_IMM_MAX) {
      setPreEntryLen(1);  // 8byte for encoding and 1byte for the prev entry length
      return std::to_string((encoding & 0x0F) - 1);
    } else {
      return {Status::NotOK, "invalid ziplist encoding"};
    }
  }
  return value;
}