Revision control
Copy as Markdown
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#ifndef QCOMTASKRESOURCE_P_H
#define QCOMTASKRESOURCE_P_H
#include <QtCore/qassert.h>
#include <objbase.h>
#include <algorithm>
#include <type_traits>
#include <utility>
QT_BEGIN_NAMESPACE
class QEmptyDeleter final
{
public:
template<typename T>
void operator()(T /*element*/) const
{
}
};
class QComDeleter final
{
public:
template<typename T>
void operator()(T element) const
{
element->Release();
}
};
template<typename T>
class QComTaskResourceBase
{
public:
QComTaskResourceBase(const QComTaskResourceBase<T> &source) = delete;
QComTaskResourceBase &operator=(const QComTaskResourceBase<T> &right) = delete;
explicit operator bool() const { return m_resource != nullptr; }
T *get() const { return m_resource; }
protected:
QComTaskResourceBase() = default;
explicit QComTaskResourceBase(T *const resource) : m_resource(resource) { }
T *release() { return std::exchange(m_resource, nullptr); }
void reset(T *const resource = nullptr)
{
if (m_resource != resource) {
if (m_resource)
CoTaskMemFree(m_resource);
m_resource = resource;
}
}
T *m_resource = nullptr;
};
template<typename T, typename TElementDeleter = QEmptyDeleter>
class QComTaskResource final : public QComTaskResourceBase<T>
{
using Base = QComTaskResourceBase<T>;
public:
using Base::QComTaskResourceBase;
~QComTaskResource() { reset(); }
T *operator->() const { return m_resource; }
T &operator*() const { return *m_resource; }
T **address()
{
Q_ASSERT(m_resource == nullptr);
return &m_resource;
}
using Base::release;
using Base::reset;
private:
using Base::m_resource;
};
template<typename T, typename TElementDeleter>
class QComTaskResource<T[], TElementDeleter> final : public QComTaskResourceBase<T>
{
using Base = QComTaskResourceBase<T>;
public:
QComTaskResource() = default;
explicit QComTaskResource(T *const resource, const std::size_t size)
: Base(resource), m_size(size)
{
}
~QComTaskResource() { reset(); }
T &operator[](const std::size_t index) const
{
Q_ASSERT(index < m_size);
return m_resource[index];
}
T *release()
{
m_size = 0;
return Base::release();
}
void reset() { reset(nullptr, 0); }
void reset(T *const resource, const std::size_t size)
{
if (m_resource != resource) {
resetElements();
Base::reset(resource);
m_size = size;
}
}
private:
void resetElements()
{
if constexpr (!std::is_same_v<TElementDeleter, QEmptyDeleter>) {
std::for_each(m_resource, m_resource + m_size, TElementDeleter());
}
}
std::size_t m_size = 0;
using Base::m_resource;
};
QT_END_NAMESPACE
#endif