Krita Source Code Documentation
Loading...
Searching...
No Matches
KisOptimizedByteArray.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2017 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
8
9#include <QGlobalStatic>
10#include <QMutexLocker>
11
12#include <string.h>
13
14namespace {
15
16/*****************************************************************/
17/* DefaultMemoryAllocator */
18/*****************************************************************/
19
20struct DefaultMemoryAllocator : KisOptimizedByteArray::MemoryAllocator
21{
22 KisOptimizedByteArray::MemoryChunk alloc(int size) override {
23 return KisOptimizedByteArray::MemoryChunk(new quint8[size], size);
24 }
25
26 void free(KisOptimizedByteArray::MemoryChunk chunk) override {
27 // chunk.first might be null
28 delete[] chunk.first;
29 }
30};
31
32
33/*****************************************************************/
34/* DefaultMemoryAllocatorStore */
35/*****************************************************************/
36
37struct DefaultMemoryAllocatorStore {
38 static DefaultMemoryAllocatorStore* instance();
39
40 DefaultMemoryAllocatorStore()
41 : m_allocator(new DefaultMemoryAllocator())
42 {
43 }
44
45 inline KisOptimizedByteArray::MemoryAllocatorSP allocator() const {
46 return m_allocator;
47 }
48
49private:
51};
52
53Q_GLOBAL_STATIC(DefaultMemoryAllocatorStore, s_instance)
54
55DefaultMemoryAllocatorStore *DefaultMemoryAllocatorStore::instance()
56{
57 return s_instance;
58}
59
60} // namespace
61
62
63/*****************************************************************/
64/* KisOptimizedByteArray::PooledMemoryAllocator */
65/*****************************************************************/
66
71
73{
74 Q_FOREACH (const MemoryChunk &chunk, m_chunks) {
75 delete[] chunk.first;
76 }
77}
78
81{
82 MemoryChunk chunk;
83
84 {
85 QMutexLocker l(&m_mutex);
86 if (!m_chunks.isEmpty()) {
87 chunk = m_chunks.takeLast();
88 }
89
90 m_meanSize(size);
91 }
92
93 if (chunk.second < size) {
94 delete[] chunk.first;
95
96 // we alloc a bit more memory for the dabs to let the chunks
97 // be more reusable
98 const int allocSize = 1.2 * size;
99 chunk = KisOptimizedByteArray::MemoryChunk(new quint8[allocSize], allocSize);
100 }
101
102 return chunk;
103}
104
106{
107 if (chunk.first) {
108 QMutexLocker l(&m_mutex);
109
110 // keep bigger chunks for ourselves and return the
111 // smaller ones to the system
112 if (chunk.second > 0.8 * m_meanSize.rollingMean()) {
113 m_chunks.append(chunk);
114 } else {
115 delete[] chunk.first;
116 }
117 }
118}
119
120
121/*****************************************************************/
122/* KisOptimizedByteArray::Private */
123/*****************************************************************/
124
125struct KisOptimizedByteArray::Private : public QSharedData
126{
128 {
130 _allocator ? _allocator : DefaultMemoryAllocatorStore::instance()->allocator();
131
132 allocator = storedAllocator.data();
133 }
134
135 Private(const Private &rhs)
136 : QSharedData(rhs)
137 {
138 allocator = rhs.allocator;
140 dataSize = rhs.dataSize;
141 if (dataSize) {
143 memcpy(data.first, rhs.data.first, dataSize);
144 }
145 }
146
149 }
150
152
153 // stored allocator shared pointer is used only for keeping
154 // the lifetime of the allocator until the detach of the last
155 // allocated chunk
157
159 int dataSize = 0;
160};
161
162
163/*****************************************************************/
164/* KisOptimizedByteArray */
165/*****************************************************************/
166
171
176
178{
179 m_d = rhs.m_d;
180 return *this;
181}
182
186
188{
189 return const_cast<Private*>(m_d.data())->data.first;
190}
191
193{
194 return const_cast<const Private*>(m_d.constData())->data.first;
195}
196
198{
199 if (size == m_d->dataSize) return;
200
201 if (size > m_d->data.second) {
202 m_d->allocator->free(m_d->data);
203 m_d->data = m_d->allocator->alloc(size);
204 }
205 m_d->dataSize = size;
206}
207
208void KisOptimizedByteArray::fill(quint8 value, int size)
209{
210 resize(size);
211 memset(m_d->data.first, value, m_d->dataSize);
212}
213
215{
216 return m_d->dataSize;
217}
218
220{
221 return !m_d->dataSize;
222}
223
228
float value(const T *src, size_t ch)
Q_GLOBAL_STATIC(KisStoragePluginRegistry, s_instance)
PythonPluginManager * instance
std::pair< quint8 *, int > MemoryChunk
const quint8 * constData() const
QSharedDataPointer< Private > m_d
KisOptimizedByteArray & operator=(const KisOptimizedByteArray &rhs)
KisOptimizedByteArray(MemoryAllocatorSP allocator=MemoryAllocatorSP())
void fill(quint8 value, int size=-1)
MemoryAllocatorSP customMemoryAllocator() const
virtual void free(MemoryChunk chunk)=0
virtual MemoryChunk alloc(int size)=0
Private(MemoryAllocatorSP _allocator)