// 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 #include #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 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(buf[0]) << 56) | (static_cast(buf[1]) << 48) | (static_cast(buf[2]) << 40) | (static_cast(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(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(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(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("Insufficient buffer length"); return false; } zlong |= static_cast(**buf & 0x7f) << shift; shift += 7; more = (**buf & 0x80) != 0; ++(*buf); --(*buf_len); } while (more); *val = (zlong >> 1) ^ -(zlong & 1); return true; } template 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(ss.str()); return false; } *val = *reinterpret_cast(*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(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