1// Copyright (C) 2025 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 Q_PMR_EMULATION_P_H
5#define Q_PMR_EMULATION_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
20#if defined(__APPLE__)
21// minimum requirement: iOS 17.0, macOS 14.0, watchOS 10.0 and tvOS 17.0.
22# include <Availability.h>
23# if !_LIBCPP_AVAILABILITY_HAS_PMR
24# define QT_MM_PMR_EMULATION
25# endif
26#endif
27
28#if defined(Q_OS_VXWORKS)
29// std::pmr::deque<variant> doesn't seem to compile on VxWorks, so we use our emulation
30# define QT_MM_PMR_EMULATION
31#endif
32
33#if !__has_include(<memory_resource>)
34# define QT_MM_PMR_EMULATION
35#endif
36
37#ifdef QT_MM_PMR_EMULATION
38
39# include <QtCore/qassert.h>
40
41# include <cstddef>
42# include <new>
43# include <typeinfo>
44
45#else
46
47# include <memory_resource>
48
49#endif
50
51QT_BEGIN_NAMESPACE
52
53namespace QtMultimediaPrivate::pmr {
54
55#ifndef QT_MM_PMR_EMULATION
56
57using memory_resource = std::pmr::memory_resource;
58template <typename T = std::byte>
59using polymorphic_allocator = std::pmr::polymorphic_allocator<T>;
60
61inline auto get_default_resource() noexcept
62{
63 return std::pmr::get_default_resource();
64}
65
66inline auto new_delete_resource() noexcept
67{
68 return std::pmr::new_delete_resource();
69}
70
71#else
72
73class memory_resource;
74memory_resource *get_default_resource() noexcept;
75memory_resource *new_delete_resource() noexcept;
76
77class memory_resource
78{
79public:
80 memory_resource() = default;
81 memory_resource(const memory_resource &) = delete;
82 memory_resource &operator=(const memory_resource &) = delete;
83 virtual ~memory_resource() noexcept = default;
84
85 [[nodiscard]]
86 void *allocate(size_t bytes, size_t alignment = alignof(std::max_align_t))
87 {
88 return do_allocate(bytes, alignment);
89 }
90
91 void deallocate(void *p, size_t bytes, size_t alignment = alignof(std::max_align_t))
92 {
93 do_deallocate(p, bytes, alignment);
94 }
95
96 bool is_equal(const memory_resource &other) const noexcept { return do_is_equal(other); }
97
98protected:
99 virtual void *do_allocate(size_t bytes, size_t alignment) = 0;
100 virtual void do_deallocate(void *p, size_t bytes, size_t alignment) = 0;
101 virtual bool do_is_equal(const memory_resource &other) const noexcept { return this == &other; }
102
103private:
104 template <class T>
105 friend class polymorphic_allocator;
106};
107
108inline bool operator==(const memory_resource &a, const memory_resource &b) noexcept
109{
110 return &a == &b || a.is_equal(b);
111}
112
113inline bool operator!=(const memory_resource &a, const memory_resource &b) noexcept
114{
115 return !(a == b);
116}
117
118template <class T>
119class polymorphic_allocator
120{
121public:
122 using value_type = T;
123
124 polymorphic_allocator() noexcept = default;
125 polymorphic_allocator(memory_resource *r) : m_resource(r) { Q_ASSERT(r); }
126 polymorphic_allocator(const polymorphic_allocator &other) noexcept = default;
127
128 template <class U>
129 polymorphic_allocator(const polymorphic_allocator<U> &other) noexcept
130 : m_resource(other.resource())
131 {
132 }
133
134 polymorphic_allocator &operator=(const polymorphic_allocator &other) noexcept = default;
135
136 [[nodiscard]]
137 T *allocate(size_t n)
138 {
139 void *ptr = m_resource->allocate(n * sizeof(T), alignof(T));
140 return static_cast<T *>(ptr);
141 }
142
143 void deallocate(T *p, size_t n) { m_resource->deallocate(p, n * sizeof(T), alignof(T)); }
144
145 [[nodiscard]]
146 memory_resource *resource() const noexcept
147 {
148 return m_resource;
149 }
150
151 [[nodiscard]]
152 polymorphic_allocator select_on_container_copy_construction() const
153 {
154 return polymorphic_allocator();
155 }
156
157private:
158 memory_resource *m_resource = get_default_resource();
159};
160
161template <class T1, class T2>
162bool operator==(const polymorphic_allocator<T1> &a, const polymorphic_allocator<T2> &b) noexcept
163{
164 return *a.resource() == *b.resource();
165}
166
167template <class T1, class T2>
168bool operator!=(const polymorphic_allocator<T1> &a, const polymorphic_allocator<T2> &b) noexcept
169{
170 return !(a == b);
171}
172
173namespace detail {
174
175class new_delete_resource_impl final : public memory_resource
176{
177public:
178 using memory_resource::memory_resource;
179
180protected:
181 void *do_allocate(size_t bytes, size_t alignment) override
182 {
183 return ::operator new(bytes, static_cast<std::align_val_t>(alignment));
184 }
185
186 void do_deallocate(void *p, [[maybe_unused]] size_t bytes, size_t alignment) override
187 {
188# ifdef __cpp_sized_deallocation
189 ::operator delete(p, bytes, static_cast<std::align_val_t>(alignment));
190# else
191 ::operator delete(p, static_cast<std::align_val_t>(alignment));
192# endif
193 }
194
195 bool do_is_equal(const memory_resource &other) const noexcept override
196 {
197 return &other == this || typeid(other) == typeid(new_delete_resource_impl);
198 }
199};
200
201} // namespace detail
202
203inline memory_resource *new_delete_resource() noexcept
204{
205 static detail::new_delete_resource_impl instance;
206 return &instance;
207}
208
209inline memory_resource *get_default_resource() noexcept
210{
211 return new_delete_resource();
212}
213
214#endif
215
216} // namespace QtMultimediaPrivate::pmr
217
218QT_END_NAMESPACE
219
220#ifdef QT_MM_PMR_EMULATION
221# undef QT_MM_PMR_EMULATION
222#endif // QT_MM_PMR_EMULATION
223
224#endif // Q_PMR_EMULATION_P_H
225

source code of qtmultimedia/src/multimedia/audio/q_pmr_emulation_p.h