55 using interator = pointer;
56 using const_iterator = const_pointer;
66 template<
typename Pixmap>
76 [[nodiscard]]
constexpr row_iterator(Pixmap *ptr,
size_t y) noexcept : _ptr(ptr), _y(y) {}
78 constexpr row_iterator &operator++()
noexcept { ++_y;
return *
this; }
79 constexpr row_iterator &operator++(
int)
noexcept {
auto tmp = *
this; ++_y;
return tmp; }
80 constexpr row_iterator &operator--()
noexcept { --_y;
return *
this; }
81 constexpr row_iterator &operator--(
int)
noexcept {
auto tmp = *
this; --_y;
return tmp; }
82 [[nodiscard]]
constexpr auto operator*()
const noexcept {
return (*_ptr)[_y]; }
86 template<
typename Pixmap>
95 [[nodiscard]]
constexpr row_range(Pixmap *ptr) noexcept : _ptr(ptr) {}
96 [[nodiscard]]
constexpr auto begin()
const noexcept {
return row_iterator{_ptr, 0_uz}; }
97 [[nodiscard]]
constexpr auto end()
const noexcept {
return row_iterator{_ptr, _ptr->height()}; }
103 std::destroy(this->begin(), this->end());
104 if (_data !=
nullptr) {
120 _width(
other._width),
121 _height(
other._height),
122 _allocator(
std::allocator_traits<
allocator_type>::select_on_container_copy_construction(
other._allocator))
135 _data(std::exchange(
other._data,
nullptr)),
136 _capacity(std::exchange(
other._capacity, 0)),
137 _width(std::exchange(
other._width, 0)),
138 _height(std::exchange(
other._height, 0)),
139 _allocator(std::exchange(
other._allocator, {}))
154 auto const use_this_allocator = this->_allocator ==
other._allocator or not propogate_allocator;
156 if (&
other ==
this) {
159 }
else if (this->_capacity >=
other.size() and use_this_allocator) {
160 static_assert(std::is_nothrow_copy_constructible_v<value_type>);
164 _width =
other._width;
165 _height =
other._height;
170 auto& new_allocator = propogate_allocator ?
const_cast<allocator_type&
>(
other._allocator) : this->_allocator;
171 auto const new_capacity =
other.size();
186 std::destroy_n(new_data, new_capacity);
192 _capacity = new_capacity;
193 _width =
other._width;
194 _height =
other._height;
195 _allocator = new_allocator;
211 if (&
other ==
this) {
214 }
else if (_allocator ==
other._allocator or propogate_allocator) {
218 _data = std::exchange(
other._data,
nullptr);
219 _capacity = std::exchange(
other._capacity, 0);
220 _width = std::exchange(
other._width, 0);
221 _height = std::exchange(
other._height, 0);
222 _allocator =
other._allocator;
225 }
else if (_capacity >=
other.size()) {
228 _width =
other._width;
229 _height =
other._height;
231 std::uninitialized_move(
other.begin(),
other.end(), this->begin());
238 auto const new_capacity =
other.size();
242 std::uninitialized_move(
other.begin(),
other.end(), new_data);
252 std::destroy_n(new_data, new_capacity);
258 _capacity = new_capacity;
259 _width =
other._width;
260 _height =
other._height;
269 [[nodiscard]]
constexpr pixmap() noexcept = default;
274 _data(
std::allocator_traits<
allocator_type>::allocate(allocator, width * height)),
275 _capacity(width * height),
278 _allocator(allocator)
280 std::uninitialized_value_construct(begin(), end());
283 template<std::convertible_to<value_type> O>
284 [[nodiscard]]
constexpr pixmap(
290 _data(
std::allocator_traits<
allocator_type>::allocate(allocator, width * height)),
291 _capacity(width * height),
294 _allocator(allocator)
296 if (width == stride) {
307 auto dst_end = end();
310 while (dst != dst_end) {
316 std::destroy(begin(), dst);
323 template<std::convertible_to<value_type> O>
324 [[nodiscard]]
constexpr pixmap(
329 pixmap(data, width, height, width, allocator)
333 template<std::convertible_to<value_type> O>
339 template<std::convertible_to<value_type> O>
345 template<std::same_as<value_type const> O>
346 [[nodiscard]]
constexpr operator pixmap_span<O>() const noexcept
348 return pixmap_span<O>{_data, _width, _height};
351 [[nodiscard]]
constexpr friend bool operator==(pixmap
const& lhs, pixmap
const& rhs)
noexcept
353 if (lhs._width != rhs._width or lhs._height != rhs._height) {
356 return std::equal(lhs.begin(), lhs.end(), rhs.begin());
359 [[nodiscard]]
constexpr allocator_type get_allocator() const noexcept
364 [[nodiscard]]
constexpr size_type width() const noexcept
369 [[nodiscard]]
constexpr size_type height() const noexcept
378 return _width * _height;
388 [[nodiscard]]
constexpr bool empty() const noexcept
390 return _width == 0 and _height == 0;
393 [[nodiscard]]
constexpr pointer data() noexcept
398 [[nodiscard]]
constexpr const_pointer data() const noexcept
403 [[nodiscard]]
constexpr interator begin() noexcept
408 [[nodiscard]]
constexpr const_iterator begin() const noexcept
413 [[nodiscard]]
constexpr const_iterator cbegin() const noexcept
418 [[nodiscard]]
constexpr interator end() noexcept
420 return _data +
size();
423 [[nodiscard]]
constexpr const_iterator end() const noexcept
425 return _data +
size();
428 [[nodiscard]]
constexpr const_iterator cend() const noexcept
430 return _data +
size();
435 hi_axiom(x < _width);
436 hi_axiom(y < _height);
437 return _data[y * _width + x];
442 hi_axiom(x < _width);
443 hi_axiom(y < _height);
444 return _data[y * _width + x];
449 hi_axiom(y < _height);
450 return {_data + y * _width, _width};
455 hi_axiom(y < height());
456 return {_data + y * _width, _width};
459 [[nodiscard]]
constexpr auto rows() noexcept
461 return row_range{
this};
464 [[nodiscard]]
constexpr auto rows() const noexcept
466 return row_range{
this};
469 [[nodiscard]]
constexpr pixmap
472 hi_axiom(x + new_width <= _width);
473 hi_axiom(y + new_height <= _height);
475 auto const p = _data + y * _width + x;
476 return {p, new_width, new_height, _width, allocator};
481 return subimage(x, y, new_width, new_height, _allocator);
484 constexpr void clear() noexcept
486 std::destroy(begin(), end());
491 constexpr void shrink_to_fit()
494 if (_data !=
nullptr) {
502 auto const new_capacity =
size();
506 std::uninitialized_move(begin(), end(), new_data);
512 std::destroy(begin(), end());
513 auto const old_capacity = std::exchange(_capacity, new_capacity);
514 auto const old_data = std::exchange(_data, new_data);
520 std::fill(dst.begin(), dst.end(), value);