summaryrefslogtreecommitdiff
path: root/src/buffer.cc
diff options
context:
space:
mode:
authorJoel Klinghed <the_jk@spawned.biz>2021-11-17 22:34:57 +0100
committerJoel Klinghed <the_jk@spawned.biz>2021-11-17 22:34:57 +0100
commit6232d13f5321b87ddf12a1aa36b4545da45f173d (patch)
tree23f3316470a14136debd9d02f9e920ca2b06f4cc /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.cc236
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;
+ }
+}