diff options
| author | Joel Klinghed <the_jk@spawned.biz> | 2021-11-17 22:34:57 +0100 |
|---|---|---|
| committer | Joel Klinghed <the_jk@spawned.biz> | 2021-11-17 22:34:57 +0100 |
| commit | 6232d13f5321b87ddf12a1aa36b4545da45f173d (patch) | |
| tree | 23f3316470a14136debd9d02f9e920ca2b06f4cc /src/buffer.cc | |
Travel3: Simple image and video display site
Reads the images and videos from filesystem and builds a site in
memroy.
Diffstat (limited to 'src/buffer.cc')
| -rw-r--r-- | src/buffer.cc | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/src/buffer.cc b/src/buffer.cc new file mode 100644 index 0000000..2412dca --- /dev/null +++ b/src/buffer.cc @@ -0,0 +1,236 @@ +#include "common.hh" + +#include "buffer.hh" + +#include <algorithm> +#include <vector> + +namespace { + +class Round : public Buffer { +public: + explicit Round(size_t size) + : data_(std::make_unique<char[]>(size)), end_(data_.get() + size), + rptr_(data_.get()), wptr_(data_.get()), full_(false) {} + + bool empty() const override { + return rptr_ == wptr_ && !full_; + } + + bool full() const override { + return rptr_ == wptr_ && full_; + } + + void clear() override { + rptr_ = wptr_ = data_.get(); + full_ = false; + } + + char const* rbuf(size_t want, size_t& avail) override { + if (rptr_ < wptr_) { + avail = wptr_ - rptr_; + } else if (rptr_ == wptr_ && !full_) { + avail = 0; + } else { + avail = end_ - rptr_; + if (want > avail) { + auto* target = data_.get(); + for (; rptr_ < end_; ++rptr_) { + std::swap(*target, *rptr_); + ++target; + } + rptr_ = data_.get(); + wptr_ += avail; + if (wptr_ == end_) { + assert(full_); + wptr_ = data_.get(); + avail = end_ - rptr_; + } else { + avail = wptr_ - rptr_; + } + } + } + return rptr_; + } + + void rcommit(size_t bytes) override { + if (bytes == 0) + return; + full_ = false; + assert(rptr_ < wptr_ ? rptr_ + bytes <= wptr_ : rptr_ + bytes <= end_); + rptr_ += bytes; + if (rptr_ == end_) + rptr_ = data_.get(); + if (rptr_ == wptr_) + rptr_ = wptr_ = data_.get(); + } + + char* wbuf(size_t request, size_t& avail) override { + if (wptr_ < rptr_) { + avail = rptr_ - wptr_; + } else if (rptr_ == wptr_ && full_) { + avail = 0; + } else { + avail = end_ - wptr_; + if (avail < request && wptr_ != data_.get() && rptr_ != data_.get()) { + std::copy(rptr_, wptr_, data_.get()); + auto size = wptr_ - rptr_; + wptr_ = data_.get() + size; + rptr_ = data_.get(); + avail = end_ - wptr_; + } + } + return wptr_; + } + + void wcommit(size_t bytes) override { + if (bytes == 0) + return; + assert(wptr_ < rptr_ ? wptr_ + bytes <= rptr_ : wptr_ + bytes <= end_); + wptr_ += bytes; + if (wptr_ == end_) + wptr_ = data_.get(); + if (wptr_ == rptr_) + full_ = true; + } + +private: + std::unique_ptr<char[]> data_; + char* const end_; + char* rptr_; + char* wptr_; + bool full_; +}; + +class Growing : public Buffer { +public: + Growing(size_t base_size, size_t max_size) + : base_size_(base_size), max_size_(max_size), data_(base_size) { + } + + bool empty() const override { + return rptr_ == wptr_; + } + + bool full() const override { + return rptr_ == 0 && wptr_ == max_size_; + } + + void clear() override { + data_.resize(base_size_); + rptr_ = wptr_ = 0; + } + + char const* rbuf(size_t, size_t& avail) override { + avail = wptr_ - rptr_; + return data_.data() + rptr_; + } + + void rcommit(size_t bytes) override { + assert(rptr_ + bytes <= wptr_); + rptr_ += bytes; + if (rptr_ == wptr_) + rptr_ = wptr_ = 0; + } + + char* wbuf(size_t request, size_t& avail) override { + avail = data_.size() - wptr_; + if (request > avail && rptr_ > 0) { + std::copy(data_.begin() + rptr_, data_.begin() + wptr_, data_.begin()); + wptr_ -= rptr_; + rptr_ = 0; + avail = data_.size() - wptr_; + } + if (request > avail && data_.size() < max_size_) { + data_.resize( + std::min(max_size_, + data_.size() + std::max(request - avail, + (max_size_ - base_size_) / 8))); + avail = data_.size() - wptr_; + } + return data_.data() + wptr_; + } + + void wcommit(size_t bytes) override { + assert(wptr_ + bytes <= data_.size()); + wptr_ += bytes; + } + +private: + size_t const base_size_; + size_t const max_size_; + std::vector<char> data_; + size_t rptr_{0}; + size_t wptr_{0}; +}; + +class Null : public Buffer { +public: + bool empty() const override { + return true; + } + + char const* rbuf(size_t, size_t& avail) override { + avail = 0; + return buf_; + } + + void rcommit(size_t bytes) override { + assert(bytes == 0); + } + + bool full() const override { + return false; + } + + void clear() override {} + + char* wbuf(size_t, size_t& avail) override { + avail = sizeof(buf_); + return buf_; + } + + void wcommit(size_t) override { + } + +private: + char buf_[4096]; +}; + +} // namespace + +std::unique_ptr<Buffer> Buffer::fixed(size_t size) { + return std::make_unique<Round>(size); +} + +std::unique_ptr<Buffer> Buffer::growing(size_t base_size, size_t max_size) { + return std::make_unique<Growing>(base_size, max_size); +} + +std::unique_ptr<Buffer> Buffer::null() { + return std::make_unique<Null>(); +} + +size_t Buffer::write(Buffer* buf, void const* data, size_t len) { + assert(buf); + assert(data); + if (len == 0) + return 0; + auto* d = reinterpret_cast<char const*>(data); + size_t wrote = 0; + while (true) { + size_t avail; + auto want = len - wrote; + auto* ptr = buf->wbuf(want, avail); + if (avail == 0) + return wrote; + if (avail >= want) { + std::copy_n(d + wrote, want, ptr); + buf->wcommit(want); + return len; + } + std::copy_n(d + wrote, avail, ptr); + buf->wcommit(avail); + wrote += avail; + } +} |
