mirror of
https://github.com/pavel-odintsov/fastnetmon
synced 2024-05-21 11:16:26 +02:00
183 lines
5.8 KiB
C++
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;
|
||
|
};
|