2023-10-10 05:41:07 +00:00
|
|
|
///
|
2023-10-10 09:35:43 +00:00
|
|
|
/// \file Buffer.h
|
2023-10-10 05:41:07 +00:00
|
|
|
/// \author K. Isom <kyle@imap.cc>
|
|
|
|
/// \date 2023-10-09
|
|
|
|
/// \brief Buffer implements basic line buffers.
|
|
|
|
///
|
|
|
|
/// Buffer implements a basic uint8_t line buffer that is intended for use in text
|
|
|
|
/// editing. It allocates memory in powers of two, and will grow or shrink
|
|
|
|
/// as needed.
|
|
|
|
///
|
2023-10-09 17:24:40 +00:00
|
|
|
|
|
|
|
#ifndef KGE_BUFFER_H
|
|
|
|
#define KGE_BUFFER_H
|
|
|
|
|
2023-10-10 02:59:21 +00:00
|
|
|
#include <iostream>
|
2023-10-09 17:24:40 +00:00
|
|
|
#include <cstdint>
|
|
|
|
|
|
|
|
|
|
|
|
namespace klib {
|
|
|
|
|
2023-10-10 05:41:07 +00:00
|
|
|
/// Buffer is a basic line buffer.
|
|
|
|
///
|
|
|
|
/// The buffer manages its own internal memory, growing and shrinking
|
|
|
|
/// as needed. Its capacity is separate from its length; the optimal
|
|
|
|
/// capacity is determined as the nearest power of two that is greater
|
|
|
|
/// than the length of the buffer. For example, if the buffer has a
|
|
|
|
/// length of 5 bytes, 8 bytes will be allocated. If the buffer is 9
|
|
|
|
/// bytes, 16 bytes will be allocated.
|
|
|
|
///
|
|
|
|
/// The #Append and #Insert methods will call #Resize as necessary to grow
|
|
|
|
/// the buffer. Similarly the #Remove methods will call #Trim to reclaim some
|
|
|
|
/// memory if possible, but only if #AutoTrimIsEnabled (it is by default).
|
2023-10-09 17:24:40 +00:00
|
|
|
class Buffer {
|
|
|
|
public:
|
2023-10-10 05:41:07 +00:00
|
|
|
/// A Buffer can be constructed empty, with no memory allocated (yet).
|
2023-10-09 17:24:40 +00:00
|
|
|
Buffer();
|
|
|
|
|
2023-10-10 05:41:07 +00:00
|
|
|
/// A Buffer can be constructed with an explicit capacity.
|
|
|
|
///
|
|
|
|
/// \param initialCapacity The initial allocation size for the buffer.
|
|
|
|
explicit Buffer(size_t initialCapacity);
|
|
|
|
|
|
|
|
/// A Buffer can be initialized with a starting C-style string.
|
|
|
|
explicit Buffer(const char *s);
|
|
|
|
|
|
|
|
/// A Buffer can be initialized with a starting string.
|
|
|
|
explicit Buffer(const std::string s);
|
|
|
|
|
|
|
|
~Buffer()
|
|
|
|
{ this->Reclaim(); }
|
|
|
|
|
|
|
|
/// Contents returns the Buffer's contents.
|
|
|
|
uint8_t *Contents() const
|
|
|
|
{ return this->contents; }
|
|
|
|
|
|
|
|
/// Length returns the length of the data currently stored in the
|
|
|
|
/// buffer.
|
|
|
|
size_t Length() const
|
|
|
|
{ return this->length; };
|
|
|
|
|
|
|
|
/// Capacity returns the amount of memory allocated to the Buffer.
|
|
|
|
size_t Capacity() const
|
|
|
|
{ return this->capacity; }
|
|
|
|
|
|
|
|
/// Append copies in a C-style string to the end of the buffer.
|
|
|
|
///
|
|
|
|
/// \param s The string to append.
|
|
|
|
/// \return True if the Buffer was resized.
|
|
|
|
bool Append(const char *s);
|
|
|
|
|
|
|
|
/// Append copies in a string to the end of the buffer.
|
|
|
|
///
|
|
|
|
/// \param s The string to append.
|
|
|
|
/// \return True if the Buffer was resized.
|
|
|
|
bool Append(const std::string s);
|
|
|
|
|
|
|
|
/// Append copies in a byte buffer to the end of the buffer.
|
|
|
|
///
|
|
|
|
/// \param data The byte buffer to insert.
|
|
|
|
/// \param datalen The length of the byte buffer.
|
|
|
|
/// \return True if the Buffer was resized.
|
|
|
|
bool Append(const uint8_t *data, const size_t datalen);
|
|
|
|
|
|
|
|
/// Append copies a single character to the end of the buffer.
|
|
|
|
///
|
|
|
|
/// \param c The character to append.
|
|
|
|
/// \return True if the Buffer was resized.
|
|
|
|
bool Append(const uint8_t c);
|
|
|
|
|
|
|
|
/// Insert copies a C-style string into the buffer at index.
|
|
|
|
///
|
|
|
|
/// \param index The index to insert the string at.
|
|
|
|
/// \param s The string to insert.
|
|
|
|
/// \return True if the Buffer was resized.
|
|
|
|
bool Insert(const size_t index, const char *s);
|
|
|
|
|
|
|
|
/// Insert copies a string into the buffer at index.
|
|
|
|
///
|
|
|
|
/// \param index The index the string should be inserted at.
|
|
|
|
/// \param s The string to insert.
|
|
|
|
/// \return True if the Buffer was resized.
|
|
|
|
bool Insert(const size_t index, const std::string s);
|
|
|
|
|
|
|
|
/// Insert copies a uint8_t buffer into the buffer at index.
|
|
|
|
///
|
|
|
|
/// \param index The index to insert the buffer at.
|
|
|
|
/// \param data The buffer to insert.
|
|
|
|
/// \param datalen The size of the data buffer.
|
|
|
|
/// \return True if the Buffer was resized.
|
|
|
|
bool
|
|
|
|
Insert(const size_t index, const uint8_t *data, const size_t datalen);
|
|
|
|
|
|
|
|
/// Insert copies a character into the buffer at index.
|
|
|
|
///
|
|
|
|
/// \param index The index to insert the character at.
|
|
|
|
/// \param c The character to insert.
|
|
|
|
/// \return True if the Buffer was resized.
|
|
|
|
bool Insert(const size_t index, const uint8_t c);
|
|
|
|
|
|
|
|
/// Remove removes `count` bytes from the buffer at `index`.
|
|
|
|
///
|
|
|
|
/// \param index The starting index to remove bytes from.
|
|
|
|
/// \param count The number of bytes to remove.
|
|
|
|
/// \return True if the Buffer was resized.
|
|
|
|
bool Remove(const size_t index, const size_t count);
|
|
|
|
|
|
|
|
/// Remove removes a single byte from the buffer.
|
|
|
|
///
|
|
|
|
/// \param index The index pointing to the byte to be removed.
|
|
|
|
/// \return True if the Buffer was resized.
|
|
|
|
bool Remove(size_t index); // remove single char
|
2023-10-09 17:24:40 +00:00
|
|
|
|
|
|
|
/* memory management */
|
|
|
|
|
2023-10-10 05:41:07 +00:00
|
|
|
/// Resize changes the capacity of the buffer to `newCapacity`.
|
|
|
|
///
|
|
|
|
/// If newCapacity is less than the length of the Buffer, it
|
|
|
|
/// will remove enough bytes from the end to make this happen.
|
|
|
|
///
|
|
|
|
/// \param newCapacity The new capacity for the Buffer.
|
|
|
|
void Resize(size_t newCapacity);
|
|
|
|
|
|
|
|
/// Trim will resize the Buffer to an appropriate size based on
|
|
|
|
/// its length.
|
|
|
|
///
|
|
|
|
/// \return The new capacity of the Buffer.
|
|
|
|
size_t Trim();
|
|
|
|
|
|
|
|
/// DisableAutoTrim prevents the #Buffer from automatically
|
|
|
|
/// trimming memory after a call to #Remove.
|
|
|
|
void DisableAutoTrim()
|
|
|
|
{ this->autoTrim = false; }
|
|
|
|
|
|
|
|
/// EnableAutoTrim enables automatically trimming memory after
|
|
|
|
/// calls to #Remove.
|
|
|
|
void EnableAutoTrim()
|
|
|
|
{ this->autoTrim = true; }
|
|
|
|
|
|
|
|
/// AutoTrimIsEnabled returns true if autotrim is enabled.
|
|
|
|
///
|
|
|
|
/// \return #Remove will call Trim.
|
|
|
|
bool AutoTrimIsEnabled()
|
|
|
|
{ return this->autoTrim; }
|
|
|
|
|
|
|
|
/// Clear removes the data stored in the buffer. It will not
|
|
|
|
/// call #Trim; the capacity of the buffer will not be altered.
|
|
|
|
void Clear();
|
|
|
|
|
|
|
|
/// Reclaim the memory in the buffer: the buffer will call #Clear,
|
|
|
|
/// followed by deleting any allocated memory.
|
|
|
|
void Reclaim();
|
|
|
|
|
|
|
|
/// HexDump dumps the data in the buffer to the output stream;
|
|
|
|
/// it is intended as a debugging tool.
|
|
|
|
///
|
|
|
|
/// \param os The output stream to write to.
|
|
|
|
void HexDump(std::ostream &os);
|
|
|
|
|
|
|
|
/// This operator allows the data in the buffer to be accessed
|
|
|
|
/// as if it were an array. If the index is out of bounds, it
|
|
|
|
/// will throw a range_error.
|
|
|
|
///
|
|
|
|
/// \throws std::range_error.
|
|
|
|
///
|
|
|
|
/// \param index The index to retrieve.
|
|
|
|
/// \return
|
|
|
|
uint8_t &operator[](size_t index);
|
|
|
|
|
|
|
|
/// Two buffers are equal if their lengths are the same and
|
|
|
|
/// their contents are the same. Equality is irrespective of
|
|
|
|
/// their capacities.
|
|
|
|
friend bool operator==(const Buffer &lhs, const Buffer &rhs);
|
2023-10-10 02:59:21 +00:00
|
|
|
|
2023-10-09 17:24:40 +00:00
|
|
|
private:
|
2023-10-10 05:41:07 +00:00
|
|
|
size_t mustGrow(size_t delta) const;
|
2023-10-09 17:24:40 +00:00
|
|
|
|
2023-10-10 05:41:07 +00:00
|
|
|
bool shiftRight(size_t offset, size_t delta);
|
|
|
|
|
|
|
|
bool shiftLeft(size_t offset, size_t delta);
|
|
|
|
|
|
|
|
uint8_t *contents;
|
|
|
|
size_t length;
|
|
|
|
size_t capacity;
|
|
|
|
bool autoTrim;
|
2023-10-09 17:24:40 +00:00
|
|
|
};
|
|
|
|
|
2023-10-10 09:35:43 +00:00
|
|
|
/// The << operator is overloaded to write out the contents of the Buffer.
|
2023-10-10 05:41:07 +00:00
|
|
|
std::ostream &operator<<(std::ostream &os, const Buffer &buf);
|
2023-10-10 09:35:43 +00:00
|
|
|
|
|
|
|
/// Two Buffers are not equal if their lengths differ or if their contents
|
|
|
|
/// differ.
|
2023-10-10 05:41:07 +00:00
|
|
|
inline bool operator!=(const Buffer &lhs, const Buffer &rhs) { return !(lhs == rhs); };
|
2023-10-09 19:45:19 +00:00
|
|
|
|
2023-10-09 17:24:40 +00:00
|
|
|
} // namespace klib
|
|
|
|
|
2023-10-10 05:41:07 +00:00
|
|
|
|
|
|
|
#endif // KGE_BUFFER_H
|