diff --git a/include/boost/gil/image.hpp b/include/boost/gil/image.hpp index 1ada7c2183..09c02adbcc 100644 --- a/include/boost/gil/image.hpp +++ b/include/boost/gil/image.hpp @@ -101,6 +101,19 @@ class image { allocate_and_copy(img.dimensions(),img._view); } + // TODO Optimization: use noexcept (requires _view to be nothrow copy constructible) + image(image&& img) : + _view(img._view), + _memory(img._memory), + _align_in_bytes(img._align_in_bytes), + _alloc(std::move(img._alloc)), + _allocated_bytes(img._allocated_bytes) { + img._view = view_t(); + img._memory = nullptr; + img._align_in_bytes = 0; + img._allocated_bytes = 0; + } + image& operator=(const image& img) { if (dimensions() == img.dimensions()) copy_pixels(img._view,_view); @@ -122,6 +135,48 @@ class image { return *this; } +private: + using equal_allocators = std::true_type; + using no_propagate_allocators = std::false_type; + + template + // TODO: Use std::allocator_traits::is_always_equal if available + using move_policy = typename std::is_empty::type; + + void move_assign(image& img, equal_allocators) { + destruct_pixels(_view); + deallocate(); + + // TODO Use std::exchange + _view = img._view; + _memory = img._memory; + _align_in_bytes = img._align_in_bytes; + _allocated_bytes = img._allocated_bytes; + + img._view = view_t(); + img._memory = nullptr; + img._align_in_bytes = 0; + img._allocated_bytes = 0; + } + + void move_assign(image& img, no_propagate_allocators) { + if (_alloc == img._alloc) { + move_assign(img, equal_allocators{}); + } else { + // Fallback to copy + image tmp(img); + swap(tmp); + } + } + +public: + image& operator=(image&& img) { + if (this != std::addressof(img)) + move_assign(img, move_policy{}); + + return *this; + } + ~image() { destruct_pixels(_view); deallocate(); diff --git a/test/core/image/image.cpp b/test/core/image/image.cpp index dad767783d..98a250cd82 100644 --- a/test/core/image/image.cpp +++ b/test/core/image/image.cpp @@ -33,3 +33,26 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(constructor_with_dimensions_pixel, Image, fixture: } } } + +BOOST_AUTO_TEST_CASE_TEMPLATE(move_constructor, Image, fixture::image_types) +{ + gil::point_t const dimensions{256, 128}; + { + Image image(fixture::create_image(dimensions.x, dimensions.y, 0)); + + Image image2(std::move(image)); + BOOST_CHECK_EQUAL(image2.dimensions(), dimensions); + BOOST_CHECK_EQUAL(image.dimensions(), gil::point_t{}); + } +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(move_assignement, Image, fixture::image_types) +{ + gil::point_t const dimensions{256, 128}; + { + Image image = fixture::create_image(dimensions.x, dimensions.y, 0); + Image image2 = std::move(image); + BOOST_CHECK_EQUAL(image2.dimensions(), dimensions); + BOOST_CHECK_EQUAL(image.dimensions(), gil::point_t{}); + } +}