diff options
| author | Joel Klinghed <the_jk@yahoo.com> | 2017-02-28 21:50:44 +0100 |
|---|---|---|
| committer | Joel Klinghed <the_jk@yahoo.com> | 2017-02-28 21:50:44 +0100 |
| commit | c029d90d1975e124d237605f1edb2be16bd05b5d (patch) | |
| tree | 9df87ffb365354bdb74a969440b32c8304bdbcb7 /src/buffer.cc | |
Initial commit
Diffstat (limited to 'src/buffer.cc')
| -rw-r--r-- | src/buffer.cc | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/src/buffer.cc b/src/buffer.cc new file mode 100644 index 0000000..d0c5fbb --- /dev/null +++ b/src/buffer.cc @@ -0,0 +1,119 @@ +// -*- mode: c++; c-basic-offset: 2; -*- + +#include "common.hh" + +#include <algorithm> +#include <cstring> + +#include "buffer.hh" + +namespace { + +class BufferImpl : public Buffer { +public: + BufferImpl(size_t capacity, size_t min_avail) + : capacity_(capacity), min_avail_(min_avail) { + data_ = capacity_ > 0 ? + reinterpret_cast<char*>(malloc(capacity_)) : nullptr; + end_ = data_; + rptr_ = data_; + wptr_ = data_; + } + ~BufferImpl() { + free(data_); + } + + void const* read_ptr(size_t* avail) const override { + if (avail) *avail = wptr_ - rptr_; + return rptr_; + } + + void consume(size_t bytes) override { + if (bytes == 0) return; + assert(rptr_ + bytes <= wptr_); + rptr_ += bytes; + if (rptr_ == wptr_) { + rptr_ = wptr_ = data_; + } + } + + void* write_ptr(size_t* avail) override { + if (wptr_ + min_avail_ > end_) { + if (rptr_ > data_) { + memmove(data_, rptr_, wptr_ - rptr_); + wptr_ -= rptr_ - data_; + rptr_ = data_; + } + if (wptr_ + min_avail_ > end_) { + auto new_size = (end_ - data_) + std::max(capacity_, min_avail_); + auto tmp = reinterpret_cast<char*>(realloc(data_, new_size)); + if (tmp) { + end_ = tmp + new_size; + rptr_ = tmp + (rptr_ - data_); + wptr_ = tmp + (wptr_ - data_); + data_ = tmp; + } + } + } + if (avail) *avail = end_ - wptr_; + return wptr_; + } + + void commit(size_t bytes) override { + if (bytes == 0) return; + assert(wptr_ + bytes <= end_); + wptr_ += bytes; + } + +private: + size_t capacity_; + size_t min_avail_; + char* data_; + char* end_; + char* rptr_; + char* wptr_; +}; + +} // namespace + +// static +Buffer* Buffer::create(size_t size, size_t min_avail) { + return new BufferImpl(std::max(size, min_avail), min_avail); +} + +bool Buffer::empty() const { + size_t avail; + read_ptr(&avail); + return avail == 0; +} + +size_t Buffer::read(void* data, size_t max) { + if (max == 0) return 0; + size_t avail; + auto ptr = read_ptr(&avail); + if (avail == 0) return 0; + avail = std::min(avail, max); + memcpy(data, ptr, avail); + commit(avail); + return avail; +} + +void Buffer::write(void const* data, size_t size) { + if (size == 0) return; + auto d = reinterpret_cast<char const*>(data); + size_t pos = 0; + while (true) { + size_t avail; + auto ptr = write_ptr(&avail); + if (pos + avail < size) { + memcpy(ptr, d + pos, avail); + pos += avail; + commit(avail); + } else { + memcpy(ptr, d + pos, size - pos); + commit(size - pos); + return; + } + } +} + |
