Skip to content
Snippets Groups Projects
buffer.cc 3.09 KiB
Newer Older
  • Learn to ignore specific revisions
  • Daniel Lyubomirov's avatar
    Daniel Lyubomirov committed
    #include <vereign/bytes/buffer.hh>
    
    
    #include <vereign/bytes/errors.hh>
    
    #include <memory>
    
    
    Daniel Lyubomirov's avatar
    Daniel Lyubomirov committed
    namespace vereign::bytes {
    
    Buffer::Buffer() noexcept
      : cap_{0},
        size_{0},
        data_{nullptr}
    {
    }
    
    Buffer::Buffer(std::size_t cap)
      : cap_{cap},
        size_{0},
        data_{nullptr}
    {
      if (cap == 0) {
        return;
      }
    
      data_ = reinterpret_cast<uint8_t*>(std::malloc(cap));
      if (data_ == nullptr) {
        throw std::bad_alloc{};
      }
    }
    
    Buffer::Buffer(bytes::View src)
      : cap_{src.Size()},
        size_{src.Size()},
        data_{nullptr}
    {
      if (size_ == 0) {
        return;
      }
    
      data_ = reinterpret_cast<uint8_t*>(std::malloc(cap_));
      if (data_ == nullptr) {
        throw std::bad_alloc{};
      }
    
      std::memcpy(data_, src.Data(), src.Size());
    }
    
    Buffer::Buffer(Buffer&& other) noexcept
      : cap_{other.cap_},
        size_{other.size_},
        data_{other.data_}
    {
      other.cap_ = 0;
      other.size_ = 0;
      other.data_ = nullptr;
    }
    
    auto Buffer::operator=(Buffer&& other) noexcept -> Buffer& {
      std::swap(cap_, other.cap_);
      std::swap(size_, other.size_);
      std::swap(data_, other.data_);
    
      return *this;
    }
    
    
    Buffer::~Buffer() {
      std::free(data_);
    }
    
    
    auto Buffer::Size() const noexcept -> std::size_t {
      return size_;
    }
    
    auto Buffer::FreeCap() const noexcept -> std::size_t {
      return cap_ - size_;
    }
    
    auto Buffer::Cap() const noexcept -> std::size_t {
      return cap_;
    }
    
    auto Buffer::begin() noexcept -> uint8_t* {
      return data_;
    }
    
    auto Buffer::begin() const noexcept -> const uint8_t* {
      return data_;
    }
    
    auto Buffer::end() noexcept -> uint8_t* {
      return data_ + size_;
    }
    
    auto Buffer::end() const noexcept -> const uint8_t* {
      return data_ + size_;
    }
    
    void Buffer::Reserve(std::size_t size) {
      if (cap_ == 0) {
        cap_ = size;
        data_ = reinterpret_cast<uint8_t*>(std::malloc(cap_));
        if (data_ == nullptr) {
          throw std::bad_alloc{};
        }
    
        return;
      }
    
      if (size <= cap_ - size_) {
        return;
      }
    
    
      auto cap = cap_ * 2;
      if (size > cap - size_) {
        cap = size_ + size;
    
    Daniel Lyubomirov's avatar
    Daniel Lyubomirov committed
      }
    
      auto newData = reinterpret_cast<uint8_t*>(std::realloc(data_, cap));
      if (newData == nullptr) {
        throw std::bad_alloc{};
      }
    
      data_ = newData;
      cap_ = cap;
    }
    
    void Buffer::Reset() {
      size_ = 0;
    }
    
    
    void Buffer::IncSize(std::size_t val) {
      if (size_ + val > cap_) {
        throw IncrementOutOfBounds{};
    
      size_ += val;
    
    Daniel Lyubomirov's avatar
    Daniel Lyubomirov committed
    }
    
    auto Buffer::WriteWithinCap(bytes::View src) noexcept -> std::size_t {
      auto size = std::min(cap_ - size_, src.Size());
    
      std::memcpy(data_ + size_, src.Data(), size);
      size_ += size;
    
      return size;
    }
    
    auto Buffer::Write(bytes::View src) -> std::size_t {
      Reserve(src.Size());
    
      return WriteWithinCap(src);
    }
    
    auto Buffer::View() const noexcept -> bytes::View {
      return bytes::View{data_, size_};
    }
    
    auto Buffer::View(std::size_t start) const noexcept -> bytes::View {
      return bytes::View{data_, size_}.Slice(start);
    }
    
    auto Buffer::operator[](std::size_t index) -> uint8_t& {
      if (index >= cap_) {
    
        throw IndexOutOfBounds{};
    
    Daniel Lyubomirov's avatar
    Daniel Lyubomirov committed
      }
    
      return data_[index];
    }
    
    auto Buffer::operator[](std::size_t index) const -> const uint8_t& {
      if (index >= cap_) {
    
        throw IndexOutOfBounds{};
    
    Daniel Lyubomirov's avatar
    Daniel Lyubomirov committed
      }
    
      return data_[index];
    }
    
    } // namespace vereign::bytes