Audacity 3.2.0
GraphicsDataCache.h
Go to the documentation of this file.
1/* SPDX-License-Identifier: GPL-2.0-or-later */
2/*!********************************************************************
3
4 Audacity: A Digital Audio Editor
5
6 GraphicsDataCache.h
7
8 Dmitry Vedenko
9
10**********************************************************************/
11#pragma once
12
13#include <cstdint>
14#include <deque>
15#include <functional>
16#include <mutex>
17#include <type_traits>
18#include <vector>
19
20#include "MemoryX.h"
21#include "IteratorX.h"
22
23class ZoomInfo;
24
26struct WAVE_TRACK_PAINT_API GraphicsDataCacheKey final
27{
29 double PixelsPerSecond { 0.0 };
31 int64_t FirstSample { -1 };
32};
33
35struct WAVE_TRACK_PAINT_API GraphicsDataCacheElementBase /* not final */
36{
37 virtual ~GraphicsDataCacheElementBase() = default;
39 virtual void Dispose();
41 virtual void Smooth(GraphicsDataCacheElementBase* prevElement);
42
44 uint64_t LastCacheAccess { 0 };
46 uint64_t LastUpdate { 0 };
48 bool IsComplete { false };
50 bool AwaitsEviction { false };
51};
52
54class WAVE_TRACK_PAINT_API GraphicsDataCacheBase /* not final */
55{
56public:
57 // Number of pixels in a single cache element
58 constexpr static uint32_t CacheElementWidth = 256;
59
60 virtual ~GraphicsDataCacheBase() = default;
61
63 void Invalidate();
64
66 double GetScaledSampleRate() const noexcept;
67
68 void UpdateViewportWidth(int64_t width) noexcept;
69 int64_t GetMaxViewportWidth() const noexcept;
70
71protected:
72 explicit GraphicsDataCacheBase(double scaledSampleRate);
73
74 void SetScaledSampleRate(double scaledSampleRate);
75
77 struct WAVE_TRACK_PAINT_API LookupElement final
78 {
81 };
83 using Lookup = std::vector<LookupElement>;
84
86 struct WAVE_TRACK_PAINT_API BaseLookupResult final
87 {
89 Lookup::iterator Begin;
91 Lookup::iterator End;
93 size_t LeftOffset {};
95 size_t RightOffset {};
96 };
101
103 virtual bool UpdateElement(
105
107 BaseLookupResult PerformBaseLookup(const ZoomInfo& zoomInfo, double t0, double t1);
108
110 const GraphicsDataCacheElementBase* PerformBaseLookup(GraphicsDataCacheKey key);
111
112private:
113 // Called internally to create a list of items in the mNewLookupItems
114 bool CreateNewItems();
115 // Called internally if the CreateNewItems has failed to dispose all the elements created
116 void DisposeNewItems();
117 Lookup::iterator FindKey(GraphicsDataCacheKey key);
118
119 // Called internally to evict the no longer needed items. Cache keeps mCacheSizeMultiplier * mMaxWidth / CacheElementWidth items
120 void PerformCleanup();
121 // A heap based approach if cache needs to evict more than one item
122 void PerformFullCleanup(int64_t currentSize, int64_t itemsToEvict);
123 // This vector is sorted according to the key
125 // This vector is used to avoid memory allocations when growing the cache
127 // This is a helper vector to store newly created items before they are inserted in cache
129 // This is a helper vector to implement the heap structure for the LRU policy
130 std::vector<size_t> mLRUHelper;
131
132 // Sample rate associated with this cache
133 double mScaledSampleRate {}; // DV: Why do we use double for sample rate? I don't know
134
135 // The max width of the request processed in pixels
136 int64_t mMaxWidth { 1600 };
137 // This value is incremented on every lookup
138 uint64_t mCacheAccessIndex {};
139 // A multiplier used to control the cache size
140 int32_t mCacheSizeMultiplier { 4 };
141
142 template <typename CacheElementType>
144};
145
147template <typename CacheElementType>
149{
150public:
151 using iterator_category = std::forward_iterator_tag;
152 using difference_type = std::ptrdiff_t;
153 using value_type = CacheElementType;
156
162
164 {
165 return static_cast<reference>(*mIterator->Data);
166 }
168 {
169 return static_cast<pointer>(mIterator->Data);
170 }
171
172 // Prefix increment
174 {
175 mIterator++;
176 return *this;
177 }
178
179 // Postfix increment
181 {
182 GraphicsDataCacheIterator tmp = *this;
183 ++(*this);
184 return tmp;
185 }
186
187 size_t GetLeftOffset() const
188 {
190 }
191
192 size_t GetRightOffset() const
193 {
194 auto next = mIterator;
195 ++next;
196
197 return next == mBaseLookup.End ? mBaseLookup.RightOffset : 0;
198 }
199
200 friend bool operator==(
201 const GraphicsDataCacheIterator& lhs,
202 const GraphicsDataCacheIterator& rhs)
203 {
204 return lhs.mIterator == rhs.mIterator;
205 };
206
207 friend bool operator!=(
208 const GraphicsDataCacheIterator& lhs,
209 const GraphicsDataCacheIterator& rhs)
210 {
211 return lhs.mIterator != rhs.mIterator;
212 };
213
214private:
217 : mBaseLookup(base)
218 , mIterator(begin ? base.Begin : base.End)
219 {
220 }
221
223 GraphicsDataCacheBase::Lookup::const_iterator mIterator;
224
225 template <typename T>
226 friend class GraphicsDataCache;
227};
228
229
230template<typename CacheElementType>
231class GraphicsDataCache /* not final */ : public GraphicsDataCacheBase
232{
233public:
234 using ElementFactory = std::function<std::unique_ptr<CacheElementType>()>;
235
238
239 using Initializer = std::function<bool(const GraphicsDataCacheKey& Key, CacheElementType& element)>;
240
241 explicit GraphicsDataCache(double scaledSampleRate, ElementFactory elementFactory)
242 : GraphicsDataCacheBase(scaledSampleRate), mElementFactory(std::move(elementFactory))
243 {
244 }
245
247 {
248 Invalidate();
249 }
250
252 PerformLookup(const ZoomInfo& zoomInfo, double t0, double t1)
253 {
254 CheckCache(zoomInfo, t0, t1);
255
256 const auto base = this->PerformBaseLookup(zoomInfo, t0, t1);
257
258 return { { base, true }, { base, false } };
259 }
260
261 const CacheElementType* PerformLookup(GraphicsDataCacheKey key)
262 {
263 return static_cast<const CacheElementType*>(PerformBaseLookup(key));
264 }
265
267 {
268 mInitializer = std::move(initializer);
269 }
270
271protected:
272 virtual void
273 CheckCache(const ZoomInfo& /*zoomInfo*/, double /*t0*/, double /*t1*/)
274 {
275 }
276
277 virtual bool
278 InitializeElement(const GraphicsDataCacheKey& key, CacheElementType& element)
279 {
280 if constexpr (std::is_assignable_v<
281 CacheElementType, GraphicsDataCacheKey>)
282 {
283 element = key;
284 return true;
285 }
286 else if constexpr (std::is_constructible_v<
287 CacheElementType, GraphicsDataCacheKey>)
288 {
289 element = CacheElementType(key);
290 return true;
291 }
292 else
293 {
294 return false;
295 }
296 }
297
298private:
300 {
301 CacheElementType* element = nullptr;
302
303 if (!mFreeList.empty())
304 {
305 element = mFreeList.back();
306 mFreeList.pop_back();
307 }
308
309 if (element == nullptr)
310 {
311 mCache.push_back(std::move(mElementFactory()));
312 element = mCache.back().get();
313 }
314
315 if (element == nullptr)
316 return nullptr;
317
318 if (mInitializer)
319 {
320 if (!mInitializer(key, *element))
321 {
322 DisposeElement(element);
323 return nullptr;
324 }
325 }
326 else if (!InitializeElement(key, *element))
327 {
328 DisposeElement(element);
329 return nullptr;
330 }
331
332 return element;
333 }
334
336 {
337 if (element == nullptr)
338 return;
339
340 element->Dispose();
341
342 mFreeList.push_back(static_cast<CacheElementType*>(element));
343 }
344
347 GraphicsDataCacheElementBase& element) override
348 {
349 return InitializeElement(key, static_cast<CacheElementType&>(element));
350 }
351
353
355 std::deque<std::unique_ptr<CacheElementType>> mCache;
356 std::vector<CacheElementType*> mFreeList;
357};
static const AudacityProject::AttachedObjects::RegisteredFactory key
A base class for the GraphicsDataCache. Implements LRU policy.
virtual ~GraphicsDataCacheBase()=default
std::vector< size_t > mLRUHelper
virtual void DisposeElement(GraphicsDataCacheElementBase *element)=0
This method is called, when the cache element should be evicted. Implementation may not deallocate th...
virtual bool UpdateElement(const GraphicsDataCacheKey &key, GraphicsDataCacheElementBase &element)=0
This method is called on all elements matching the request that are not complete (i....
BaseLookupResult PerformBaseLookup(const ZoomInfo &zoomInfo, double t0, double t1)
Perform a lookup inside the cache. This method modifies mLookup and invalidates any previous result.
void Invalidate()
Invalidate the cache content.
virtual GraphicsDataCacheElementBase * CreateElement(const GraphicsDataCacheKey &key)=0
Create a new Cache element. Implementation is responsible of the lifetime control.
std::vector< LookupElement > Lookup
Cache lookup is a vector, with items sorted using Key.
~GraphicsDataCache() override
IteratorRange< GraphicsDataCacheIterator< CacheElementType > > PerformLookup(const ZoomInfo &zoomInfo, double t0, double t1)
const CacheElementType * PerformLookup(GraphicsDataCacheKey key)
GraphicsDataCache(const GraphicsDataCache &)=delete
std::vector< CacheElementType * > mFreeList
std::function< std::unique_ptr< CacheElementType >()> ElementFactory
void setInitializer(Initializer initializer)
GraphicsDataCache(double scaledSampleRate, ElementFactory elementFactory)
GraphicsDataCache & operator=(const GraphicsDataCache &)=delete
GraphicsDataCacheElementBase * CreateElement(const GraphicsDataCacheKey &key) override
Create a new Cache element. Implementation is responsible of the lifetime control.
virtual void CheckCache(const ZoomInfo &, double, double)
void DisposeElement(GraphicsDataCacheElementBase *element) override
This method is called, when the cache element should be evicted. Implementation may not deallocate th...
std::deque< std::unique_ptr< CacheElementType > > mCache
virtual bool InitializeElement(const GraphicsDataCacheKey &key, CacheElementType &element)
std::function< bool(const GraphicsDataCacheKey &Key, CacheElementType &element)> Initializer
bool UpdateElement(const GraphicsDataCacheKey &key, GraphicsDataCacheElementBase &element) override
This method is called on all elements matching the request that are not complete (i....
ElementFactory mElementFactory
Initializer mInitializer
A class that implements an iterator for the cache lookup result.
GraphicsDataCacheIterator()=default
GraphicsDataCacheIterator & operator=(const GraphicsDataCacheIterator &)=default
GraphicsDataCacheIterator(GraphicsDataCacheIterator &&)=default
GraphicsDataCacheIterator operator++(int)
GraphicsDataCacheIterator(const GraphicsDataCacheBase::BaseLookupResult &base, bool begin)
friend bool operator!=(const GraphicsDataCacheIterator &lhs, const GraphicsDataCacheIterator &rhs)
friend bool operator==(const GraphicsDataCacheIterator &lhs, const GraphicsDataCacheIterator &rhs)
GraphicsDataCacheBase::BaseLookupResult mBaseLookup
GraphicsDataCacheIterator & operator=(GraphicsDataCacheIterator &&)=default
GraphicsDataCacheIterator & operator++()
std::forward_iterator_tag iterator_category
GraphicsDataCacheIterator(const GraphicsDataCacheIterator &)=default
GraphicsDataCacheBase::Lookup::const_iterator mIterator
bool Begin(const FilePath &dataDir)
Definition: Journal.cpp:226
const char * begin(const char *str) noexcept
Definition: StringUtils.h:101
STL namespace.
A result of the cache lookup.
size_t RightOffset
Offset from the right for the last element that matches the request.
Lookup::iterator Begin
Iterator to the first cache element that fulfills the request.
size_t LeftOffset
First column of the first element that matches the request.
Lookup::iterator End
Iterator past the last cache element that fulfills the request.
Element of the cache lookup.
A base class for the for cache elements.
virtual void Dispose()
This method is called when the item is evicted from the cache. Default implementation is empty.
virtual ~GraphicsDataCacheElementBase()=default
A key into the graphics data cache.
A convenience for use with range-for.
Definition: IteratorX.h:39