blob: 67ae763dc9574367b13b7a9d2c12fa1b1436dcff [file] [log] [blame]
// 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.
#pragma once
#include <bit>
#ifndef __APPLE__
#include <endian.h>
#endif
#include <stdint.h>
#include <string.h>
#include "olap/olap_common.h"
#include "util/slice.h"
namespace doris {
// TODO(zc): add encode big endian later when we need it
// use big endian when we have order requirement.
// little endian is more efficient when we use X86 CPU, so
// when we have no order needs, we prefer little endian encoding
inline void encode_fixed8(uint8_t* buf, uint8_t val) {
*buf = val;
}
inline void encode_fixed16_le(uint8_t* buf, uint16_t val) {
val = to_endian<std::endian::little>(val);
memcpy(buf, &val, sizeof(val));
}
inline void encode_fixed32_le(uint8_t* buf, uint32_t val) {
val = to_endian<std::endian::little>(val);
memcpy(buf, &val, sizeof(val));
}
inline void encode_fixed64_le(uint8_t* buf, uint64_t val) {
val = to_endian<std::endian::little>(val);
memcpy(buf, &val, sizeof(val));
}
inline void encode_fixed128_le(uint8_t* buf, uint128_t val) {
val = to_endian<std::endian::little>(val);
memcpy(buf, &val, sizeof(val));
}
inline uint8_t decode_fixed8(const uint8_t* buf) {
return *buf;
}
inline uint16_t decode_fixed16_le(const uint8_t* buf) {
uint16_t res;
memcpy(&res, buf, sizeof(res));
return to_endian<std::endian::little>(res);
}
inline uint32_t decode_fixed32_le(const uint8_t* buf) {
uint32_t res;
memcpy(&res, buf, sizeof(res));
return to_endian<std::endian::little>(res);
}
inline uint64_t decode_fixed64_le(const uint8_t* buf) {
uint64_t res;
memcpy(&res, buf, sizeof(res));
return to_endian<std::endian::little>(res);
}
inline uint128_t decode_fixed128_le(const uint8_t* buf) {
uint128_t res;
memcpy(&res, buf, sizeof(res));
return to_endian<std::endian::little>(res);
}
template <typename T>
void put_fixed32_le(T* dst, uint32_t val) {
uint8_t buf[sizeof(val)];
encode_fixed32_le(buf, val);
dst->append((char*)buf, sizeof(buf));
}
template <typename T>
void put_fixed64_le(T* dst, uint64_t val) {
uint8_t buf[sizeof(val)];
encode_fixed64_le(buf, val);
dst->append((char*)buf, sizeof(buf));
}
// Returns the length of the varint32 or varint64 encoding of "v"
inline int varint_length(uint64_t v) {
int len = 1;
while (v >= 128) {
v >>= 7;
len++;
}
return len;
}
template <typename T>
void put_fixed128_le(T* dst, uint128_t val) {
uint8_t buf[sizeof(val)];
encode_fixed128_le(buf, val);
dst->append((char*)buf, sizeof(buf));
}
extern uint8_t* encode_varint32(uint8_t* dst, uint32_t value);
extern uint8_t* encode_varint64(uint8_t* dst, uint64_t value);
inline uint8_t* encode_varint64(uint8_t* dst, uint64_t v) {
static const unsigned int B = 128;
while (v >= B) {
// Fetch low seven bits from current v, and the eight bit is marked as compression mark.
// v | B is optimised from (v & (B-1)) | B, because result is assigned to uint8_t and other bits
// is cleared by implicit conversion.
*(dst++) = v | B;
v >>= 7;
}
*(dst++) = static_cast<unsigned char>(v);
return dst;
}
extern const uint8_t* decode_varint32_ptr_fallback(const uint8_t* p, const uint8_t* limit,
uint32_t* value);
inline const uint8_t* decode_varint32_ptr(const uint8_t* ptr, const uint8_t* limit,
uint32_t* value) {
if (ptr < limit) {
uint32_t result = *ptr;
if ((result & 128) == 0) {
*value = result;
return ptr + 1;
}
}
return decode_varint32_ptr_fallback(ptr, limit, value);
}
extern const uint8_t* decode_varint64_ptr(const uint8_t* p, const uint8_t* limit, uint64_t* value);
template <typename T>
void put_varint32(T* dst, uint32_t v) {
uint8_t buf[16];
uint8_t* ptr = encode_varint32(buf, v);
dst->append((char*)buf, static_cast<size_t>(ptr - buf));
}
template <typename T>
void put_varint64(T* dst, uint64_t v) {
uint8_t buf[16];
uint8_t* ptr = encode_varint64(buf, v);
dst->append((char*)buf, static_cast<size_t>(ptr - buf));
}
template <typename T>
void put_length_prefixed_slice(T* dst, const Slice& value) {
put_varint32(dst, value.get_size());
dst->append(value.get_data(), value.get_size());
}
template <typename T>
void put_varint64_varint32(T* dst, uint64_t v1, uint32_t v2) {
uint8_t buf[16];
uint8_t* ptr = encode_varint64(buf, v1);
ptr = encode_varint32(ptr, v2);
dst->append((char*)buf, static_cast<size_t>(ptr - buf));
}
// parse a varint32 from the start of `input` into `val`.
// on success, return true and advance `input` past the parsed value.
// on failure, return false and `input` is not modified.
inline bool get_varint32(Slice* input, uint32_t* val) {
const uint8_t* p = (const uint8_t*)input->data;
const uint8_t* limit = p + input->size;
const uint8_t* q = decode_varint32_ptr(p, limit, val);
if (q == nullptr) {
return false;
} else {
*input = Slice(q, limit - q);
return true;
}
}
// parse a varint64 from the start of `input` into `val`.
// on success, return true and advance `input` past the parsed value.
// on failure, return false and `input` is not modified.
inline bool get_varint64(Slice* input, uint64_t* val) {
const uint8_t* p = (const uint8_t*)input->data;
const uint8_t* limit = p + input->size;
const uint8_t* q = decode_varint64_ptr(p, limit, val);
if (q == nullptr) {
return false;
} else {
*input = Slice(q, limit - q);
return true;
}
}
// parse a length-prefixed-slice from the start of `input` into `val`.
// on success, return true and advance `input` past the parsed value.
// on failure, return false and `input` may or may not be modified.
inline bool get_length_prefixed_slice(Slice* input, Slice* val) {
uint32_t len;
if (get_varint32(input, &len) && input->get_size() >= len) {
*val = Slice(input->get_data(), len);
input->remove_prefix(len);
return true;
} else {
return false;
}
}
} // namespace doris