1 /* sane - Scanner Access Now Easy. 2 3 Copyright (C) 2019 Povilas Kanapickas <povilas@radix.lt> 4 5 This file is part of the SANE package. 6 7 This program is free software; you can redistribute it and/or 8 modify it under the terms of the GNU General Public License as 9 published by the Free Software Foundation; either version 2 of the 10 License, or (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, but 13 WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program. If not, see <https://www.gnu.org/licenses/>. 19 */ 20 21 #ifndef BACKEND_GENESYS_LINE_BUFFER_H 22 #define BACKEND_GENESYS_LINE_BUFFER_H 23 24 #include "error.h" 25 26 #include <algorithm> 27 #include <cstdint> 28 #include <cstddef> 29 #include <vector> 30 31 namespace genesys { 32 33 class RowBuffer 34 { 35 public: RowBuffer(std::size_t line_bytes)36 RowBuffer(std::size_t line_bytes) : row_bytes_{line_bytes} {} 37 RowBuffer(const RowBuffer&) = default; 38 RowBuffer& operator=(const RowBuffer&) = default; 39 ~RowBuffer() = default; 40 get_row_ptr(std::size_t y) const41 const std::uint8_t* get_row_ptr(std::size_t y) const 42 { 43 if (y >= height()) { 44 throw SaneException("y %zu is out of range", y); 45 } 46 return data_.data() + row_bytes_ * get_row_index(y); 47 } 48 get_row_ptr(std::size_t y)49 std::uint8_t* get_row_ptr(std::size_t y) 50 { 51 if (y >= height()) { 52 throw SaneException("y %zu is out of range", y); 53 } 54 return data_.data() + row_bytes_ * get_row_index(y); 55 } 56 get_front_row_ptr() const57 const std::uint8_t* get_front_row_ptr() const { return get_row_ptr(0); } get_front_row_ptr()58 std::uint8_t* get_front_row_ptr() { return get_row_ptr(0); } get_back_row_ptr() const59 const std::uint8_t* get_back_row_ptr() const { return get_row_ptr(height() - 1); } get_back_row_ptr()60 std::uint8_t* get_back_row_ptr() { return get_row_ptr(height() - 1); } 61 empty() const62 bool empty() const { return is_linear_ && first_ == last_; } 63 full()64 bool full() 65 { 66 if (is_linear_) { 67 return last_ == buffer_end_; 68 } 69 return first_ == last_; 70 } 71 is_linear() const72 bool is_linear() const { return is_linear_; } 73 linearize()74 void linearize() 75 { 76 if (!is_linear_) { 77 std::rotate(data_.begin(), data_.begin() + row_bytes_ * first_, data_.end()); 78 last_ = height(); 79 first_ = 0; 80 is_linear_ = true; 81 } 82 } 83 pop_front()84 void pop_front() 85 { 86 if (empty()) { 87 throw SaneException("Trying to pop out of empty() line buffer"); 88 } 89 90 first_++; 91 if (first_ == last_) { 92 first_ = 0; 93 last_ = 0; 94 is_linear_ = true; 95 } else if (first_ == buffer_end_) { 96 first_ = 0; 97 is_linear_ = true; 98 } 99 } 100 push_front()101 void push_front() 102 { 103 if (height() + 1 >= height_capacity()) { 104 ensure_capacity(std::max<std::size_t>(1, height() * 2)); 105 } 106 107 if (first_ == 0) { 108 is_linear_ = false; 109 first_ = buffer_end_; 110 } 111 first_--; 112 } 113 pop_back()114 void pop_back() 115 { 116 if (empty()) { 117 throw SaneException("Trying to pop out of empty() line buffer"); 118 } 119 if (last_ == 0) { 120 last_ = buffer_end_; 121 is_linear_ = true; 122 } 123 last_--; 124 if (first_ == last_) { 125 first_ = 0; 126 last_ = 0; 127 is_linear_ = true; 128 } 129 } 130 push_back()131 void push_back() 132 { 133 if (height() + 1 >= height_capacity()) { 134 ensure_capacity(std::max<std::size_t>(1, height() * 2)); 135 } 136 137 if (last_ == buffer_end_) { 138 is_linear_ = false; 139 last_ = 0; 140 } 141 last_++; 142 } 143 row_bytes() const144 std::size_t row_bytes() const { return row_bytes_; } 145 height() const146 std::size_t height() const 147 { 148 if (!is_linear_) { 149 return last_ + buffer_end_ - first_; 150 } 151 return last_ - first_; 152 } 153 height_capacity() const154 std::size_t height_capacity() const { return buffer_end_; } 155 clear()156 void clear() 157 { 158 first_ = 0; 159 last_ = 0; 160 } 161 162 private: get_row_index(std::size_t index) const163 std::size_t get_row_index(std::size_t index) const 164 { 165 if (index >= buffer_end_ - first_) { 166 return index - (buffer_end_ - first_); 167 } 168 return index + first_; 169 } 170 ensure_capacity(std::size_t capacity)171 void ensure_capacity(std::size_t capacity) 172 { 173 if (capacity < height_capacity()) 174 return; 175 linearize(); 176 data_.resize(capacity * row_bytes_); 177 buffer_end_ = capacity; 178 } 179 180 private: 181 std::size_t row_bytes_ = 0; 182 std::size_t first_ = 0; 183 std::size_t last_ = 0; 184 std::size_t buffer_end_ = 0; 185 bool is_linear_ = true; 186 std::vector<std::uint8_t> data_; 187 }; 188 189 } // namespace genesys 190 191 #endif // BACKEND_GENESYS_LINE_BUFFER_H 192