Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
quniquehandle_p.h
Go to the documentation of this file.
1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QUNIQUEHANDLE_P_H
5#define QUNIQUEHANDLE_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QtCore/qtconfigmacros.h>
19#include <QtCore/qassert.h>
20#include <QtCore/qcompare.h>
21#include <QtCore/qswap.h>
22#include <QtCore/qtclasshelpermacros.h>
23
24#include <memory>
25#include <utility>
26#include <type_traits>
27
28QT_BEGIN_NAMESPACE
29
30/*! \internal QUniqueHandle is a general purpose RAII wrapper intended
31 for interfacing with resource-allocating C-style APIs, for example
32 operating system APIs, database engine APIs, or any other scenario
33 where resources are allocated and released, and where pointer
34 semantics does not seem a perfect fit.
35
36 QUniqueHandle does not support copying, because it is intended to
37 maintain ownership of resources that can not be copied. This makes
38 it safer to use than naked handle types, since ownership is
39 maintained by design.
40
41 The underlying handle object is described using a client supplied
42 HandleTraits object that is implemented per resource type. The
43 traits struct must describe two properties of a handle:
44
45 1) What value is considered invalid
46 2) How to close a resource.
47
48 Example 1:
49
50 struct InvalidHandleTraits {
51 using Type = HANDLE;
52
53 static Type invalidValue() {
54 return INVALID_HANDLE_VALUE;
55 }
56
57 static bool close(Type handle) {
58 return CloseHandle(handle) != 0;
59 }
60 }
61
62 using FileHandle = QUniqueHandle<InvalidHandleTraits>;
63
64 Usage:
65
66 // Takes ownership of returned handle.
67 FileHandle handle{ CreateFile(...) };
68
69 if (!handle.isValid()) {
70 qDebug() << GetLastError()
71 return;
72 }
73
74 ...
75
76 Example 2:
77
78 struct SqLiteTraits {
79 using Type = sqlite3*;
80
81 static Type invalidValue() {
82 return nullptr;
83 }
84
85 static bool close(Type handle) {
86 sqlite3_close(handle);
87 return true;
88 }
89 }
90
91 using DbHandle = QUniqueHandle<SqLiteTraits>;
92
93 Usage:
94
95 DbHandle h;
96
97 // Take ownership of returned handle.
98 int result = sqlite3_open(":memory:", &h);
99
100 ...
101
102 NOTE: The QUniqueHandle assumes that closing a resource is
103 guaranteed to succeed, and provides no support for handling failure
104 to close a resource. It is therefore only recommended for use cases
105 where failure to close a resource is either not an error, or an
106 unrecoverable error.
107*/
108
109// clang-format off
110
111template <typename HandleTraits>
112class QUniqueHandle
113{
114public:
115 using Type = typename HandleTraits::Type;
116 static_assert(std::is_nothrow_default_constructible_v<Type>);
117 static_assert(std::is_nothrow_constructible_v<Type>);
118 static_assert(std::is_nothrow_copy_constructible_v<Type>);
119 static_assert(std::is_nothrow_move_constructible_v<Type>);
120 static_assert(std::is_nothrow_copy_assignable_v<Type>);
121 static_assert(std::is_nothrow_move_assignable_v<Type>);
122 static_assert(std::is_nothrow_destructible_v<Type>);
123 static_assert(noexcept(std::declval<Type>() == std::declval<Type>()));
124 static_assert(noexcept(std::declval<Type>() != std::declval<Type>()));
125 static_assert(noexcept(std::declval<Type>() < std::declval<Type>()));
126 static_assert(noexcept(std::declval<Type>() <= std::declval<Type>()));
127 static_assert(noexcept(std::declval<Type>() > std::declval<Type>()));
128 static_assert(noexcept(std::declval<Type>() >= std::declval<Type>()));
129
130 QUniqueHandle() = default;
131
132 explicit QUniqueHandle(const Type &handle) noexcept
133 : m_handle{ handle }
134 {}
135
136 QUniqueHandle(QUniqueHandle &&other) noexcept
137 : m_handle{ other.release() }
138 {}
139
140 ~QUniqueHandle() noexcept
141 {
142 close();
143 }
144
145 void swap(QUniqueHandle &other) noexcept
147 qSwap(m_handle, other.m_handle);
150 QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QUniqueHandle)
151
152 QUniqueHandle(const QUniqueHandle &) = delete;
153 QUniqueHandle &operator=(const QUniqueHandle &) = delete;
154
155
156 [[nodiscard]] bool isValid() const noexcept
157 {
158 return m_handle != HandleTraits::invalidValue();
159 }
160
161 [[nodiscard]] explicit operator bool() const noexcept
162 {
163 return isValid();
164 }
165
166 [[nodiscard]] Type get() const noexcept
167 {
168 return m_handle;
169 }
170
171 void reset(const Type& handle = HandleTraits::invalidValue()) noexcept
172 {
173 if (handle == m_handle)
174 return;
175
176 close();
177 m_handle = handle;
178 }
179
180 [[nodiscard]] Type release() noexcept
181 {
182 return std::exchange(m_handle, HandleTraits::invalidValue());
183 }
184
185 [[nodiscard]] Type *operator&() noexcept // NOLINT(google-runtime-operator)
186 {
187 Q_ASSERT(!isValid());
188 return &m_handle;
189 }
190
191 void close() noexcept
192 {
193 if (!isValid())
194 return;
195
196 const bool success = HandleTraits::close(m_handle);
197 Q_ASSERT(success);
198
199 m_handle = HandleTraits::invalidValue();
200 }
201
202private:
203 friend bool comparesEqual(const QUniqueHandle& lhs, const QUniqueHandle& rhs) noexcept
204 {
205 return lhs.get() == rhs.get();
206 }
207
208 friend Qt::strong_ordering compareThreeWay(const QUniqueHandle& lhs,
209 const QUniqueHandle& rhs) noexcept
210 {
211 if constexpr (std::is_pointer_v<Type>)
212 return qCompareThreeWay(Qt::totally_ordered_wrapper{ lhs.get() },
213 Qt::totally_ordered_wrapper{ rhs.get() });
214 else
215 return qCompareThreeWay(lhs.get(), rhs.get());
216 }
217
218 Q_DECLARE_STRONGLY_ORDERED(QUniqueHandle)
219
220 Type m_handle{ HandleTraits::invalidValue() };
221};
222
223// clang-format on
224
225template <typename Trait>
226void swap(QUniqueHandle<Trait> &lhs, QUniqueHandle<Trait> &rhs) noexcept
227{
228 lhs.swap(rhs);
229}
230
231
232QT_END_NAMESPACE
233
234#endif
void swap(QArrayDataPointer< T > &p1, QArrayDataPointer< T > &p2) noexcept