File: | /home/gilles/Devel/8.x/core/libs/dimg/filters/fx/charcoalfilter.cpp |
Warning: | line 285, column 19 Assigned value is garbage or undefined |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* ============================================================ | |||
2 | * | |||
3 | * This file is a part of digiKam project | |||
4 | * https://www.digikam.org | |||
5 | * | |||
6 | * Date : 2005-05-25 | |||
7 | * Description : Charcoal threaded image filter. | |||
8 | * | |||
9 | * SPDX-FileCopyrightText: 2005-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> | |||
10 | * SPDX-FileCopyrightText: 2010 by Martin Klapetek <martin dot klapetek at gmail dot com> | |||
11 | * | |||
12 | * SPDX-License-Identifier: GPL-2.0-or-later | |||
13 | * | |||
14 | * ============================================================ */ | |||
15 | ||||
16 | #define SQ2PI2.50662827463100024161235523934010416269302368164062 2.50662827463100024161235523934010416269302368164062 | |||
17 | #define Epsilon1.0e-12 1.0e-12 | |||
18 | ||||
19 | #include "charcoalfilter.h" | |||
20 | ||||
21 | // C++ includes | |||
22 | ||||
23 | #include <cmath> | |||
24 | ||||
25 | // Qt includes | |||
26 | ||||
27 | #include <QtConcurrent> // krazy:exclude=includes | |||
28 | #include <QMutex> | |||
29 | ||||
30 | // Local includes | |||
31 | ||||
32 | #include "dimg.h" | |||
33 | #include "digikam_debug.h" | |||
34 | #include "blurfilter.h" | |||
35 | #include "stretchfilter.h" | |||
36 | #include "mixerfilter.h" | |||
37 | #include "invertfilter.h" | |||
38 | #include "digikam_globals_p.h" // For KF6::Ki18n deprecated | |||
39 | ||||
40 | namespace Digikam | |||
41 | { | |||
42 | ||||
43 | class Q_DECL_HIDDEN__attribute__((visibility("hidden"))) CharcoalFilter::Private | |||
44 | { | |||
45 | public: | |||
46 | ||||
47 | Private() = default; | |||
48 | ||||
49 | double pencil = 5.0; | |||
50 | double smooth = 10.0; | |||
51 | int globalProgress = 0; | |||
52 | ||||
53 | QMutex lock; | |||
54 | }; | |||
55 | ||||
56 | CharcoalFilter::CharcoalFilter(QObject* const parent) | |||
57 | : DImgThreadedFilter(parent), | |||
58 | d (new Private) | |||
59 | { | |||
60 | initFilter(); | |||
61 | } | |||
62 | ||||
63 | CharcoalFilter::CharcoalFilter(DImg* const orgImage, | |||
64 | QObject* const parent, | |||
65 | double pencil, | |||
66 | double smooth) | |||
67 | : DImgThreadedFilter(orgImage, parent, QLatin1String("Charcoal")), | |||
68 | d (new Private) | |||
69 | { | |||
70 | d->pencil = pencil; | |||
71 | d->smooth = smooth; | |||
72 | ||||
73 | initFilter(); | |||
74 | } | |||
75 | ||||
76 | CharcoalFilter::~CharcoalFilter() | |||
77 | { | |||
78 | cancelFilter(); | |||
79 | delete d; | |||
80 | } | |||
81 | ||||
82 | QString CharcoalFilter::DisplayableName() | |||
83 | { | |||
84 | return QString::fromUtf8(I18N_NOOP("Charcoal Effect")kli18n("Charcoal Effect").untranslatedText()); | |||
85 | } | |||
86 | ||||
87 | void CharcoalFilter::filterImage() | |||
88 | { | |||
89 | if (m_orgImage.isNull()) | |||
| ||||
90 | { | |||
91 | qCWarning(DIGIKAM_DIMG_LOG)for (QLoggingCategoryMacroHolder<QtWarningMsg> qt_category ((DIGIKAM_DIMG_LOG)()); qt_category; qt_category.control = false ) QMessageLogger(static_cast<const char *>("/home/gilles/Devel/8.x/core/libs/dimg/filters/fx/charcoalfilter.cpp" ), 91, static_cast<const char *>(__PRETTY_FUNCTION__), qt_category .name()).warning() << "No image data available!"; | |||
92 | return; | |||
93 | } | |||
94 | ||||
95 | if (d->pencil <= 0.0) | |||
96 | { | |||
97 | m_destImage = m_orgImage; | |||
98 | return; | |||
99 | } | |||
100 | ||||
101 | // -- Applying Edge effect ----------------------------------------------- | |||
102 | ||||
103 | long i = 0; | |||
104 | int kernelWidth = getOptimalKernelWidth(d->pencil, d->smooth); | |||
105 | ||||
106 | if ((int)m_orgImage.width() < kernelWidth) | |||
107 | { | |||
108 | qCWarning(DIGIKAM_DIMG_LOG)for (QLoggingCategoryMacroHolder<QtWarningMsg> qt_category ((DIGIKAM_DIMG_LOG)()); qt_category; qt_category.control = false ) QMessageLogger(static_cast<const char *>("/home/gilles/Devel/8.x/core/libs/dimg/filters/fx/charcoalfilter.cpp" ), 108, static_cast<const char *>(__PRETTY_FUNCTION__), qt_category.name()).warning() << "Image is smaller than radius!"; | |||
109 | return; | |||
110 | } | |||
111 | ||||
112 | QScopedArrayPointer<double> kernel(new double[kernelWidth * kernelWidth]{}); | |||
113 | ||||
114 | if (kernel.isNull()) | |||
115 | { | |||
116 | qCWarning(DIGIKAM_DIMG_LOG)for (QLoggingCategoryMacroHolder<QtWarningMsg> qt_category ((DIGIKAM_DIMG_LOG)()); qt_category; qt_category.control = false ) QMessageLogger(static_cast<const char *>("/home/gilles/Devel/8.x/core/libs/dimg/filters/fx/charcoalfilter.cpp" ), 116, static_cast<const char *>(__PRETTY_FUNCTION__), qt_category.name()).warning() << "Unable to allocate memory!"; | |||
117 | return; | |||
118 | } | |||
119 | ||||
120 | for (i = 0 ; i < (kernelWidth * kernelWidth) ; ++i) | |||
121 | { | |||
122 | kernel[i] = (-1.0); | |||
123 | } | |||
124 | ||||
125 | kernel[i / 2] = kernelWidth * kernelWidth - 1.0; | |||
126 | convolveImage(kernelWidth, kernel.data()); | |||
127 | ||||
128 | // -- Applying Gaussian blur effect --------------------------------------- | |||
129 | ||||
130 | // cppcheck-suppress unusedScopedObject | |||
131 | BlurFilter(this, m_destImage, m_destImage, 80, 85, (int)(d->smooth / 10.0)); | |||
132 | ||||
133 | if (!runningFlag()) | |||
134 | { | |||
135 | return; | |||
136 | } | |||
137 | ||||
138 | // -- Applying stretch contrast color effect ------------------------------- | |||
139 | ||||
140 | StretchFilter stretch(&m_destImage, &m_destImage); | |||
141 | stretch.startFilterDirectly(); | |||
142 | m_destImage.putImageData(stretch.getTargetImage().bits()); | |||
143 | ||||
144 | postProgress(90); | |||
145 | ||||
146 | if (!runningFlag()) | |||
147 | { | |||
148 | return; | |||
149 | } | |||
150 | ||||
151 | // -- Inverting image color ----------------------------------------------- | |||
152 | ||||
153 | InvertFilter invert(&m_destImage); | |||
154 | invert.startFilterDirectly(); | |||
155 | m_destImage.putImageData(invert.getTargetImage().bits()); | |||
156 | ||||
157 | postProgress(95); | |||
158 | ||||
159 | if (!runningFlag()) | |||
160 | { | |||
161 | return; | |||
162 | } | |||
163 | ||||
164 | // -- Convert to neutral black & white ------------------------------------ | |||
165 | ||||
166 | MixerContainer settings; | |||
167 | settings.bMonochrome = true; | |||
168 | settings.blackRedGain = 0.3; | |||
169 | settings.blackGreenGain = 0.59; | |||
170 | settings.blackBlueGain = 0.11; | |||
171 | MixerFilter mixer(&m_destImage, nullptr, settings); | |||
172 | mixer.startFilterDirectly(); | |||
173 | m_destImage.putImageData(mixer.getTargetImage().bits()); | |||
174 | ||||
175 | postProgress(100); | |||
176 | ||||
177 | if (!runningFlag()) | |||
178 | { | |||
179 | return; | |||
180 | } | |||
181 | } | |||
182 | ||||
183 | void CharcoalFilter::convolveImageMultithreaded(uint start, uint stop, double* normal_kernel, double kernelWidth) | |||
184 | { | |||
185 | int mx, my, sx, sy, mcx, mcy, oldProgress=0, progress=0; | |||
186 | double red, green, blue, alpha; | |||
187 | double* k = nullptr; | |||
188 | ||||
189 | uint height = m_destImage.height(); | |||
190 | uint width = m_destImage.width(); | |||
191 | bool sixteenBit = m_destImage.sixteenBit(); | |||
192 | uchar* ddata = m_destImage.bits(); | |||
193 | int ddepth = m_destImage.bytesDepth(); | |||
194 | uchar* sdata = m_orgImage.bits(); | |||
195 | int sdepth = m_orgImage.bytesDepth(); | |||
196 | double maxClamp = m_destImage.sixteenBit() ? 16777215.0 : 65535.0; | |||
197 | ||||
198 | for (uint y = start ; runningFlag() && (y < stop) ; ++y) | |||
199 | { | |||
200 | for (uint x = 0 ; runningFlag() && (x < width) ; ++x) | |||
201 | { | |||
202 | k = normal_kernel; | |||
203 | red = green = blue = alpha = 0; | |||
204 | sy = y - (kernelWidth / 2); | |||
205 | ||||
206 | for (mcy = 0 ; runningFlag() && (mcy < kernelWidth) ; ++mcy, ++sy) | |||
207 | { | |||
208 | my = (sy < 0) ? 0 | |||
209 | : (sy > ((int) height - 1)) ? height - 1 | |||
210 | : sy; | |||
211 | sx = x + (-kernelWidth / 2); | |||
212 | ||||
213 | for (mcx = 0 ; runningFlag() && (mcx < kernelWidth) ; ++mcx, ++sx) | |||
214 | { | |||
215 | mx = (sx < 0) ? 0 | |||
216 | : (sx > ((int) width - 1)) ? width - 1 | |||
217 | : sx; | |||
218 | DColor color(sdata + mx * sdepth + (width * my * sdepth), sixteenBit); | |||
219 | red += (*k) * (color.red() * 257.0); | |||
220 | green += (*k) * (color.green() * 257.0); | |||
221 | blue += (*k) * (color.blue() * 257.0); | |||
222 | alpha += (*k) * (color.alpha() * 257.0); | |||
223 | ++k; | |||
224 | } | |||
225 | } | |||
226 | ||||
227 | red = (red < 0.0) ? 0.0 | |||
228 | : (red > maxClamp) ? maxClamp | |||
229 | : red + 0.5; | |||
230 | ||||
231 | green = (green < 0.0) ? 0.0 | |||
232 | : (green > maxClamp) ? maxClamp | |||
233 | : green + 0.5; | |||
234 | ||||
235 | blue = (blue < 0.0) ? 0.0 | |||
236 | : (blue > maxClamp) ? maxClamp | |||
237 | : blue + 0.5; | |||
238 | ||||
239 | alpha = (alpha < 0.0) ? 0.0 | |||
240 | : (alpha > maxClamp) ? maxClamp | |||
241 | : alpha + 0.5; | |||
242 | ||||
243 | DColor color((int)(red / 257UL), (int)(green / 257UL), | |||
244 | (int)(blue / 257UL), (int)(alpha / 257UL), sixteenBit); | |||
245 | color.setPixel((ddata + x * ddepth + (width * y * ddepth))); | |||
246 | } | |||
247 | ||||
248 | progress = (int)( ( (double)y * (80.0 / QThreadPool::globalInstance()->maxThreadCount()) ) / (stop-start)); | |||
249 | ||||
250 | if ((progress % 5 == 0) && (progress > oldProgress)) | |||
251 | { | |||
252 | d->lock.lock(); | |||
253 | oldProgress = progress; | |||
254 | d->globalProgress += 5; | |||
255 | postProgress(d->globalProgress); | |||
256 | d->lock.unlock(); | |||
257 | } | |||
258 | } | |||
259 | } | |||
260 | ||||
261 | ||||
262 | bool CharcoalFilter::convolveImage(const unsigned int order, const double* kernel) | |||
263 | { | |||
264 | long kernelWidth = order; | |||
265 | ||||
266 | if ((kernelWidth % 2) == 0) | |||
267 | { | |||
268 | qCWarning(DIGIKAM_DIMG_LOG)for (QLoggingCategoryMacroHolder<QtWarningMsg> qt_category ((DIGIKAM_DIMG_LOG)()); qt_category; qt_category.control = false ) QMessageLogger(static_cast<const char *>("/home/gilles/Devel/8.x/core/libs/dimg/filters/fx/charcoalfilter.cpp" ), 268, static_cast<const char *>(__PRETTY_FUNCTION__), qt_category.name()).warning() << "Kernel width must be an odd number!"; | |||
269 | return false; | |||
270 | } | |||
271 | ||||
272 | long i; | |||
273 | double normalize = 0.0; | |||
274 | ||||
275 | QScopedArrayPointer<double> normal_kernel(new double[kernelWidth * kernelWidth]); | |||
276 | ||||
277 | if (!normal_kernel) | |||
278 | { | |||
279 | qCWarning(DIGIKAM_DIMG_LOG)for (QLoggingCategoryMacroHolder<QtWarningMsg> qt_category ((DIGIKAM_DIMG_LOG)()); qt_category; qt_category.control = false ) QMessageLogger(static_cast<const char *>("/home/gilles/Devel/8.x/core/libs/dimg/filters/fx/charcoalfilter.cpp" ), 279, static_cast<const char *>(__PRETTY_FUNCTION__), qt_category.name()).warning() << "Unable to allocate memory!"; | |||
280 | return false; | |||
281 | } | |||
282 | ||||
283 | for (i = 0 ; i < (kernelWidth * kernelWidth) ; ++i) | |||
284 | { | |||
285 | normalize += kernel[i]; | |||
| ||||
286 | } | |||
287 | ||||
288 | if (fabs(normalize) <= Epsilon1.0e-12) | |||
289 | { | |||
290 | normalize = 1.0; | |||
291 | } | |||
292 | ||||
293 | normalize = 1.0 / normalize; | |||
294 | ||||
295 | for (i = 0 ; i < (kernelWidth * kernelWidth) ; ++i) | |||
296 | { | |||
297 | normal_kernel[i] = normalize * kernel[i]; | |||
298 | } | |||
299 | ||||
300 | // -------------------------------------------------------- | |||
301 | ||||
302 | QList<int> vals = multithreadedSteps(m_orgImage.height()); | |||
303 | QList <QFuture<void> > tasks; | |||
304 | ||||
305 | for (int j = 0 ; runningFlag() && (j < vals.count()-1) ; ++j) | |||
306 | { | |||
307 | tasks.append(QtConcurrent::run( | |||
308 | ||||
309 | #if (QT_VERSION((6<<16)|(7<<8)|(0)) >= QT_VERSION_CHECK(6, 0, 0)((6<<16)|(0<<8)|(0))) | |||
310 | ||||
311 | &CharcoalFilter::convolveImageMultithreaded, this, | |||
312 | ||||
313 | #else | |||
314 | ||||
315 | this, &CharcoalFilter::convolveImageMultithreaded, | |||
316 | ||||
317 | #endif | |||
318 | ||||
319 | vals[j], | |||
320 | vals[j+1], | |||
321 | normal_kernel.data(), | |||
322 | kernelWidth | |||
323 | ) | |||
324 | ); | |||
325 | } | |||
326 | ||||
327 | Q_FOREACH (QFuture<void> t, tasks)for (auto _container_327 = QtPrivate::qMakeForeachContainer(tasks ); _container_327.i != _container_327.e; ++_container_327.i) if (QFuture<void> t = *_container_327.i; false) {} else | |||
328 | { | |||
329 | t.waitForFinished(); | |||
330 | } | |||
331 | ||||
332 | return true; | |||
333 | } | |||
334 | ||||
335 | int CharcoalFilter::getOptimalKernelWidth(double radius, double sigma) | |||
336 | { | |||
337 | double normalize, value; | |||
338 | long kernelWidth; | |||
339 | long u; | |||
340 | ||||
341 | if (radius > 0.0) | |||
342 | { | |||
343 | return((int)(2.0 * ceil(radius) + 1.0)); | |||
344 | } | |||
345 | ||||
346 | for (kernelWidth = 5 ; ;) | |||
347 | { | |||
348 | normalize = 0.0; | |||
349 | ||||
350 | for (u = (-kernelWidth / 2) ; u <= (kernelWidth / 2) ; ++u) | |||
351 | { | |||
352 | normalize += exp(-((double) u * u) / (2.0 * sigma * sigma)) / (SQ2PI2.50662827463100024161235523934010416269302368164062 * sigma); | |||
353 | } | |||
354 | ||||
355 | u = kernelWidth / 2; | |||
356 | value = exp(-((double) u * u) / (2.0 * sigma * sigma)) / (SQ2PI2.50662827463100024161235523934010416269302368164062 * sigma) / normalize; | |||
357 | ||||
358 | if ((long)(65535 * value) <= 0) | |||
359 | { | |||
360 | break; | |||
361 | } | |||
362 | ||||
363 | kernelWidth += 2; | |||
364 | } | |||
365 | ||||
366 | return ((int)kernelWidth - 2); | |||
367 | } | |||
368 | ||||
369 | FilterAction CharcoalFilter::filterAction() | |||
370 | { | |||
371 | FilterAction action(FilterIdentifier(), CurrentVersion()); | |||
372 | action.setDisplayableName(DisplayableName()); | |||
373 | ||||
374 | action.addParameter(QLatin1String("pencil"), d->pencil); | |||
375 | action.addParameter(QLatin1String("smooth"), d->smooth); | |||
376 | ||||
377 | return action; | |||
378 | } | |||
379 | ||||
380 | void CharcoalFilter::readParameters(const Digikam::FilterAction& action) | |||
381 | { | |||
382 | d->pencil = action.parameter(QLatin1String("pencil")).toDouble(); | |||
383 | d->smooth = action.parameter(QLatin1String("smooth")).toDouble(); | |||
384 | } | |||
385 | ||||
386 | } // namespace Digikam | |||
387 | ||||
388 | #include "moc_charcoalfilter.cpp" |
1 | // Copyright (C) 2016 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 QSCOPEDPOINTER_H |
5 | #define QSCOPEDPOINTER_H |
6 | |
7 | #include <QtCore/qglobal.h> |
8 | |
9 | #include <stdlib.h> |
10 | |
11 | QT_BEGIN_NAMESPACE |
12 | |
13 | template <typename T> |
14 | struct QScopedPointerDeleter |
15 | { |
16 | static inline void cleanup(T *pointer) noexcept |
17 | { |
18 | // Enforce a complete type. |
19 | // If you get a compile error here, read the section on forward declared |
20 | // classes in the QScopedPointer documentation. |
21 | typedef char IsIncompleteType[ sizeof(T) ? 1 : -1 ]; |
22 | (void) sizeof(IsIncompleteType); |
23 | |
24 | delete pointer; |
25 | } |
26 | void operator()(T *pointer) const noexcept |
27 | { |
28 | cleanup(pointer); |
29 | } |
30 | }; |
31 | |
32 | template <typename T> |
33 | struct QScopedPointerArrayDeleter |
34 | { |
35 | static inline void cleanup(T *pointer) noexcept |
36 | { |
37 | // Enforce a complete type. |
38 | // If you get a compile error here, read the section on forward declared |
39 | // classes in the QScopedPointer documentation. |
40 | typedef char IsIncompleteType[ sizeof(T) ? 1 : -1 ]; |
41 | (void) sizeof(IsIncompleteType); |
42 | |
43 | delete[] pointer; |
44 | } |
45 | void operator()(T *pointer) const noexcept |
46 | { |
47 | cleanup(pointer); |
48 | } |
49 | }; |
50 | |
51 | struct QScopedPointerPodDeleter |
52 | { |
53 | static inline void cleanup(void *pointer) noexcept { free(pointer); } |
54 | void operator()(void *pointer) const noexcept { cleanup(pointer); } |
55 | }; |
56 | |
57 | #ifndef QT_NO_QOBJECT |
58 | template <typename T> |
59 | struct QScopedPointerObjectDeleteLater |
60 | { |
61 | static inline void cleanup(T *pointer) { if (pointer) pointer->deleteLater(); } |
62 | void operator()(T *pointer) const { cleanup(pointer); } |
63 | }; |
64 | |
65 | class QObject; |
66 | typedef QScopedPointerObjectDeleteLater<QObject> QScopedPointerDeleteLater; |
67 | #endif |
68 | |
69 | template <typename T, typename Cleanup = QScopedPointerDeleter<T> > |
70 | class QScopedPointer |
71 | { |
72 | public: |
73 | Q_NODISCARD_CTOR[[nodiscard]] |
74 | explicit QScopedPointer(T *p = nullptr) noexcept : d(p) |
75 | { |
76 | } |
77 | |
78 | inline ~QScopedPointer() |
79 | { |
80 | T *oldD = this->d; |
81 | Cleanup::cleanup(oldD); |
82 | } |
83 | |
84 | inline T &operator*() const |
85 | { |
86 | Q_ASSERT(d)((d) ? static_cast<void>(0) : qt_assert("d", "/opt/qt6/include/QtCore/qscopedpointer.h" , 86)); |
87 | return *d; |
88 | } |
89 | |
90 | T *operator->() const noexcept |
91 | { |
92 | return d; |
93 | } |
94 | |
95 | bool operator!() const noexcept |
96 | { |
97 | return !d; |
98 | } |
99 | |
100 | explicit operator bool() const |
101 | { |
102 | return !isNull(); |
103 | } |
104 | |
105 | T *data() const noexcept |
106 | { |
107 | return d; |
108 | } |
109 | |
110 | T *get() const noexcept |
111 | { |
112 | return d; |
113 | } |
114 | |
115 | bool isNull() const noexcept |
116 | { |
117 | return !d; |
118 | } |
119 | |
120 | void reset(T *other = nullptr) noexcept(noexcept(Cleanup::cleanup(std::declval<T *>()))) |
121 | { |
122 | if (d == other) |
123 | return; |
124 | T *oldD = std::exchange(d, other); |
125 | Cleanup::cleanup(oldD); |
126 | } |
127 | |
128 | #if QT_DEPRECATED_SINCE(6, 1)(((6<<16)|(1<<8)|(0)) > 0x050E00) |
129 | QT_DEPRECATED_VERSION_X_6_1("Use std::unique_ptr instead, and call release().") |
130 | T *take() noexcept |
131 | { |
132 | T *oldD = std::exchange(d, nullptr); |
133 | return oldD; |
134 | } |
135 | #endif |
136 | |
137 | #if QT_DEPRECATED_SINCE(6, 2)(((6<<16)|(2<<8)|(0)) > 0x050E00) |
138 | QT_DEPRECATED_VERSION_X_6_2("Use std::unique_ptr instead of QScopedPointer.") |
139 | void swap(QScopedPointer<T, Cleanup> &other) noexcept |
140 | { |
141 | qt_ptr_swap(d, other.d); |
142 | } |
143 | #endif |
144 | |
145 | typedef T *pointer; |
146 | |
147 | friend bool operator==(const QScopedPointer<T, Cleanup> &lhs, const QScopedPointer<T, Cleanup> &rhs) noexcept |
148 | { |
149 | return lhs.data() == rhs.data(); |
150 | } |
151 | |
152 | friend bool operator!=(const QScopedPointer<T, Cleanup> &lhs, const QScopedPointer<T, Cleanup> &rhs) noexcept |
153 | { |
154 | return lhs.data() != rhs.data(); |
155 | } |
156 | |
157 | friend bool operator==(const QScopedPointer<T, Cleanup> &lhs, std::nullptr_t) noexcept |
158 | { |
159 | return lhs.isNull(); |
160 | } |
161 | |
162 | friend bool operator==(std::nullptr_t, const QScopedPointer<T, Cleanup> &rhs) noexcept |
163 | { |
164 | return rhs.isNull(); |
165 | } |
166 | |
167 | friend bool operator!=(const QScopedPointer<T, Cleanup> &lhs, std::nullptr_t) noexcept |
168 | { |
169 | return !lhs.isNull(); |
170 | } |
171 | |
172 | friend bool operator!=(std::nullptr_t, const QScopedPointer<T, Cleanup> &rhs) noexcept |
173 | { |
174 | return !rhs.isNull(); |
175 | } |
176 | |
177 | #if QT_DEPRECATED_SINCE(6, 2)(((6<<16)|(2<<8)|(0)) > 0x050E00) |
178 | QT_DEPRECATED_VERSION_X_6_2("Use std::unique_ptr instead of QScopedPointer.") |
179 | friend void swap(QScopedPointer<T, Cleanup> &p1, QScopedPointer<T, Cleanup> &p2) noexcept |
180 | { p1.swap(p2); } |
181 | #endif |
182 | |
183 | protected: |
184 | T *d; |
185 | |
186 | private: |
187 | Q_DISABLE_COPY_MOVE(QScopedPointer)QScopedPointer(const QScopedPointer &) = delete; QScopedPointer &operator=(const QScopedPointer &) = delete; QScopedPointer (QScopedPointer &&) = delete; QScopedPointer &operator =(QScopedPointer &&) = delete; |
188 | }; |
189 | |
190 | template <typename T, typename Cleanup = QScopedPointerArrayDeleter<T> > |
191 | class QScopedArrayPointer : public QScopedPointer<T, Cleanup> |
192 | { |
193 | template <typename Ptr> |
194 | using if_same_type = typename std::enable_if<std::is_same<typename std::remove_cv<T>::type, Ptr>::value, bool>::type; |
195 | public: |
196 | Q_NODISCARD_CTOR[[nodiscard]] |
197 | inline QScopedArrayPointer() : QScopedPointer<T, Cleanup>(nullptr) {} |
198 | inline ~QScopedArrayPointer() = default; |
199 | |
200 | template <typename D, if_same_type<D> = true> |
201 | Q_NODISCARD_CTOR[[nodiscard]] |
202 | explicit QScopedArrayPointer(D *p) |
203 | : QScopedPointer<T, Cleanup>(p) |
204 | { |
205 | } |
206 | |
207 | T &operator[](qsizetype i) |
208 | { |
209 | return this->d[i]; |
210 | } |
211 | |
212 | const T &operator[](qsizetype i) const |
213 | { |
214 | return this->d[i]; |
215 | } |
216 | |
217 | #if QT_DEPRECATED_SINCE(6, 2)(((6<<16)|(2<<8)|(0)) > 0x050E00) |
218 | QT_DEPRECATED_VERSION_X_6_2("Use std::unique_ptr instead of QScopedArrayPointer.") |
219 | void swap(QScopedArrayPointer &other) noexcept // prevent QScopedPointer <->QScopedArrayPointer swaps |
220 | { QScopedPointer<T, Cleanup>::swap(other); } |
221 | #endif |
222 | |
223 | private: |
224 | explicit inline QScopedArrayPointer(void *) |
225 | { |
226 | // Enforce the same type. |
227 | |
228 | // If you get a compile error here, make sure you declare |
229 | // QScopedArrayPointer with the same template type as you pass to the |
230 | // constructor. See also the QScopedPointer documentation. |
231 | |
232 | // Storing a scalar array as a pointer to a different type is not |
233 | // allowed and results in undefined behavior. |
234 | } |
235 | |
236 | Q_DISABLE_COPY_MOVE(QScopedArrayPointer)QScopedArrayPointer(const QScopedArrayPointer &) = delete ; QScopedArrayPointer &operator=(const QScopedArrayPointer &) = delete; QScopedArrayPointer(QScopedArrayPointer && ) = delete; QScopedArrayPointer &operator=(QScopedArrayPointer &&) = delete; |
237 | }; |
238 | |
239 | #if QT_DEPRECATED_SINCE(6, 2)(((6<<16)|(2<<8)|(0)) > 0x050E00) |
240 | template <typename T, typename Cleanup> |
241 | QT_DEPRECATED_VERSION_X_6_2("Use std::unique_ptr instead of QScopedArrayPointer.") |
242 | inline void swap(QScopedArrayPointer<T, Cleanup> &lhs, QScopedArrayPointer<T, Cleanup> &rhs) noexcept |
243 | { lhs.swap(rhs); } |
244 | #endif |
245 | |
246 | QT_END_NAMESPACE |
247 | |
248 | #endif // QSCOPEDPOINTER_H |