Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
Loading...
Searching...
No Matches
qfreelist_p.h
Go to the documentation of this file.
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
// Qt-Security score:significant reason:default
4
5
#
ifndef
QFREELIST_P_H
6
#
define
QFREELIST_P_H
7
8
//
9
// W A R N I N G
10
// -------------
11
//
12
// This file is not part of the Qt API. It exists purely as an
13
// implementation detail. This header file may change from version to
14
// version without notice, or even be removed.
15
//
16
// We mean it.
17
//
18
19
#
include
<
QtCore
/
private
/
qglobal_p
.
h
>
20
21
#
include
<
QtCore
/
q20atomic
.
h
>
22
23
QT_BEGIN_NAMESPACE
24
25
/*! \internal
26
27
Element in a QFreeList. ConstReferenceType and ReferenceType are used as
28
the return values for QFreeList::at() and QFreeList::operator[](). Contains
29
the real data storage (_t) and the id of the next free element (next).
30
31
Note: the t() functions should be used to access the data, not _t.
32
*/
33
template
<
typename
T>
34
struct
QFreeListElement
35
{
36
typedef
const
T &ConstReferenceType;
37
typedef
T &ReferenceType;
38
39
T _t;
40
q20::atomic<
int
> next;
41
42
inline
ConstReferenceType t()
const
{
return
_t; }
43
inline
ReferenceType t() {
return
_t; }
44
};
45
46
/*! \internal
47
48
Element in a QFreeList without a payload. ConstReferenceType and
49
ReferenceType are void, the t() functions return void and are empty.
50
*/
51
template
<>
52
struct
QFreeListElement
<
void
>
53
{
54
typedef
void
ConstReferenceType
;
55
typedef
void
ReferenceType
;
56
57
q20
::
atomic
<
int
>
next
;
58
59
inline
void
t
()
const
{ }
60
inline
void
t
() { }
61
};
62
63
/*! \internal
64
65
Defines default constants used by QFreeList:
66
67
- The initial value returned by QFreeList::next() is zero.
68
69
- QFreeList allows for up to 16777216 elements in QFreeList and uses the top
70
8 bits to store a serial counter for ABA protection.
71
72
- QFreeList will make a maximum of 4 allocations (blocks), with each
73
successive block larger than the previous.
74
75
- Sizes static int[] array to define the size of each block.
76
77
It is possible to define your own constants struct/class and give this to
78
QFreeList to customize/tune the behavior.
79
*/
80
struct
Q_AUTOTEST_EXPORT
QFreeListDefaultConstants
81
{
82
// used by QFreeList, make sure to define all of when customizing
83
enum
{
84
InitialNextValue = 0,
85
IndexMask = 0x00ffffff,
86
SerialMask = ~IndexMask & ~0x80000000,
87
SerialCounter = IndexMask + 1,
88
MaxIndex = IndexMask,
89
BlockCount = 4
90
};
91
92
static
const
int
Sizes[BlockCount];
93
};
94
95
/*! \internal
96
97
This is a generic implementation of a lock-free free list. Use next() to
98
get the next free entry in the list, and release(id) when done with the id.
99
100
This version is templated and allows having a payload of type T which can
101
be accessed using the id returned by next(). The payload is allocated and
102
deallocated automatically by the free list, but *NOT* when calling
103
next()/release(). Initialization should be done by code needing it after
104
next() returns. Likewise, cleanup() should happen before calling release().
105
It is possible to have use 'void' as the payload type, in which case the
106
free list only contains indexes to the next free entry.
107
108
The ConstantsType type defaults to QFreeListDefaultConstants above. You can
109
define your custom ConstantsType, see above for details on what needs to be
110
available.
111
*/
112
template
<
typename
T,
typename
ConstantsType = QFreeListDefaultConstants>
113
class
QFreeList
114
{
115
typedef
T ValueType;
116
typedef
QFreeListElement
<
T
>
ElementType
;
117
typedef
typename
ElementType::ConstReferenceType ConstReferenceType;
118
typedef
typename
ElementType::ReferenceType ReferenceType;
119
120
// return which block the index \a x falls in, and modify \a x to be the index into that block
121
static
inline
int
blockfor(
int
&x)
122
{
123
x = x & ConstantsType::IndexMask;
124
for
(
int
i = 0; i < ConstantsType::BlockCount; ++i) {
125
int
size = ConstantsType::Sizes[i];
126
if
(x < size)
127
return
i;
128
x -= size;
129
}
130
Q_UNREACHABLE_RETURN(-1);
131
}
132
133
// allocate a block of the given \a size, initialized starting with the given \a offset
134
static
inline
ElementType *allocate(
int
offset,
int
size)
135
{
136
// qDebug("QFreeList: allocating %d elements (%ld bytes) with offset %d", size, size * sizeof(ElementType), offset);
137
ElementType *v =
new
ElementType[size];
138
for
(
int
i = 0; i < size; ++i)
139
v[i].next.store(offset + i + 1, std::memory_order_relaxed);
140
return
v;
141
}
142
143
// take the current serial number from \a o, increment it, and store it in \a n
144
static
inline
int
incrementserial(
int
o,
int
n)
145
{
146
return
int
((uint(n) & ConstantsType::IndexMask) | ((uint(o) + ConstantsType::SerialCounter) & ConstantsType::SerialMask));
147
}
148
149
// the blocks
150
q20::atomic<ElementType *> _v[ConstantsType::BlockCount];
151
// the next free id
152
q20::atomic<
int
> _next;
153
154
// QFreeList is not copyable
155
Q_DISABLE_COPY_MOVE
(
QFreeList
)
156
157
public
:
158
constexpr
inline
QFreeList
();
159
inline
~
QFreeList
();
160
161
// returns the payload for the given index \a x
162
inline
ConstReferenceType
at
(
int
x)
const
;
163
inline
ReferenceType
operator
[](
int
x);
164
165
/*
166
Return the next free id. Use this id to access the payload (see above).
167
Call release(id) when done using the id.
168
*/
169
inline
int
next
();
170
inline
void
release
(
int
id);
171
};
172
173
template
<
typename
T,
typename
ConstantsType>
174
constexpr
inline
QFreeList
<T, ConstantsType>::QFreeList()
175
:
176
_v{},
// uniform initialization required
177
_next(ConstantsType::InitialNextValue)
178
{ }
179
180
template
<
typename
T,
typename
ConstantsType>
181
inline
QFreeList
<T, ConstantsType>::~
QFreeList
()
182
{
183
for
(
int
i = 0; i < ConstantsType::BlockCount; ++i)
184
delete
[] _v[i].load(std::memory_order_acquire);
185
}
186
187
template
<
typename
T,
typename
ConstantsType>
188
inline
typename
QFreeList
<T, ConstantsType>::ConstReferenceType
QFreeList
<T, ConstantsType>::
at
(
int
x)
const
189
{
190
const
int
block = blockfor(x);
191
return
(_v[block].load(std::memory_order_relaxed))[x].t();
192
}
193
194
template
<
typename
T,
typename
ConstantsType>
195
inline
typename
QFreeList
<T, ConstantsType>::ReferenceType
QFreeList
<T, ConstantsType>::
operator
[](
int
x)
196
{
197
const
int
block = blockfor(x);
198
return
(_v[block].load(std::memory_order_relaxed))[x].t();
199
}
200
201
template
<
typename
T,
typename
ConstantsType>
202
inline
int
QFreeList
<T, ConstantsType>::
next
()
203
{
204
int
newid;
205
int
id = _next.load(std::memory_order_acquire);
206
do
{
207
int
at = id & ConstantsType::IndexMask;
208
const
int
block = blockfor(at);
209
ElementType *v = _v[block].load(std::memory_order_acquire);
210
211
if
(!v) {
212
ElementType*
const
alloced = allocate((id & ConstantsType::IndexMask) - at,
213
ConstantsType::Sizes[block]);
214
if
(_v[block].compare_exchange_strong(v, alloced, std::memory_order_release, std::memory_order_acquire)) {
215
v = alloced;
216
}
else
{
217
// race with another thread lost
218
delete
[] alloced;
219
Q_ASSERT(v !=
nullptr
);
220
}
221
}
222
223
newid = v[at].next.load(std::memory_order_relaxed) | (id & ~ConstantsType::IndexMask);
224
}
while
(!_next.compare_exchange_strong(id, newid, std::memory_order_release, std::memory_order_acquire));
225
// qDebug("QFreeList::next(): returning %d (_next now %d, serial %d)",
226
// id & ConstantsType::IndexMask,
227
// newid & ConstantsType::IndexMask,
228
// (newid & ~ConstantsType::IndexMask) >> 24);
229
return
id;
230
}
231
232
template
<
typename
T,
typename
ConstantsType>
233
inline
void
QFreeList
<T, ConstantsType>::
release
(
int
id)
234
{
235
int
at = id & ConstantsType::IndexMask;
236
const
int
block = blockfor(at);
237
ElementType *v = _v[block].load(std::memory_order_acquire);
238
239
int
x, newid;
240
do
{
241
x = _next.load(std::memory_order_acquire);
242
v[at].next.store(x & ConstantsType::IndexMask, std::memory_order_relaxed);
243
244
newid = incrementserial(x, id);
245
}
while
(!_next.compare_exchange_weak(x, newid, std::memory_order_release));
246
// qDebug("QFreeList::release(%d): _next now %d (was %d), serial %d",
247
// id & ConstantsType::IndexMask,
248
// newid & ConstantsType::IndexMask,
249
// x & ConstantsType::IndexMask,
250
// (newid & ~ConstantsType::IndexMask) >> 24);
251
}
252
253
QT_END_NAMESPACE
254
255
#
endif
// QFREELIST_P_H
QFreeList
Definition
qfreelist_p.h:114
QFreeList::operator[]
ReferenceType operator[](int x)
Definition
qfreelist_p.h:195
QFreeList::at
ConstReferenceType at(int x) const
Definition
qfreelist_p.h:188
QFreeList::next
int next()
Definition
qfreelist_p.h:202
QFreeList::~QFreeList
~QFreeList()
Definition
qfreelist_p.h:181
QFreeList::release
void release(int id)
Definition
qfreelist_p.h:233
QFreeListDefaultConstantsPrivate
Definition
qfreelist.cpp:10
QFreeListDefaultConstantsPrivate::Size2
@ Size2
Definition
qfreelist.cpp:19
QFreeListDefaultConstantsPrivate::Offset1
@ Offset1
Definition
qfreelist.cpp:13
QFreeListDefaultConstantsPrivate::Size0
@ Size0
Definition
qfreelist.cpp:17
QFreeListDefaultConstantsPrivate::Offset0
@ Offset0
Definition
qfreelist.cpp:12
QFreeListDefaultConstantsPrivate::Offset2
@ Offset2
Definition
qfreelist.cpp:14
QFreeListDefaultConstantsPrivate::Offset3
@ Offset3
Definition
qfreelist.cpp:15
QFreeListDefaultConstantsPrivate::Size3
@ Size3
Definition
qfreelist.cpp:20
QFreeListDefaultConstantsPrivate::Size1
@ Size1
Definition
qfreelist.cpp:18
QT_BEGIN_NAMESPACE
Combined button and popup list for selecting options.
Definition
qsequentialanimationgroup.cpp:47
QFreeListDefaultConstants
Definition
qfreelist_p.h:81
QFreeListElement< void >
Definition
qfreelist_p.h:53
QFreeListElement< void >::ReferenceType
void ReferenceType
Definition
qfreelist_p.h:55
QFreeListElement< void >::t
void t() const
Definition
qfreelist_p.h:59
QFreeListElement< void >::ConstReferenceType
void ConstReferenceType
Definition
qfreelist_p.h:54
QFreeListElement< void >::next
q20::atomic< int > next
Definition
qfreelist_p.h:57
QFreeListElement< void >::t
void t()
Definition
qfreelist_p.h:60
qtbase
src
corelib
tools
qfreelist_p.h
Generated on
for Qt by
1.18.0