#ifndef COMMON_ASSORTED_BYTEBUFFER_H
#define COMMON_ASSORTED_BYTEBUFFER_H
#include <string>
typedef unsigned char Byte;
//A simple wrapper (with lots of convenience functions) for managing a block of memory.
class ByteBuffer
{
public:
static const size_t NoPos = ((size_t)-1);
public:
ByteBuffer() = default;
ByteBuffer(size_t bytesToAllocate); //Calls 'AllocateData()'.
ByteBuffer(const ByteBuffer &) = delete; //Disabled copy constructor. This class might contain alot of data, and should be explicitely copied only.
ByteBuffer(ByteBuffer &&other); //Move constructor works though.
ByteBuffer &operator=(const ByteBuffer &) = delete;
ByteBuffer &operator=(ByteBuffer &&other);
~ByteBuffer();
//========================================================
//Named constructors, for convience:
//========================================================
//Creates a ByteBuffer that owns 'data', and will delete it when destroyed.
static ByteBuffer MakeOwnerOf(Byte *data, size_t bytes);
static ByteBuffer MakeOwnerOf(ByteBuffer &other);
//Creates a ByteBuffer that copies 'data'. When destroyed, this ByteBuffer will delete the copied memory but not the original.
static ByteBuffer MakeCopiedFrom(const Byte *data, size_t bytes);
static ByteBuffer MakeCopiedFrom(const ByteBuffer &other, size_t pos = 0, size_t bytes = NoPos);
//Creates a ByteBuffer that points to 'data', without copying it, and will not delete the memory when destroyed.
static ByteBuffer MakePointedAt(Byte *data, size_t bytes);
static ByteBuffer MakePointedAt(ByteBuffer &other, size_t pos = 0, size_t bytes = NoPos);
//Creates a ByteBuffer that allocates a new block of memory of size 'bytes', and that will delete the memory when destroyed.
static ByteBuffer MakeAllocated(size_t bytes);
public:
//========================================================
//Access functions:
//========================================================
//Returns a reference to the bytes starting at 'pos'.
//Doesn't check if 'pos' is inbounds or not.
Byte &operator[](size_t pos);
const Byte &operator[](size_t pos) const;
//Returns a reference to the bytes starting at 'pos'.
//This is the same as buffer[pos], except it _does_ check if pos is in-bounds, by asserting
Byte &At(size_t pos);
const Byte &At(size_t pos) const;
//Returns a pointer to the first byte of the entire buffer. (The same as buffer[0])
Byte *GetData();
const Byte *GetData() const;
//Creates a non-owning ByteBuffer that points to the memory starting at 'pos', and containing the specified length of bytes.
//This is similar to getting a substring of a string.
//This ByteBuffer still owns and data and is responsible for freeing it. The returned buffer merely points to the data, but doesn't own it.
ByteBuffer MakeDataPortion(size_t pos, size_t bytes);
//The same as 'MakeDataPortion()', but copies the data.
ByteBuffer DuplicateDataPortion(size_t pos, size_t bytes);
//========================================================
//Querying functions:
//========================================================
//Returns the size of the buffer, in bytes.
size_t GetSize() const;
//True if this ByteBuffer owns the memory it points to.
bool IsOwner() const;
//True if this ByteBuffer points to nullptr, or is of size 0.
bool IsEmpty() const;
//========================================================
//Freeing functions: (deletes or releases the data)
//========================================================
//Releases ownership of the data (if it owned it), and returns a pointer to the data.
//This ByteBuffer still points to the data, but will never delete it.
//If 'bytes' is not Null, it will be set to the size of this buffer.
Byte *ReleaseData(size_t *bytes = nullptr);
//Releases ownership of the data (if it owned it), and returns a pointer to the data.
//This ByteBuffer no longer points to the data, and will never delete it.
//If 'bytes' is not Null, it will be set to the size of this buffer.
//This is the same as calling ReleaseData() followed by Clear().
Byte *ReleaseAndReset(size_t *bytes = nullptr);
//Clears this ByteBuffer, setting the data pointer to nullptr and the size to 0.
//If this ByteBuffer owns the memory it points to, that memory will now get deleted.
void Clear();
//========================================================
//Re-assignment functions
//========================================================
//Takes ownership of 'data' without copying it.
//When this ByteBuffer is destroyed, it will delete 'data' also.
//Any old data this ByteBuffer already points to will be freed (if this buffer is the owner of that data).
void TakeData(Byte *data, size_t bytes);
void TakeData(ByteBuffer &other); //'other' is made to Release() the data.
//Copies 'data'. When this ByteBuffer is destroyed, it will delete the copied memory but not the original.
//Any old data this ByteBuffer already points to will be freed (if this buffer is the owner of that data).
void CopyData(const Byte *data, size_t bytes);
void CopyData(const ByteBuffer &other, size_t pos = 0, size_t bytes = NoPos);
//Points to 'data', without copying it, and when this ByteBuffer is destroyed, will not delete the memory.
//Any old data this ByteBuffer already points to will be freed (if this buffer is the owner of that data).
void PointToData(Byte *data, size_t bytes);
void PointToData(ByteBuffer &other, size_t pos = 0, size_t bytes = NoPos);
//Allocates a new block of memory of size 'bytes'.
//Any old data this ByteBuffer already points to will be freed (if this buffer is the owner of that data).
void AllocateData(size_t bytes);
private:
//Clears the existing data (freeing it if this ByteBuffer is the owner),
//and assigning 'data' as the new memory pointer and 'bytes' as the new size.
void resetTo(Byte *data, size_t bytes, bool isOwner);
private:
Byte *data = nullptr;
size_t bytes = 0;
bool isOwner = true; //True if this ByteBuffer owns 'data', and is responsible for deleting it.
};
//================================================================================
//A constant value
const size_t ByteBuffer_SuggestedResize = size_t(-1);
//Resizes 'byteBuffer' by allocating a new buffer of size 'newSize', and copying the old bytes to it, before deleting the original buffer.
//If 'offset' is specified, offsets the position to place the the old memory in the new buffer. This allows you to grow the buffer's front as well as the back.
//e.g. to grow a buffer's front and back by 4 bytes each, you can do: ResizeByteBuffer(buffer, (buffer.GetSize() + 8), 4);
//This can shrink or grow the buffer.
//
//If 'newSize' is ResizeByteBuffer_SuggestedSize, automaticly grows the buffer by an internally-decided reasonable amount (35% or a minimum of 128 bytes).
void ResizeByteBuffer(ByteBuffer &byteBuffer, size_t newSize = ByteBuffer_SuggestedResize, size_t offset = 0);
//Starting at 'pos', fills a number of bytes (bytes) in byteBuffer with 'fillValue'.
void FillByteBuffer(ByteBuffer &byteBuffer, Byte fillValue = 0, size_t pos = 0, size_t bytes = ByteBuffer::NoPos);
//================================================================================
//Loads a file entirely into a bytebuffer. Returns an empty ByteBuffer if the load failed or if the file was empty.
ByteBuffer LoadFileAsByteBuffer(const std::string &filename);
//Writes the entire bytebuffer to a file, and returns true if it succeeded.
//If 'bytes' is specified, and if it's less than the bytebuffer's size, only writes that number of bytes.
bool SaveByteBufferToFile(const ByteBuffer &byteBuffer, const std::string &filename, size_t bytes = static_cast<size_t>(-1));
ByteBuffer StringToByteBuffer(const std::string &str);
std::string ByteBufferToString(const ByteBuffer &byteBuffer);
//================================================================================
//Note yet written:
//ByteBuffer CompressByteBufferWith_AlgorithmName(const ByteBuffer &byteBuffer);
//ByteBuffer UncompressByteBufferWith_AlgorithmName(const ByteBuffer &byteBuffer);
//================================================================================
//ByteBuffer EncryptByteBufferWith_AlgorithmName(const ByteBuffer &byteBuffer);
//ByteBuffer UnencryptByteBufferWith_AlgorithmName(const ByteBuffer &byteBuffer);
//================================================================================
#endif // COMMON_ASSORTED_BYTEBUFFER_H