sane-project-backends/backend/genesys/row_buffer.h

192 wiersze
4.7 KiB
C++

/* sane - Scanner Access Now Easy.
Copyright (C) 2019 Povilas Kanapickas <povilas@radix.lt>
This file is part of the SANE package.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BACKEND_GENESYS_LINE_BUFFER_H
#define BACKEND_GENESYS_LINE_BUFFER_H
#include "error.h"
#include <algorithm>
#include <cstdint>
#include <cstddef>
#include <vector>
namespace genesys {
class RowBuffer
{
public:
RowBuffer(std::size_t line_bytes) : row_bytes_{line_bytes} {}
RowBuffer(const RowBuffer&) = default;
RowBuffer& operator=(const RowBuffer&) = default;
~RowBuffer() = default;
const std::uint8_t* get_row_ptr(std::size_t y) const
{
if (y >= height()) {
throw SaneException("y %zu is out of range", y);
}
return data_.data() + row_bytes_ * get_row_index(y);
}
std::uint8_t* get_row_ptr(std::size_t y)
{
if (y >= height()) {
throw SaneException("y %zu is out of range", y);
}
return data_.data() + row_bytes_ * get_row_index(y);
}
const std::uint8_t* get_front_row_ptr() const { return get_row_ptr(0); }
std::uint8_t* get_front_row_ptr() { return get_row_ptr(0); }
const std::uint8_t* get_back_row_ptr() const { return get_row_ptr(height() - 1); }
std::uint8_t* get_back_row_ptr() { return get_row_ptr(height() - 1); }
bool empty() const { return is_linear_ && first_ == last_; }
bool full()
{
if (is_linear_) {
return last_ == buffer_end_;
}
return first_ == last_;
}
bool is_linear() const { return is_linear_; }
void linearize()
{
if (!is_linear_) {
std::rotate(data_.begin(), data_.begin() + row_bytes_ * first_, data_.end());
last_ = height();
first_ = 0;
is_linear_ = true;
}
}
void pop_front()
{
if (empty()) {
throw SaneException("Trying to pop out of empty() line buffer");
}
first_++;
if (first_ == last_) {
first_ = 0;
last_ = 0;
is_linear_ = true;
} else if (first_ == buffer_end_) {
first_ = 0;
is_linear_ = true;
}
}
void push_front()
{
if (height() + 1 >= height_capacity()) {
ensure_capacity(std::max<std::size_t>(1, height() * 2));
}
if (first_ == 0) {
is_linear_ = false;
first_ = buffer_end_;
}
first_--;
}
void pop_back()
{
if (empty()) {
throw SaneException("Trying to pop out of empty() line buffer");
}
if (last_ == 0) {
last_ = buffer_end_;
is_linear_ = true;
}
last_--;
if (first_ == last_) {
first_ = 0;
last_ = 0;
is_linear_ = true;
}
}
void push_back()
{
if (height() + 1 >= height_capacity()) {
ensure_capacity(std::max<std::size_t>(1, height() * 2));
}
if (last_ == buffer_end_) {
is_linear_ = false;
last_ = 0;
}
last_++;
}
std::size_t row_bytes() const { return row_bytes_; }
std::size_t height() const
{
if (!is_linear_) {
return last_ + buffer_end_ - first_;
}
return last_ - first_;
}
std::size_t height_capacity() const { return buffer_end_; }
void clear()
{
first_ = 0;
last_ = 0;
}
private:
std::size_t get_row_index(std::size_t index) const
{
if (index >= buffer_end_ - first_) {
return index - (buffer_end_ - first_);
}
return index + first_;
}
void ensure_capacity(std::size_t capacity)
{
if (capacity < height_capacity())
return;
linearize();
data_.resize(capacity * row_bytes_);
buffer_end_ = capacity;
}
private:
std::size_t row_bytes_ = 0;
std::size_t first_ = 0;
std::size_t last_ = 0;
std::size_t buffer_end_ = 0;
bool is_linear_ = true;
std::vector<std::uint8_t> data_;
};
} // namespace genesys
#endif // BACKEND_GENESYS_LINE_BUFFER_H