| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480 |
- // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
- // This source code is licensed under both the GPLv2 (found in the
- // COPYING file in the root directory) and Apache 2.0 License
- // (found in the LICENSE.Apache file in the root directory).
- //
- // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file. See the AUTHORS file for names of contributors.
- //
- // Endian-neutral encoding:
- // * Fixed-length numbers are encoded with least-significant byte first
- // * In addition we support variable length "varint" encoding
- // * Strings are encoded prefixed by their length in varint format
- #pragma once
- #include <algorithm>
- #include <stdint.h>
- #include <string.h>
- #include <string>
- #include "rocksdb/write_batch.h"
- #include "port/port.h"
- // Some processors does not allow unaligned access to memory
- #if defined(__sparc)
- #define PLATFORM_UNALIGNED_ACCESS_NOT_ALLOWED
- #endif
- namespace ROCKSDB_NAMESPACE {
- // The maximum length of a varint in bytes for 64-bit.
- const unsigned int kMaxVarint64Length = 10;
- // Standard Put... routines append to a string
- extern void PutFixed16(std::string* dst, uint16_t value);
- extern void PutFixed32(std::string* dst, uint32_t value);
- extern void PutFixed64(std::string* dst, uint64_t value);
- extern void PutVarint32(std::string* dst, uint32_t value);
- extern void PutVarint32Varint32(std::string* dst, uint32_t value1,
- uint32_t value2);
- extern void PutVarint32Varint32Varint32(std::string* dst, uint32_t value1,
- uint32_t value2, uint32_t value3);
- extern void PutVarint64(std::string* dst, uint64_t value);
- extern void PutVarint64Varint64(std::string* dst, uint64_t value1,
- uint64_t value2);
- extern void PutVarint32Varint64(std::string* dst, uint32_t value1,
- uint64_t value2);
- extern void PutVarint32Varint32Varint64(std::string* dst, uint32_t value1,
- uint32_t value2, uint64_t value3);
- extern void PutLengthPrefixedSlice(std::string* dst, const Slice& value);
- extern void PutLengthPrefixedSliceParts(std::string* dst,
- const SliceParts& slice_parts);
- extern void PutLengthPrefixedSlicePartsWithPadding(
- std::string* dst, const SliceParts& slice_parts, size_t pad_sz);
- // Standard Get... routines parse a value from the beginning of a Slice
- // and advance the slice past the parsed value.
- extern bool GetFixed64(Slice* input, uint64_t* value);
- extern bool GetFixed32(Slice* input, uint32_t* value);
- extern bool GetFixed16(Slice* input, uint16_t* value);
- extern bool GetVarint32(Slice* input, uint32_t* value);
- extern bool GetVarint64(Slice* input, uint64_t* value);
- extern bool GetVarsignedint64(Slice* input, int64_t* value);
- extern bool GetLengthPrefixedSlice(Slice* input, Slice* result);
- // This function assumes data is well-formed.
- extern Slice GetLengthPrefixedSlice(const char* data);
- extern Slice GetSliceUntil(Slice* slice, char delimiter);
- // Borrowed from
- // https://github.com/facebook/fbthrift/blob/449a5f77f9f9bae72c9eb5e78093247eef185c04/thrift/lib/cpp/util/VarintUtils-inl.h#L202-L208
- constexpr inline uint64_t i64ToZigzag(const int64_t l) {
- return (static_cast<uint64_t>(l) << 1) ^ static_cast<uint64_t>(l >> 63);
- }
- inline int64_t zigzagToI64(uint64_t n) {
- return (n >> 1) ^ -static_cast<int64_t>(n & 1);
- }
- // Pointer-based variants of GetVarint... These either store a value
- // in *v and return a pointer just past the parsed value, or return
- // nullptr on error. These routines only look at bytes in the range
- // [p..limit-1]
- extern const char* GetVarint32Ptr(const char* p,const char* limit, uint32_t* v);
- extern const char* GetVarint64Ptr(const char* p,const char* limit, uint64_t* v);
- inline const char* GetVarsignedint64Ptr(const char* p, const char* limit,
- int64_t* value) {
- uint64_t u = 0;
- const char* ret = GetVarint64Ptr(p, limit, &u);
- *value = zigzagToI64(u);
- return ret;
- }
- // Returns the length of the varint32 or varint64 encoding of "v"
- extern int VarintLength(uint64_t v);
- // Lower-level versions of Put... that write directly into a character buffer
- // REQUIRES: dst has enough space for the value being written
- extern void EncodeFixed16(char* dst, uint16_t value);
- extern void EncodeFixed32(char* dst, uint32_t value);
- extern void EncodeFixed64(char* dst, uint64_t value);
- // Lower-level versions of Put... that write directly into a character buffer
- // and return a pointer just past the last byte written.
- // REQUIRES: dst has enough space for the value being written
- extern char* EncodeVarint32(char* dst, uint32_t value);
- extern char* EncodeVarint64(char* dst, uint64_t value);
- // Lower-level versions of Get... that read directly from a character buffer
- // without any bounds checking.
- inline uint16_t DecodeFixed16(const char* ptr) {
- if (port::kLittleEndian) {
- // Load the raw bytes
- uint16_t result;
- memcpy(&result, ptr, sizeof(result)); // gcc optimizes this to a plain load
- return result;
- } else {
- return ((static_cast<uint16_t>(static_cast<unsigned char>(ptr[0]))) |
- (static_cast<uint16_t>(static_cast<unsigned char>(ptr[1])) << 8));
- }
- }
- inline uint32_t DecodeFixed32(const char* ptr) {
- if (port::kLittleEndian) {
- // Load the raw bytes
- uint32_t result;
- memcpy(&result, ptr, sizeof(result)); // gcc optimizes this to a plain load
- return result;
- } else {
- return ((static_cast<uint32_t>(static_cast<unsigned char>(ptr[0])))
- | (static_cast<uint32_t>(static_cast<unsigned char>(ptr[1])) << 8)
- | (static_cast<uint32_t>(static_cast<unsigned char>(ptr[2])) << 16)
- | (static_cast<uint32_t>(static_cast<unsigned char>(ptr[3])) << 24));
- }
- }
- inline uint64_t DecodeFixed64(const char* ptr) {
- if (port::kLittleEndian) {
- // Load the raw bytes
- uint64_t result;
- memcpy(&result, ptr, sizeof(result)); // gcc optimizes this to a plain load
- return result;
- } else {
- uint64_t lo = DecodeFixed32(ptr);
- uint64_t hi = DecodeFixed32(ptr + 4);
- return (hi << 32) | lo;
- }
- }
- // Internal routine for use by fallback path of GetVarint32Ptr
- extern const char* GetVarint32PtrFallback(const char* p,
- const char* limit,
- uint32_t* value);
- inline const char* GetVarint32Ptr(const char* p,
- const char* limit,
- uint32_t* value) {
- if (p < limit) {
- uint32_t result = *(reinterpret_cast<const unsigned char*>(p));
- if ((result & 128) == 0) {
- *value = result;
- return p + 1;
- }
- }
- return GetVarint32PtrFallback(p, limit, value);
- }
- // -- Implementation of the functions declared above
- inline void EncodeFixed16(char* buf, uint16_t value) {
- if (port::kLittleEndian) {
- memcpy(buf, &value, sizeof(value));
- } else {
- buf[0] = value & 0xff;
- buf[1] = (value >> 8) & 0xff;
- }
- }
- inline void EncodeFixed32(char* buf, uint32_t value) {
- if (port::kLittleEndian) {
- memcpy(buf, &value, sizeof(value));
- } else {
- buf[0] = value & 0xff;
- buf[1] = (value >> 8) & 0xff;
- buf[2] = (value >> 16) & 0xff;
- buf[3] = (value >> 24) & 0xff;
- }
- }
- inline void EncodeFixed64(char* buf, uint64_t value) {
- if (port::kLittleEndian) {
- memcpy(buf, &value, sizeof(value));
- } else {
- buf[0] = value & 0xff;
- buf[1] = (value >> 8) & 0xff;
- buf[2] = (value >> 16) & 0xff;
- buf[3] = (value >> 24) & 0xff;
- buf[4] = (value >> 32) & 0xff;
- buf[5] = (value >> 40) & 0xff;
- buf[6] = (value >> 48) & 0xff;
- buf[7] = (value >> 56) & 0xff;
- }
- }
- // Pull the last 8 bits and cast it to a character
- inline void PutFixed16(std::string* dst, uint16_t value) {
- if (port::kLittleEndian) {
- dst->append(const_cast<const char*>(reinterpret_cast<char*>(&value)),
- sizeof(value));
- } else {
- char buf[sizeof(value)];
- EncodeFixed16(buf, value);
- dst->append(buf, sizeof(buf));
- }
- }
- inline void PutFixed32(std::string* dst, uint32_t value) {
- if (port::kLittleEndian) {
- dst->append(const_cast<const char*>(reinterpret_cast<char*>(&value)),
- sizeof(value));
- } else {
- char buf[sizeof(value)];
- EncodeFixed32(buf, value);
- dst->append(buf, sizeof(buf));
- }
- }
- inline void PutFixed64(std::string* dst, uint64_t value) {
- if (port::kLittleEndian) {
- dst->append(const_cast<const char*>(reinterpret_cast<char*>(&value)),
- sizeof(value));
- } else {
- char buf[sizeof(value)];
- EncodeFixed64(buf, value);
- dst->append(buf, sizeof(buf));
- }
- }
- inline void PutVarint32(std::string* dst, uint32_t v) {
- char buf[5];
- char* ptr = EncodeVarint32(buf, v);
- dst->append(buf, static_cast<size_t>(ptr - buf));
- }
- inline void PutVarint32Varint32(std::string* dst, uint32_t v1, uint32_t v2) {
- char buf[10];
- char* ptr = EncodeVarint32(buf, v1);
- ptr = EncodeVarint32(ptr, v2);
- dst->append(buf, static_cast<size_t>(ptr - buf));
- }
- inline void PutVarint32Varint32Varint32(std::string* dst, uint32_t v1,
- uint32_t v2, uint32_t v3) {
- char buf[15];
- char* ptr = EncodeVarint32(buf, v1);
- ptr = EncodeVarint32(ptr, v2);
- ptr = EncodeVarint32(ptr, v3);
- dst->append(buf, static_cast<size_t>(ptr - buf));
- }
- inline char* EncodeVarint64(char* dst, uint64_t v) {
- static const unsigned int B = 128;
- unsigned char* ptr = reinterpret_cast<unsigned char*>(dst);
- while (v >= B) {
- *(ptr++) = (v & (B - 1)) | B;
- v >>= 7;
- }
- *(ptr++) = static_cast<unsigned char>(v);
- return reinterpret_cast<char*>(ptr);
- }
- inline void PutVarint64(std::string* dst, uint64_t v) {
- char buf[kMaxVarint64Length];
- char* ptr = EncodeVarint64(buf, v);
- dst->append(buf, static_cast<size_t>(ptr - buf));
- }
- inline void PutVarsignedint64(std::string* dst, int64_t v) {
- char buf[kMaxVarint64Length];
- // Using Zigzag format to convert signed to unsigned
- char* ptr = EncodeVarint64(buf, i64ToZigzag(v));
- dst->append(buf, static_cast<size_t>(ptr - buf));
- }
- inline void PutVarint64Varint64(std::string* dst, uint64_t v1, uint64_t v2) {
- char buf[20];
- char* ptr = EncodeVarint64(buf, v1);
- ptr = EncodeVarint64(ptr, v2);
- dst->append(buf, static_cast<size_t>(ptr - buf));
- }
- inline void PutVarint32Varint64(std::string* dst, uint32_t v1, uint64_t v2) {
- char buf[15];
- char* ptr = EncodeVarint32(buf, v1);
- ptr = EncodeVarint64(ptr, v2);
- dst->append(buf, static_cast<size_t>(ptr - buf));
- }
- inline void PutVarint32Varint32Varint64(std::string* dst, uint32_t v1,
- uint32_t v2, uint64_t v3) {
- char buf[20];
- char* ptr = EncodeVarint32(buf, v1);
- ptr = EncodeVarint32(ptr, v2);
- ptr = EncodeVarint64(ptr, v3);
- dst->append(buf, static_cast<size_t>(ptr - buf));
- }
- inline void PutLengthPrefixedSlice(std::string* dst, const Slice& value) {
- PutVarint32(dst, static_cast<uint32_t>(value.size()));
- dst->append(value.data(), value.size());
- }
- inline void PutLengthPrefixedSliceParts(std::string* dst, size_t total_bytes,
- const SliceParts& slice_parts) {
- for (int i = 0; i < slice_parts.num_parts; ++i) {
- total_bytes += slice_parts.parts[i].size();
- }
- PutVarint32(dst, static_cast<uint32_t>(total_bytes));
- for (int i = 0; i < slice_parts.num_parts; ++i) {
- dst->append(slice_parts.parts[i].data(), slice_parts.parts[i].size());
- }
- }
- inline void PutLengthPrefixedSliceParts(std::string* dst,
- const SliceParts& slice_parts) {
- PutLengthPrefixedSliceParts(dst, /*total_bytes=*/0, slice_parts);
- }
- inline void PutLengthPrefixedSlicePartsWithPadding(
- std::string* dst, const SliceParts& slice_parts, size_t pad_sz) {
- PutLengthPrefixedSliceParts(dst, /*total_bytes=*/pad_sz, slice_parts);
- dst->append(pad_sz, '\0');
- }
- inline int VarintLength(uint64_t v) {
- int len = 1;
- while (v >= 128) {
- v >>= 7;
- len++;
- }
- return len;
- }
- inline bool GetFixed64(Slice* input, uint64_t* value) {
- if (input->size() < sizeof(uint64_t)) {
- return false;
- }
- *value = DecodeFixed64(input->data());
- input->remove_prefix(sizeof(uint64_t));
- return true;
- }
- inline bool GetFixed32(Slice* input, uint32_t* value) {
- if (input->size() < sizeof(uint32_t)) {
- return false;
- }
- *value = DecodeFixed32(input->data());
- input->remove_prefix(sizeof(uint32_t));
- return true;
- }
- inline bool GetFixed16(Slice* input, uint16_t* value) {
- if (input->size() < sizeof(uint16_t)) {
- return false;
- }
- *value = DecodeFixed16(input->data());
- input->remove_prefix(sizeof(uint16_t));
- return true;
- }
- inline bool GetVarint32(Slice* input, uint32_t* value) {
- const char* p = input->data();
- const char* limit = p + input->size();
- const char* q = GetVarint32Ptr(p, limit, value);
- if (q == nullptr) {
- return false;
- } else {
- *input = Slice(q, static_cast<size_t>(limit - q));
- return true;
- }
- }
- inline bool GetVarint64(Slice* input, uint64_t* value) {
- const char* p = input->data();
- const char* limit = p + input->size();
- const char* q = GetVarint64Ptr(p, limit, value);
- if (q == nullptr) {
- return false;
- } else {
- *input = Slice(q, static_cast<size_t>(limit - q));
- return true;
- }
- }
- inline bool GetVarsignedint64(Slice* input, int64_t* value) {
- const char* p = input->data();
- const char* limit = p + input->size();
- const char* q = GetVarsignedint64Ptr(p, limit, value);
- if (q == nullptr) {
- return false;
- } else {
- *input = Slice(q, static_cast<size_t>(limit - q));
- return true;
- }
- }
- // Provide an interface for platform independent endianness transformation
- inline uint64_t EndianTransform(uint64_t input, size_t size) {
- char* pos = reinterpret_cast<char*>(&input);
- uint64_t ret_val = 0;
- for (size_t i = 0; i < size; ++i) {
- ret_val |= (static_cast<uint64_t>(static_cast<unsigned char>(pos[i]))
- << ((size - i - 1) << 3));
- }
- return ret_val;
- }
- inline bool GetLengthPrefixedSlice(Slice* input, Slice* result) {
- uint32_t len = 0;
- if (GetVarint32(input, &len) && input->size() >= len) {
- *result = Slice(input->data(), len);
- input->remove_prefix(len);
- return true;
- } else {
- return false;
- }
- }
- inline Slice GetLengthPrefixedSlice(const char* data) {
- uint32_t len = 0;
- // +5: we assume "data" is not corrupted
- // unsigned char is 7 bits, uint32_t is 32 bits, need 5 unsigned char
- auto p = GetVarint32Ptr(data, data + 5 /* limit */, &len);
- return Slice(p, len);
- }
- inline Slice GetSliceUntil(Slice* slice, char delimiter) {
- uint32_t len = 0;
- for (len = 0; len < slice->size() && slice->data()[len] != delimiter; ++len) {
- // nothing
- }
- Slice ret(slice->data(), len);
- slice->remove_prefix(len + ((len < slice->size()) ? 1 : 0));
- return ret;
- }
- template<class T>
- #ifdef ROCKSDB_UBSAN_RUN
- #if defined(__clang__)
- __attribute__((__no_sanitize__("alignment")))
- #elif defined(__GNUC__)
- __attribute__((__no_sanitize_undefined__))
- #endif
- #endif
- inline void PutUnaligned(T *memory, const T &value) {
- #if defined(PLATFORM_UNALIGNED_ACCESS_NOT_ALLOWED)
- char *nonAlignedMemory = reinterpret_cast<char*>(memory);
- memcpy(nonAlignedMemory, reinterpret_cast<const char*>(&value), sizeof(T));
- #else
- *memory = value;
- #endif
- }
- template<class T>
- #ifdef ROCKSDB_UBSAN_RUN
- #if defined(__clang__)
- __attribute__((__no_sanitize__("alignment")))
- #elif defined(__GNUC__)
- __attribute__((__no_sanitize_undefined__))
- #endif
- #endif
- inline void GetUnaligned(const T *memory, T *value) {
- #if defined(PLATFORM_UNALIGNED_ACCESS_NOT_ALLOWED)
- char *nonAlignedMemory = reinterpret_cast<char*>(value);
- memcpy(nonAlignedMemory, reinterpret_cast<const char*>(memory), sizeof(T));
- #else
- *value = *memory;
- #endif
- }
- } // namespace ROCKSDB_NAMESPACE
|