239 lines
7.6 KiB
C++
239 lines
7.6 KiB
C++
// Licensed to the Apache Software Foundation (ASF) under one
|
|
// or more contributor license agreements. See the NOTICE file
|
|
// distributed with this work for additional information
|
|
// regarding copyright ownership. The ASF licenses this file
|
|
// to you under the Apache License, Version 2.0 (the
|
|
// "License"); you may not use this file except in compliance
|
|
// with the License. You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing,
|
|
// software distributed under the License is distributed on an
|
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
// KIND, either express or implied. See the License for the
|
|
// specific language governing permissions and limitations
|
|
// under the License.
|
|
|
|
#ifndef DORIS_BE_SRC_QUERY_EXEC_READ_WRITE_UTIL_H
|
|
#define DORIS_BE_SRC_QUERY_EXEC_READ_WRITE_UTIL_H
|
|
|
|
#include <boost/cstdint.hpp>
|
|
#include <sstream>
|
|
#include "common/logging.h"
|
|
#include "common/status.h"
|
|
|
|
namespace doris {
|
|
|
|
#define RETURN_IF_FALSE(x) if (UNLIKELY(!(x))) return false
|
|
|
|
// Class for reading and writing various data types.
|
|
class ReadWriteUtil {
|
|
public:
|
|
// Maximum length for Writeable VInt
|
|
static const int MAX_VINT_LEN = 9;
|
|
|
|
// Maximum lengths for Zigzag encodings.
|
|
const static int MAX_ZINT_LEN = 5;
|
|
const static int MAX_ZLONG_LEN = 10;
|
|
|
|
// Put a zigzag encoded integer into a buffer and return its length.
|
|
static int put_zint(int32_t integer, uint8_t* buf);
|
|
|
|
// Put a zigzag encoded long integer into a buffer and return its length.
|
|
static int put_zlong(int64_t longint, uint8_t* buf);
|
|
|
|
// Get a big endian integer from a buffer. The buffer does not have to be word aligned.
|
|
static int32_t get_int(const uint8_t* buffer);
|
|
static int16_t get_small_int(const uint8_t* buffer);
|
|
static int64_t get_long_int(const uint8_t* buffer);
|
|
|
|
// Get a variable-length Long or int value from a byte buffer.
|
|
// Returns the length of the long/int
|
|
// If the size byte is corrupted then return -1;
|
|
static int get_vlong(uint8_t* buf, int64_t* vlong);
|
|
static int get_vint(uint8_t* buf, int32_t* vint);
|
|
|
|
// Read a variable-length Long value from a byte buffer starting at the specified
|
|
// byte offset.
|
|
static int get_vlong(uint8_t* buf, int64_t offset, int64_t* vlong);
|
|
|
|
// Put an Integer into a buffer in big endian order . The buffer must be at least
|
|
// 4 bytes long.
|
|
static void put_int(uint8_t* buf, int32_t integer);
|
|
|
|
// Dump the first length bytes of buf to a Hex string.
|
|
static std::string hex_dump(const uint8_t* buf, int64_t length);
|
|
static std::string hex_dump(const char* buf, int64_t length);
|
|
|
|
// Determines the sign of a VInt/VLong from the first byte.
|
|
static bool is_negative_vint(int8_t byte);
|
|
|
|
// Determines the total length in bytes of a Writable VInt/VLong from the first byte.
|
|
static int decode_vint_size(int8_t byte);
|
|
|
|
// The following methods read data from a buffer without assuming the buffer is long
|
|
// enough. If the buffer isn't long enough or another error occurs, they return false
|
|
// and update the status with the error. Otherwise they return true. buffer is advanced
|
|
// past the data read and buf_len is decremented appropriately.
|
|
|
|
// Read a zig-zag encoded long. This is the integer encoding defined by google.com
|
|
// protocol-buffers: https://developers.google.com/protocol-buffers/docs/encoding
|
|
static bool read_zlong(uint8_t** buf, int* buf_len, int64_t* val, Status* status);
|
|
|
|
// Read a zig-zag encoded int.
|
|
static bool read_zint(uint8_t** buf, int* buf_len, int32_t* val, Status* status);
|
|
|
|
// Read a native type T (e.g. bool, float) directly into output (i.e. input is cast
|
|
// directly to T and incremented by sizeof(T)).
|
|
template <class T>
|
|
static bool read(uint8_t** buf, int* buf_len, T* val, Status* status);
|
|
|
|
// Skip the next num_bytes bytes.
|
|
static bool skip_bytes(uint8_t** buf, int* buf_len, int num_bytes, Status* status);
|
|
};
|
|
|
|
inline int16_t ReadWriteUtil::get_small_int(const uint8_t* buf) {
|
|
return (buf[0] << 8) | buf[1];
|
|
}
|
|
|
|
inline int32_t ReadWriteUtil::get_int(const uint8_t* buf) {
|
|
return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
|
|
}
|
|
|
|
inline int64_t ReadWriteUtil::get_long_int(const uint8_t* buf) {
|
|
return (static_cast<int64_t>(buf[0]) << 56) |
|
|
(static_cast<int64_t>(buf[1]) << 48) |
|
|
(static_cast<int64_t>(buf[2]) << 40) |
|
|
(static_cast<int64_t>(buf[3]) << 32) |
|
|
(buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
|
|
}
|
|
|
|
inline void ReadWriteUtil::put_int(uint8_t* buf, int32_t integer) {
|
|
buf[0] = integer >> 24;
|
|
buf[1] = integer >> 16;
|
|
buf[2] = integer >> 8;
|
|
buf[3] = integer;
|
|
}
|
|
|
|
inline int ReadWriteUtil::get_vint(uint8_t* buf, int32_t* vint) {
|
|
int64_t vlong = 0;
|
|
int len = get_vlong(buf, &vlong);
|
|
*vint = static_cast<int32_t>(vlong);
|
|
return len;
|
|
}
|
|
|
|
inline int ReadWriteUtil::get_vlong(uint8_t* buf, int64_t* vlong) {
|
|
return get_vlong(buf, 0, vlong);
|
|
}
|
|
|
|
inline int ReadWriteUtil::get_vlong(uint8_t* buf, int64_t offset, int64_t* vlong) {
|
|
int8_t firstbyte = (int8_t) buf[0 + offset];
|
|
|
|
int len = decode_vint_size(firstbyte);
|
|
|
|
if (len > MAX_VINT_LEN) {
|
|
return -1;
|
|
}
|
|
|
|
if (len == 1) {
|
|
*vlong = static_cast<int64_t>(firstbyte);
|
|
return len;
|
|
}
|
|
|
|
*vlong &= ~*vlong;
|
|
|
|
for (int i = 1; i < len; i++) {
|
|
*vlong = (*vlong << 8) | buf[i + offset];
|
|
}
|
|
|
|
if (is_negative_vint(firstbyte)) {
|
|
*vlong = *vlong ^ ((int64_t) - 1);
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
inline bool ReadWriteUtil::read_zint(uint8_t** buf, int* buf_len, int32_t* val,
|
|
Status* status) {
|
|
int64_t zlong;
|
|
RETURN_IF_FALSE(read_zlong(buf, buf_len, &zlong, status));
|
|
*val = static_cast<int32_t>(zlong);
|
|
return true;
|
|
}
|
|
|
|
inline bool ReadWriteUtil::read_zlong(uint8_t** buf, int* buf_len, int64_t* val,
|
|
Status* status) {
|
|
uint64_t zlong = 0;
|
|
int shift = 0;
|
|
bool more;
|
|
|
|
do {
|
|
DCHECK_LE(shift, 64);
|
|
|
|
if (UNLIKELY(*buf_len < 1)) {
|
|
*status = Status::InternalError("Insufficient buffer length");
|
|
return false;
|
|
}
|
|
|
|
zlong |= static_cast<uint64_t>(**buf & 0x7f) << shift;
|
|
shift += 7;
|
|
more = (**buf & 0x80) != 0;
|
|
++(*buf);
|
|
--(*buf_len);
|
|
} while (more);
|
|
|
|
*val = (zlong >> 1) ^ -(zlong & 1);
|
|
return true;
|
|
}
|
|
|
|
template <class T>
|
|
inline bool ReadWriteUtil::read(uint8_t** buf, int* buf_len, T* val, Status* status) {
|
|
int val_len = sizeof(T);
|
|
|
|
if (UNLIKELY(val_len > *buf_len)) {
|
|
std::stringstream ss;
|
|
ss << "Cannot read " << val_len << " bytes, buffer length is " << *buf_len;
|
|
*status = Status::InternalError(ss.str());
|
|
return false;
|
|
}
|
|
|
|
*val = *reinterpret_cast<T*>(*buf);
|
|
*buf += val_len;
|
|
*buf_len -= val_len;
|
|
return true;
|
|
}
|
|
|
|
inline bool ReadWriteUtil::skip_bytes(uint8_t** buf, int* buf_len, int num_bytes,
|
|
Status* status) {
|
|
DCHECK_GE(*buf_len, 0);
|
|
|
|
if (UNLIKELY(num_bytes > *buf_len)) {
|
|
std::stringstream ss;
|
|
ss << "Cannot skip " << num_bytes << " bytes, buffer length is " << *buf_len;
|
|
*status = Status::InternalError(ss.str());
|
|
return false;
|
|
}
|
|
|
|
*buf += num_bytes;
|
|
*buf_len -= num_bytes;
|
|
return true;
|
|
}
|
|
|
|
inline bool ReadWriteUtil::is_negative_vint(int8_t byte) {
|
|
return byte < -120 || (byte >= -112 && byte < 0);
|
|
}
|
|
|
|
inline int ReadWriteUtil::decode_vint_size(int8_t byte) {
|
|
if (byte >= -112) {
|
|
return 1;
|
|
} else if (byte < -120) {
|
|
return -119 - byte;
|
|
}
|
|
|
|
return -111 - byte;
|
|
}
|
|
|
|
}
|
|
#endif
|