StormByte is a comprehensive, cross-platform C++ library aimed at easing system programming, configuration management, logging, and database handling tasks. This library provides a unified API that abstracts away the complexities and inconsistencies of different platforms (Windows, Linux).
Features
- Buffer Operations: FIFO buffers, thread-safe shared buffers, producer-consumer interfaces, and pipelines
Table of Contents
- Repository
- Installation
- Modules
- Contributing
- License
Repository
You can visit the code repository at GitHub
Installation
Prerequisites
Ensure you have the following installed:
- C++23 compatible compiler
- CMake 3.12 or higher
Building
To build the library, follow these steps:
git clone https://github.com/StormBytePP/StormByte-Buffer.git
cd StormByte-Buffer
mkdir build
cd build
cmake ..
make
Modules
Buffer
The Buffer module provides a comprehensive set of classes for efficient data buffering, thread-safe producer-consumer patterns, and multi-stage data processing pipelines.
FIFO
A byte-oriented buffer backed by std::deque<std::byte> with automatic growth on demand. Not thread-safe by itself.
- Purpose: Basic buffer for sequential byte storage and retrieval
- Key Features:
- Non-destructive
Read() with seek support
- Destructive
Extract() for consuming data
Clear() empties the buffer
- API:
Size(), Empty(), Clear(), Write(), Read(count), Extract(count), Seek()
Usage example:
#include <StormByte/buffer/fifo.hxx>
using StormByte::Buffer::Position;
int main() {
FIFO fifo;
fifo.
Write(
"Hello World");
StormByte::Buffer::DataType data;
auto res = fifo.Read(5, data);
if (res.has_value()) {
std::string s(reinterpret_cast<const char*>(data.data()), data.size());
}
fifo.Seek(6, Position::Absolute);
StormByte::Buffer::DataType more;
auto res_more = fifo.Read(5, more);
StormByte::Buffer::DataType extracted;
auto res_ex = fifo.Extract(11, extracted);
}
Byte-oriented FIFO buffer with grow-on-demand.
Definition fifo.hxx:40
bool Write(const std::size_t &count, const DataType &data) noexcept override
Write bytes from a vector to the buffer.
Definition fifo.hxx:394
SharedFIFO
Thread-safe version of FIFO with blocking semantics for concurrent access.
- Purpose: Thread-safe buffer for multi-threaded applications
- Key Features:
- All FIFO operations are thread-safe
Read() and Extract() block until data is available
Close() wakes waiting threads
- Mutex and condition variable for synchronization
- API: Same as FIFO, plus
Close()
- API: Same as FIFO, plus
Close() and SetError()
Prefer using the Producer/Consumer wrappers rather than manipulating a SharedFIFO directly. The example below shows a writer and reader using these safe interfaces; readers should use Consumer::EoF() to detect completion and Consumer::IsReadable() to detect an error state.
Usage example (Producer/Consumer):
#include <StormByte/buffer/producer.hxx>
#include <StormByte/buffer/consumer.hxx>
#include <thread>
int main() {
Producer producer;
Consumer consumer = producer.
Consumer();
std::thread writer([producer]() mutable {
producer.Write("Data chunk 1");
std::this_thread::sleep_for(std::chrono::milliseconds(100));
producer.Write("Data chunk 2");
producer.Close();
});
std::thread reader([consumer]() mutable {
while (!consumer.EoF()) {
StormByte::Buffer::DataType data;
auto res = consumer.Extract(0, data);
if (res.has_value() && !data.empty()) {
}
}
});
writer.join();
reader.join();
}
Read-only interface for consuming data from a shared FIFO buffer.
Definition consumer.hxx:46
Consumer(const Consumer &other) noexcept
Copy constructor.
Definition consumer.hxx:56
Producer interface for writing data to a shared FIFO buffer.
Definition producer.hxx:27
Producer and Consumer
High-level interfaces for producer-consumer patterns built on top of SharedFIFO.
- Purpose: Simplified API for producer-consumer workflows
- Key Features:
Producer: Write-only interface
Consumer: Read-only interface
- Both share the same underlying
SharedFIFO
- Multiple producers/consumers can share one buffer
- API:
- Producer:
Write(), Close(), SetError(), Consumer()
- Consumer:
Read(), Extract(), Size(), Empty(), EoF(), IsReadable(), IsWritable(), Seek()
Usage example:
#include <StormByte/buffer/producer.hxx>
#include <StormByte/buffer/consumer.hxx>
#include <thread>
int main() {
Producer producer;
Consumer consumer = producer.
Consumer();
std::thread writer([producer]() mutable {
for (int i = 0; i < 10; i++) {
producer.Write("Message " + std::to_string(i));
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
producer.Close();
});
std::thread reader([consumer]() mutable {
while (!consumer.EoF()) {
auto data = consumer.Extract(0);
if (data && !data->empty()) {
std::string msg(reinterpret_cast<const char*>(data->data()), data->size());
std::cout << msg << std::endl;
}
}
});
writer.join();
reader.join();
}
Bridge
The Bridge adapter provides a small pass-through utility that reads bytes from an ExternalReader and forwards them to an ExternalWriter in fixed-size chunks. It's useful for connecting two buffer-like endpoints (for example, a source FIFO and a destination FIFO) without the caller needing to manually manage chunked reads/writes.
- Purpose: Move bytes from an external read source into an external write target in configurable chunk sizes.
- Key Features:
- Accepts user-provided
ExternalReader and ExternalWriter implementations.
- Accumulates bytes into an internal
FIFO and flushes when a chunk is complete or when Flush() is called.
- Automatically flushes pending bytes in the destructor.
- API:
Bridge(const ExternalReader&, const ExternalWriter&, std::size_t chunk_size = 4096), Passthrough(std::size_t bytes), Flush(), PendingBytes()
Usage notes:
ExternalReader and ExternalWriter are abstract interfaces you must implement. ExternalReader::Read(size_t, WriteOnly&) should fill the provided WriteOnly with up to the requested number of bytes. ExternalWriter::Write(ReadOnly&) should consume the provided data (for example writing it into a FIFO).
- The bridge accumulates reads in an internal buffer and issues writes in multiples of
chunk_size. If you request fewer bytes than chunk_size the bridge will hold data until enough bytes are available or until Flush()/destruction occurs.
Example (adapted from test/bridge_test.cxx):
#include <StormByte/buffer/bridge.hxx>
#include <StormByte/buffer/fifo.hxx>
class SimpleReader final: public ExternalReader {
public:
SimpleReader(FIFO& from) noexcept: m_source(from) {}
bool Read(std::size_t bytes, WriteOnly& outBuffer) const noexcept override {
return m_source.
Extract(bytes, outBuffer);
}
PointerType Clone() const override { return SimpleReader::MakePointer<SimpleReader>(m_source); }
PointerType Move() override { return SimpleReader::MakePointer<SimpleReader>(m_source); }
private:
FIFO& m_source;
};
class SimpleWriter final: public ExternalWriter {
public:
SimpleWriter(FIFO& to) noexcept: m_target(to) {}
bool Write(ReadOnly& inBuffer) noexcept override {
return m_target.Write(std::move(inBuffer));
}
PointerType Clone() const override { return SimpleWriter::MakePointer<SimpleWriter>(m_target); }
PointerType Move() override { return SimpleWriter::MakePointer<SimpleWriter>(m_target); }
private:
FIFO& m_target;
};
int example_bridge() {
FIFO source;
FIFO target;
source.Write("Hello Bridge!");
SimpleReader reader(source);
SimpleWriter writer(target);
Bridge bridge(reader, writer, 16);
std::size_t total = source.Size();
if (!bridge.Passthrough(total)) return -1;
if (!bridge.Flush()) return -1;
auto got = StormByte::String::FromByteVector(target.Data());
return 0;
}
Pass-through adapter that forwards bytes from an ExternalReader to an ExternalWriter in chunks.
Definition bridge.hxx:52
Interface for reading data from an external source.
Definition external.hxx:26
Interface for writing data to an external source.
Definition external.hxx:174
bool Extract(const std::size_t &count, DataType &outBuffer) noexcept override
Destructive read that removes data from the buffer into an existing vector.
Definition fifo.hxx:213
Pipeline
Multi-stage data processing pipeline with concurrent execution of stages.
- Purpose: Chain multiple transformation functions that process data concurrently
- Key Features:
- Each stage runs in its own detached thread
- Stages execute concurrently (parallel processing)
- Data flows through thread-safe buffers
- Reusable pipeline definition
- API:
AddPipe(PipeFunction), Process(Consumer, ExecutionMode, StormByte::Logger::Log&)
Usage example:
#include <StormByte/buffer/pipeline.hxx>
#include <StormByte/logger/log.hxx>
#include <cctype>
#include <algorithm>
int main() {
Pipeline pipeline;
StormByte::Logger::Log logging(std::cout, StormByte::Logger::Level::LowLevel);
pipeline.AddPipe([](Consumer in, Producer out, StormByte::Logger::Log& log) {
while (!in.EoF()) {
StormByte::Buffer::DataType data;
auto res = in.Extract(0, data);
if (res.has_value() && !data.empty()) {
std::string str(reinterpret_cast<const char*>(data.data()), data.size());
for (auto& c : str) c = std::toupper(c);
out.Write(str);
}
}
out.Close();
});
pipeline.AddPipe([](Consumer in, Producer out, StormByte::Logger::Log& log) {
while (!in.EoF()) {
StormByte::Buffer::DataType data;
auto res = in.Extract(0, data);
if (res.has_value() && !data.empty()) {
std::string str(reinterpret_cast<const char*>(data.data()), data.size());
std::replace(str.begin(), str.end(), ' ', '_');
out.Write(str);
}
}
out.Close();
});
pipeline.AddPipe([](Consumer in, Producer out, StormByte::Logger::Log& log) {
out.Write("[");
while (!in.EoF()) {
StormByte::Buffer::DataType data;
auto res = in.Extract(0, data);
if (res.has_value() && !data.empty()) {
out.Write(data);
}
}
out.Write("]");
out.Close();
});
Producer input;
input.Write("hello world");
input.Close();
Consumer result = pipeline.Process(input.Consumer(), StormByte::Buffer::ExecutionMode::Async, logging);
while (!result.EoF()) { std::this_thread::yield(); }
StormByte::Buffer::DataType final_data;
auto final_res = result.Extract(0, final_data);
if (final_res.has_value()) {
std::string output(reinterpret_cast<const char*>(final_data.data()), final_data.size());
}
}
Multi-stage data-processing pipeline with optional concurrent execution.
Definition pipeline.hxx:74
Error Handling
The library uses std::expected-like (StormByte::Expected) for error handling:
Read/Extract operations return ExpectedVoid<ReadError> and fill a DataType buffer passed as the second parameter:
StormByte::Buffer::DataType data;
auto res = fifo.Read(100, data);
if (res.has_value()) {
process(data);
} else {
std::cerr << "Read error: " << res.error()->what() << std::endl;
}
Write operations return ExpectedVoid<WriteError>:
auto result = producer.Write("Some data");
if (result.has_value()) {
} else {
std::cerr << "Write error: " << result.error()->what() << std::endl;
}
Additional notes on end-of-stream and errors:
Consumer::EoF() returns true when the buffer is unreadable (closed or in error) and there are no available bytes; prefer it to detect stream completion in consumers.
Producer::SetError() marks a buffer as erroneous (unreadable and unwritable); blocked Read()/Extract() calls wake and return an error. Use IsReadable()/IsWritable() to query state.
Contributing
Contributions are welcome! Please fork the repository and submit pull requests for any enhancements or bug fixes.
License
This project is licensed under GPL v3 License - see the [LICENSE](LICENSE) file for details.