From 6a79741d4761f9bed0f137ad63a0d65a51fd407e Mon Sep 17 00:00:00 2001 From: Samuel Debionne Date: Sun, 5 Apr 2020 10:29:46 +0200 Subject: [PATCH] Revert to tag dispatching implementation with appropriate used of propagate_on_container_move_assignment and rebinded allocator type to choose pocma. --- include/boost/gil/image.hpp | 111 ++++++++++++++++++++---------------- 1 file changed, 62 insertions(+), 49 deletions(-) diff --git a/include/boost/gil/image.hpp b/include/boost/gil/image.hpp index 394785a1ec..649fdceb1a 100644 --- a/include/boost/gil/image.hpp +++ b/include/boost/gil/image.hpp @@ -149,55 +149,68 @@ class image return *this; } - image& operator=(image&& img) - { - if (this != std::addressof(img)) - { - auto const exchange_memory = [](image& lhs, image& rhs) - { - lhs._memory = boost::exchange(rhs._memory, nullptr); - lhs._align_in_bytes = boost::exchange(rhs._align_in_bytes, 0); - lhs._allocated_bytes = boost::exchange(rhs._allocated_bytes, 0); - lhs._view = boost::exchange(rhs._view, image::view_t{}); - }; - - constexpr bool pocma = std::allocator_traits::propagate_on_container_move_assignment::value; - if (pocma) - { - // non-sticky allocator, can adopt the memory, fast - destruct_pixels(this->_view); - this->deallocate(); - this->_alloc = img._alloc; - exchange_memory(*this, img); - } - else if (_alloc == img._alloc) - { - // allocator stuck to the rhs, but it's equivalent of ours, we can still adopt the memory - destruct_pixels(_view); - this->deallocate(); - exchange_memory(*this, img); - } - else - { - // cannot propagate the allocator and cannot adopt the memory - if (img._memory) - { - allocate_and_copy(img.dimensions(), img._view); - destruct_pixels(img._view); - img.deallocate(); - img._view = image::view_t{}; - } - else - { - destruct_pixels(this->_view); - this->deallocate(); - this->_view = view_t{}; - } - } - } - - return *this; - } + private: + using propagate_allocators = std::true_type; + using no_propagate_allocators = std::false_type; + + template + using choose_pocma = typename std::conditional< + // TODO: Use std::allocator_traits::is_always_equal if available + std::is_empty::value, + std::true_type, + typename std::allocator_traits::propagate_on_container_move_assignment::type + >::type; + + static void exchange_memory(image& lhs, image& rhs) + { + lhs._memory = boost::exchange(rhs._memory, nullptr); + lhs._align_in_bytes = boost::exchange(rhs._align_in_bytes, 0); + lhs._allocated_bytes = boost::exchange(rhs._allocated_bytes, 0); + lhs._view = boost::exchange(rhs._view, image::view_t{}); + }; + + void move_assign(image& img, propagate_allocators) noexcept { + // non-sticky allocator, can adopt the memory, fast + destruct_pixels(_view); + this->deallocate(); + this->_alloc = img._alloc; + exchange_memory(*this, img); + } + + void move_assign(image& img, no_propagate_allocators) { + if (_alloc == img._alloc) { + // allocator stuck to the rhs, but it's equivalent of ours, we can still adopt the memory + destruct_pixels(_view); + this->deallocate(); + exchange_memory(*this, img); + } else { + // cannot propagate the allocator and cannot adopt the memory + if (img._memory) + { + allocate_and_copy(img.dimensions(), img._view); + destruct_pixels(img._view); + img.deallocate(); + img._view = image::view_t{}; + } + else + { + destruct_pixels(this->_view); + this->deallocate(); + this->_view = view_t{}; + } + } + } + + public: + // TODO: Use noexcept(noexcept(move_assign(img, choose_pocma{}))) + // But https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52869 prevents it (fixed in GCC > 9) + image& operator=(image&& img) { + if (this != std::addressof(img)) + // Use rebinded alloc to choose pocma + move_assign(img, choose_pocma{}); + + return *this; + } ~image() {