diff --git a/src/Magnum/Vk/Queue.cpp b/src/Magnum/Vk/Queue.cpp index 0f1cb52da..5073463d9 100644 --- a/src/Magnum/Vk/Queue.cpp +++ b/src/Magnum/Vk/Queue.cpp @@ -39,4 +39,17 @@ Queue Queue::wrap(Device& device, VkQueue handle) { Queue::Queue(NoCreateT): _device{}, _handle{} {} +Queue::Queue(Queue&& other) noexcept: _device{other._device}, _handle{other._handle} { + other._handle = {}; +} + +Queue::~Queue() = default; + +Queue& Queue::operator=(Queue&& other) noexcept { + using std::swap; + swap(other._device, _device); + swap(other._handle, _handle); + return *this; +} + }} diff --git a/src/Magnum/Vk/Queue.h b/src/Magnum/Vk/Queue.h index af4c2195c..d933c6651 100644 --- a/src/Magnum/Vk/Queue.h +++ b/src/Magnum/Vk/Queue.h @@ -67,6 +67,32 @@ class MAGNUM_VK_EXPORT Queue { */ explicit Queue(NoCreateT); + /* The class *technically* doesn't need to be move-only, it's done only + for consistency and to make room for possible future move-only + state. If move-only proves to be annoying, it might get removed -- + going the other way would be much more painful and breaking user + code. */ + + /** @brief Copying is not allowed */ + Queue(const Queue&) = delete; + + /** @brief Move constructor */ + Queue(Queue&& other) noexcept; + + /** + * @brief Destructor + * + * Queues are associated with the device they come from, so no explicit + * destruction is needed. + */ + ~Queue(); + + /** @brief Copying is not allowed */ + Queue& operator=(const Queue&) = delete; + + /** @brief Move assignment */ + Queue& operator=(Queue&& other) noexcept; + /** @brief Underlying @type_vk{Queue} handle */ VkQueue handle() { return _handle; } /** @overload */ diff --git a/src/Magnum/Vk/Test/QueueTest.cpp b/src/Magnum/Vk/Test/QueueTest.cpp index 1de73540e..c372f417b 100644 --- a/src/Magnum/Vk/Test/QueueTest.cpp +++ b/src/Magnum/Vk/Test/QueueTest.cpp @@ -34,12 +34,16 @@ struct QueueTest: TestSuite::Tester { explicit QueueTest(); void constructNoCreate(); + void constructCopy(); + void constructMove(); void wrap(); }; QueueTest::QueueTest() { addTests({&QueueTest::constructNoCreate, + &QueueTest::constructCopy, + &QueueTest::constructMove, &QueueTest::wrap}); } @@ -54,6 +58,30 @@ void QueueTest::constructNoCreate() { CORRADE_VERIFY(!(std::is_convertible::value)); } +void QueueTest::constructCopy() { + CORRADE_VERIFY(!std::is_copy_constructible{}); + CORRADE_VERIFY(!std::is_copy_assignable{}); +} + +void QueueTest::constructMove() { + Device device{NoCreate}; + Queue a = Queue::wrap(device, reinterpret_cast(0xbadcafe)); + VkQueue handle = a.handle(); + CORRADE_VERIFY(a.handle()); + + Queue b = std::move(a); + CORRADE_VERIFY(!a.handle()); + CORRADE_COMPARE(b.handle(), handle); + + Queue c{NoCreate}; + c = std::move(b); + CORRADE_VERIFY(!b.handle()); + CORRADE_COMPARE(c.handle(), handle); + + CORRADE_VERIFY(std::is_nothrow_move_constructible::value); + CORRADE_VERIFY(std::is_nothrow_move_assignable::value); +} + void QueueTest::wrap() { /* Queues are not getting destroyed in any way, so it's enough to do it in a non-Vulkan-enabled test */