1
0
Fork 0
mirror of https://github.com/pavel-odintsov/fastnetmon synced 2024-05-03 22:26:30 +02:00
fastnetmon-rewritten/src/dynamic_binary_buffer.hpp

183 lines
5.8 KiB
C++

#pragma once
#include <iostream>
class dynamic_binary_buffer_t {
public:
dynamic_binary_buffer_t() : byte_storage(nullptr), maximum_internal_storage_size(0) {
// std::cout << "Default constructor called" << std::endl;
}
// Explicitly removed it as we need to implement it properly when needed
dynamic_binary_buffer_t(dynamic_binary_buffer_t&& that) = delete;
// We should set maximum buffer size here.
// TODO: add ability to relocate memory of we need more memory
bool set_maximum_buffer_size_in_bytes(ssize_t size) {
// Already allocated
if (byte_storage) {
return false;
}
// With nothrow we are using new without exceptions
byte_storage = new (std::nothrow) uint8_t[size];
if (byte_storage) {
maximum_internal_storage_size = size;
return true;
} else {
return false;
}
}
~dynamic_binary_buffer_t() {
// std::cout << "Destructor called" << std::endl;
if (byte_storage) {
delete[] byte_storage;
byte_storage = nullptr;
maximum_internal_storage_size = 0;
}
}
// So this implementation will be useful only for real object copies
// For returning local variable from function compiler will do this job
// perfectly:
// https://en.wikipedia.org/wiki/Return_value_optimization
dynamic_binary_buffer_t(const dynamic_binary_buffer_t& that) {
this->maximum_internal_storage_size = that.maximum_internal_storage_size;
// Copy internal pointer too! It's very important!
this->internal_data_shift = that.internal_data_shift;
// std::cout << "Copy constructor called" << std::endl;
// std::cout << "Copy constructor will copy " << this->internal_size << "
// bytes" <<
// std::endl;
// We are copying all memory (unused too)
if (this->maximum_internal_storage_size > 0) {
// Allocate memory for new instance
this->set_maximum_buffer_size_in_bytes(this->maximum_internal_storage_size);
memcpy(this->byte_storage, that.byte_storage, that.maximum_internal_storage_size);
}
}
// All this functions just append some data with certain length to buffer and
// increase total
// size
// They are very similar to std::stringstream but for binary data only
bool append_byte(uint8_t byte_value) {
// Do bounds check
if (internal_data_shift > maximum_internal_storage_size - 1) {
errors_occured = true;
return false;
}
byte_storage[internal_data_shift] = byte_value;
internal_data_shift += sizeof(uint8_t);
return true;
}
// Use reference as argument
bool append_dynamic_buffer(dynamic_binary_buffer_t& dynamic_binary_buffer) {
// In this case we are copying only used memory
// TODO: Why +1?
if (internal_data_shift + dynamic_binary_buffer.get_used_size() > maximum_internal_storage_size + 1) {
errors_occured = true;
return false;
}
return this->append_data_as_pointer(dynamic_binary_buffer.get_pointer(), dynamic_binary_buffer.get_used_size());
}
bool append_data_as_pointer(const void* ptr, size_t length) {
if (internal_data_shift + length > maximum_internal_storage_size + 1) {
errors_occured = true;
return false;
}
memcpy(byte_storage + internal_data_shift, ptr, length);
internal_data_shift += length;
return true;
}
template <typename src_type> bool append_data_as_object_ptr(src_type* ptr) {
if (internal_data_shift + sizeof(src_type) > maximum_internal_storage_size + 1) {
errors_occured = true;
return false;
}
memcpy(byte_storage + internal_data_shift, ptr, sizeof(src_type));
internal_data_shift += sizeof(src_type);
return true;
}
// All functions below DO NOT CHANGE internal buffer position! They are very
// low level and
// should be avoided!
// We could set arbitrary byte with this function
bool set_byte(uint32_t byte_number, uint8_t byte_value) {
// Do bounds check
if (byte_number > maximum_internal_storage_size - 1) {
errors_occured = true;
return false;
}
byte_storage[byte_number] = byte_value;
return true;
}
bool memcpy_from_ptr(uint32_t shift, const void* ptr, uint32_t length) {
if (shift + length > maximum_internal_storage_size + 1) {
errors_occured = true;
return false;
}
memcpy(byte_storage + shift, ptr, length);
return true;
}
// More user friendly version of previous function
template <typename src_type> bool memcpy_from_object_ptr(uint32_t shift, src_type* ptr) {
if (shift + sizeof(src_type) > maximum_internal_storage_size + 1) {
errors_occured = true;
return false;
}
memcpy(byte_storage + shift, ptr, sizeof(src_type));
return true;
}
// Return full size (with non initialized data region too)
uint32_t get_full_size() {
return maximum_internal_storage_size;
}
// Return only used memory region
size_t get_used_size() {
return internal_data_shift;
}
const uint8_t* get_pointer() {
return byte_storage;
}
// If we have any issues with it
bool is_failed() {
return errors_occured;
}
private:
size_t internal_data_shift = 0;
uint8_t* byte_storage = nullptr;
ssize_t maximum_internal_storage_size = 0;
// If any errors occurred in any time when we used this buffer
bool errors_occured = false;
};