52 using interator = pointer;
53 using const_iterator = const_pointer;
63 template<
typename Pixmap>
73 [[nodiscard]]
constexpr row_iterator(Pixmap *ptr,
size_t y) noexcept : _ptr(ptr), _y(y) {}
75 constexpr row_iterator &operator++()
noexcept { ++_y;
return *
this; }
76 constexpr row_iterator &operator++(
int)
noexcept {
auto tmp = *
this; ++_y;
return tmp; }
77 constexpr row_iterator &operator--()
noexcept { --_y;
return *
this; }
78 constexpr row_iterator &operator--(
int)
noexcept {
auto tmp = *
this; --_y;
return tmp; }
79 [[nodiscard]]
constexpr auto operator*()
const noexcept {
return (*_ptr)[_y]; }
83 template<
typename Pixmap>
92 [[nodiscard]]
constexpr row_range(Pixmap *ptr) noexcept : _ptr(ptr) {}
93 [[nodiscard]]
constexpr auto begin()
const noexcept {
return row_iterator{_ptr, 0_uz}; }
94 [[nodiscard]]
constexpr auto end()
const noexcept {
return row_iterator{_ptr, _ptr->height()}; }
100 std::destroy(this->begin(), this->end());
101 if (_data !=
nullptr) {
117 _width(
other._width),
118 _height(
other._height),
119 _allocator(
std::allocator_traits<
allocator_type>::select_on_container_copy_construction(
other._allocator))
132 _data(std::exchange(
other._data,
nullptr)),
133 _capacity(std::exchange(
other._capacity, 0)),
134 _width(std::exchange(
other._width, 0)),
135 _height(std::exchange(
other._height, 0)),
136 _allocator(std::exchange(
other._allocator, {}))
151 hilet use_this_allocator = this->_allocator ==
other._allocator or not propogate_allocator;
153 if (&
other ==
this) {
156 }
else if (this->_capacity >=
other.size() and use_this_allocator) {
157 static_assert(std::is_nothrow_copy_constructible_v<value_type>);
161 _width =
other._width;
162 _height =
other._height;
167 auto& new_allocator = propogate_allocator ?
const_cast<allocator_type&
>(
other._allocator) : this->_allocator;
183 std::destroy_n(new_data, new_capacity);
189 _capacity = new_capacity;
190 _width =
other._width;
191 _height =
other._height;
192 _allocator = new_allocator;
208 if (&
other ==
this) {
211 }
else if (_allocator ==
other._allocator or propogate_allocator) {
215 _data = std::exchange(
other._data,
nullptr);
216 _capacity = std::exchange(
other._capacity, 0);
217 _width = std::exchange(
other._width, 0);
218 _height = std::exchange(
other._height, 0);
219 _allocator =
other._allocator;
222 }
else if (_capacity >=
other.size()) {
225 _width =
other._width;
226 _height =
other._height;
228 std::uninitialized_move(
other.begin(),
other.end(), this->begin());
239 std::uninitialized_move(
other.begin(),
other.end(), new_data);
249 std::destroy_n(new_data, new_capacity);
255 _capacity = new_capacity;
256 _width =
other._width;
257 _height =
other._height;
266 [[nodiscard]]
constexpr pixmap() noexcept = default;
271 _data(
std::allocator_traits<
allocator_type>::allocate(allocator, width * height)),
272 _capacity(width * height),
275 _allocator(allocator)
277 std::uninitialized_value_construct(begin(), end());
280 template<std::convertible_to<value_type> O>
281 [[nodiscard]]
constexpr pixmap(
287 _data(
std::allocator_traits<
allocator_type>::allocate(allocator, width * height)),
288 _capacity(width * height),
291 _allocator(allocator)
293 if (width == stride) {
304 auto dst_end = end();
307 while (dst != dst_end) {
313 std::destroy(begin(), dst);
320 template<std::convertible_to<value_type> O>
321 [[nodiscard]]
constexpr pixmap(
326 pixmap(data, width, height, width, allocator)
330 template<std::convertible_to<value_type> O>
336 template<std::convertible_to<value_type> O>
342 template<std::same_as<value_type const> O>
343 [[nodiscard]]
constexpr operator pixmap_span<O>() const noexcept
345 return pixmap_span<O>{_data, _width, _height};
348 [[nodiscard]]
constexpr friend bool operator==(pixmap
const& lhs, pixmap
const& rhs)
noexcept
350 if (lhs._width != rhs._width or lhs._height != rhs._height) {
353 return std::equal(lhs.begin(), lhs.end(), rhs.begin());
356 [[nodiscard]]
constexpr allocator_type get_allocator() const noexcept
361 [[nodiscard]]
constexpr size_type width() const noexcept
366 [[nodiscard]]
constexpr size_type height() const noexcept
375 return _width * _height;
385 [[nodiscard]]
constexpr bool empty() const noexcept
387 return _width == 0 and _height == 0;
390 [[nodiscard]]
constexpr pointer data() noexcept
395 [[nodiscard]]
constexpr const_pointer data() const noexcept
400 [[nodiscard]]
constexpr interator begin() noexcept
405 [[nodiscard]]
constexpr const_iterator begin() const noexcept
410 [[nodiscard]]
constexpr const_iterator cbegin() const noexcept
415 [[nodiscard]]
constexpr interator end() noexcept
417 return _data +
size();
420 [[nodiscard]]
constexpr const_iterator end() const noexcept
422 return _data +
size();
425 [[nodiscard]]
constexpr const_iterator cend() const noexcept
427 return _data +
size();
434 return _data[y * _width + x];
441 return _data[y * _width + x];
447 return {_data + y * _width, _width};
453 return {_data + y * _width, _width};
456 [[nodiscard]]
constexpr auto rows() noexcept
458 return row_range{
this};
461 [[nodiscard]]
constexpr auto rows() const noexcept
463 return row_range{
this};
466 [[nodiscard]]
constexpr pixmap
470 hi_axiom(y + new_height <= _height);
472 hilet p = _data + y * _width + x;
473 return {p, new_width, new_height, _width, allocator};
478 return subimage(x, y, new_width, new_height, _allocator);
481 constexpr void clear() noexcept
483 std::destroy(begin(), end());
488 constexpr void shrink_to_fit()
491 if (_data !=
nullptr) {
503 std::uninitialized_move(begin(), end(), new_data);
509 std::destroy(begin(), end());
510 hilet old_capacity = std::exchange(_capacity, new_capacity);
511 hilet old_data = std::exchange(_data, new_data);
517 std::fill(dst.begin(), dst.end(), value);