* Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
#ifndef FLINK_TNEL_BYTEBUFFER_H
#define FLINK_TNEL_BYTEBUFFER_H
#include <vector>
#include <cstddef>
#include <cstdint>
#include <memory>
#include "../include/common.h"
#include <libboundscheck/include/securec.h>
class ByteBuffer {
public:
explicit ByteBuffer(int capacity) : position_(0), limit_(capacity), mark_(-1), capacity_(capacity)
{
data_ = new uint8_t[capacity_];
}
ByteBuffer() : data_(nullptr), position_(0), limit_(0), mark_(-1), capacity_(0) {}
ByteBuffer(uint8_t* data, int capacity) : position_(0), limit_(capacity), mark_(-1), capacity_(capacity)
{
data_ = data;
reusedData = true;
}
inline int capacity() const;
inline int position() const;
inline int remaining() const;
inline bool hasRemaining() const;
inline void setPosition(int position);
inline void setLimit(int limit);
inline void clear();
inline void putBytes(const void* src, int len);
inline void putInt(int value);
inline void putLong(int64_t value);
inline void putByte(uint8_t value);
inline int64_t getLong();
inline uint8_t getByte();
inline void getBytes(uint8_t* dst, int len);
inline int limit();
inline void flip();
inline int getIntBigEndian();
inline int getIntBigEndian(int index);
inline uint8_t getInt();
inline uint8_t* getValue();
inline ByteBuffer* wrapOpt(uint8_t* data, int position, int length);
static inline ByteBuffer* wrap(uint8_t* data, int length);
static inline ByteBuffer* wrap(uint8_t* data, int position, int length);
static inline std::shared_ptr<ByteBuffer> wrap2(uint8_t *data_, int length);
inline int getSize()
{
return limit_;
}
static inline void showInternalInfo(ByteBuffer* buffer);
inline int getIntFromValue();
virtual ~ByteBuffer()
{
if (!reusedData) {
delete[] data_;
}
}
protected:
uint8_t* data_;
int position_;
int limit_;
int mark_;
int capacity_;
bool reusedData = false;
};
inline int ByteBuffer::capacity() const
{
return capacity_;
}
inline int ByteBuffer::remaining() const
{
int rem = limit_ - position_;
return rem > 0 ? rem : 0;
}
inline bool ByteBuffer::hasRemaining() const
{
return position_ < limit_;
}
inline int ByteBuffer::position() const
{
return position_;
}
inline void ByteBuffer::clear()
{
position_ = 0;
limit_ = capacity_;
mark_ = -1;
}
inline void ByteBuffer::putBytes(const void* src, int len)
{
if (position_ + len > capacity()) {
THROW_LOGIC_EXCEPTION("ByteBuffer overflow");
}
memcpy_s(data_ + position_, len, src, len);
position_ += len;
}
inline void ByteBuffer::putInt(int value)
{
auto curValue = static_cast<unsigned int>(value);
uint8_t bytes[4];
for (int i = 3; i >= 0; --i) {
bytes[i] = static_cast<uint8_t>(curValue & 0xFF);
curValue >>= 8;
}
putBytes(bytes, 4);
}
inline void ByteBuffer::putLong(int64_t value)
{
auto curValue = static_cast<unsigned long>(value);
uint8_t bytes[8];
for (int i = 7; i >= 0; --i) {
bytes[i] = static_cast<uint8_t>(curValue & 0xFF);
curValue >>= 8;
}
putBytes(bytes, 8);
}
inline void ByteBuffer::putByte(uint8_t value)
{
putBytes(&value, 1);
}
inline void ByteBuffer::flip()
{
position_ = 0;
mark_ = -1;
}
inline int64_t ByteBuffer::getLong()
{
const int LEN = 8;
if (position_ + LEN > limit_) {
THROW_LOGIC_EXCEPTION("ByteBuffer underflow");
}
unsigned long value = 0;
for (int i = 0; i < LEN; ++i) {
value <<= 8;
value |= static_cast<uint8_t>((data_)[position_ + i]);
}
position_ += LEN;
return static_cast<int64_t>(value);
}
inline uint8_t ByteBuffer::getInt()
{
const int INT_SIZE = 4;
if (position_ + INT_SIZE > limit_) {
THROW_LOGIC_EXCEPTION("ByteBuffer underflow");
}
unsigned int result = 0;
for (int i = 0; i < INT_SIZE; ++i) {
result <<= 8;
result |= static_cast<uint8_t>((data_)[position_ + i]);
}
position_ += INT_SIZE;
return result;
}
inline uint8_t ByteBuffer::getByte()
{
if (position_ + 1 > limit_) {
THROW_LOGIC_EXCEPTION("ByteBuffer underflow");
}
return (data_)[position_++];
}
inline void ByteBuffer::getBytes(uint8_t* dst, int len)
{
if (position_ + len > limit_) {
THROW_LOGIC_EXCEPTION("ByteBuffer underflow");
}
memcpy_s(dst, len, data_ + position_, len);
position_ += len;
}
inline int ByteBuffer::limit()
{
return limit_;
}
inline int ByteBuffer::getIntBigEndian()
{
const int INT_LENGTH = 4;
if (position_ + INT_LENGTH > limit_) {
THROW_LOGIC_EXCEPTION("ByteBuffer underflow");
}
unsigned int value = 0;
for (int i = 0; i < INT_LENGTH; ++i) {
value <<= 8;
value |= (data_)[position_ + i];
}
position_ += INT_LENGTH;
return static_cast<int>(value);
}
inline int ByteBuffer::getIntBigEndian(int index)
{
const int INT_LENGTH = 4;
if (index + INT_LENGTH > limit_) {
THROW_LOGIC_EXCEPTION("ByteBuffer underflow");
}
unsigned int value = 0;
for (int i = 0; i < INT_LENGTH; ++i) {
value <<= 8;
value |= (data_)[index + i];
}
return static_cast<int>(value);
}
inline ByteBuffer *ByteBuffer::wrap(uint8_t *data, int length)
{
return wrap(data, 0, length);
}
inline std::shared_ptr<ByteBuffer> ByteBuffer::wrap2(uint8_t *data_, int length)
{
std::shared_ptr<ByteBuffer> ret = std::make_shared<ByteBuffer>();
ret->data_ = data_;
ret->capacity_ = length;
ret->limit_ = length;
ret->position_ = 0;
ret->reusedData = true;
return ret;
}
inline ByteBuffer* ByteBuffer::wrap(uint8_t* data, int position, int length)
{
auto* ret = new ByteBuffer();
ret->position_ = position;
ret->data_ = data;
ret->limit_ = length;
ret->reusedData = true;
return ret;
}
inline ByteBuffer* ByteBuffer::wrapOpt(uint8_t* data, int position, int length)
{
this->data_ = data;
this->position_ = position;
this->limit_ = length;
this->capacity_ = length;
this->reusedData = true;
return this;
}
inline void ByteBuffer::setPosition(int position)
{
position_ = position;
}
inline void ByteBuffer::setLimit(int limit)
{
limit_ = limit;
}
inline uint8_t* ByteBuffer::getValue()
{
if (!data_) {
return nullptr;
}
return data_;
}
inline void ByteBuffer::showInternalInfo(ByteBuffer* buffer)
{
LOG("buffer " << &buffer << " position_ " << buffer->position_
<< " limit_ " << buffer->limit_ << " capacity_ " << buffer->capacity_
<< " data_ " << std::string(reinterpret_cast<const char *>(buffer->data_), buffer->limit_))
}
inline int ByteBuffer::getIntFromValue()
{
const int INT_LENGTH = 4;
if (position_ + INT_LENGTH > limit_) {
THROW_LOGIC_EXCEPTION("ByteBuffer underflow");
}
unsigned int result = 0;
uint8_t* value = getValue();
for (int i = 0; i < INT_LENGTH; ++i) {
result <<= 8;
result |= (value[position_ + i]);
}
position_ += INT_LENGTH;
return result;
}
#endif