GCC Code Coverage Report


Directory: avs_core/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 50.5% 147 / 0 / 291
Functions: 63.1% 41 / 0 / 65
Branches: 31.9% 60 / 0 / 188

core/AVSMap.h
Line Branch Exec Source
1 #pragma once
2 /*
3 This program is free software; you can redistribute it and /or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
10 GNU General Public License for more details.
11
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software
14 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
15
16 Helper structures for frame properties a.k.a VSMap.
17 Based on VapourSynth API4, copyright (c) Fredrik Mellbin
18
19 */
20 #include <map>
21 #include <mutex>
22 #include <string>
23 #include "avisynth.h"
24 #include <atomic>
25 #include <vector>
26 #include <memory>
27 #include <cassert>
28
29 // VS node ~ Avisynth clip, VSMap-AVSMap
30 // See also in Avisynth.cpp
31
32 // INTRUSIVE_PTR_H
33
34 #include <algorithm>
35
36 template<typename T>
37 class vs_intrusive_ptr {
38 private:
39 T* obj;
40 public:
41 1963 vs_intrusive_ptr(T* ptr = nullptr, bool add_ref = false) noexcept {
42 1963 obj = ptr;
43
2/8
vs_intrusive_ptr<VSArrayBase>::vs_intrusive_ptr(VSArrayBase*, bool):
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 5 taken 222 times.
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 5 not taken.
vs_intrusive_ptr<VSMapStorage>::vs_intrusive_ptr(VSMapStorage*, bool):
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 5 taken 1741 times.
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 5 not taken.
1963 if (add_ref && obj)
44 obj->add_ref();
45 1963 }
46
47 244 vs_intrusive_ptr(const vs_intrusive_ptr& ptr) noexcept {
48 244 obj = ptr.obj;
49
1/4
vs_intrusive_ptr<VSArrayBase>::vs_intrusive_ptr(vs_intrusive_ptr<VSArrayBase> const&):
✓ Branch 2 → 3 taken 244 times.
✗ Branch 2 → 4 not taken.
vs_intrusive_ptr<VSMapStorage>::vs_intrusive_ptr(vs_intrusive_ptr<VSMapStorage> const&):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
244 if (obj)
50 244 obj->add_ref();
51 244 }
52
53 vs_intrusive_ptr(vs_intrusive_ptr&& ptr) noexcept {
54 obj = ptr.obj;
55 ptr.obj = nullptr;
56 }
57
58 2207 ~vs_intrusive_ptr() noexcept {
59
2/4
vs_intrusive_ptr<VSArrayBase>::~vs_intrusive_ptr():
✓ Branch 2 → 3 taken 466 times.
✗ Branch 2 → 4 not taken.
vs_intrusive_ptr<VSMapStorage>::~vs_intrusive_ptr():
✓ Branch 2 → 3 taken 1741 times.
✗ Branch 2 → 4 not taken.
2207 if (obj)
60 2207 obj->release();
61 2207 }
62
63 801 vs_intrusive_ptr& operator=(vs_intrusive_ptr const& ptr) noexcept {
64
2/4
vs_intrusive_ptr<VSArrayBase>::operator=(vs_intrusive_ptr<VSArrayBase> const&):
✓ Branch 2 → 3 taken 19 times.
✗ Branch 2 → 4 not taken.
vs_intrusive_ptr<VSMapStorage>::operator=(vs_intrusive_ptr<VSMapStorage> const&):
✓ Branch 2 → 3 taken 782 times.
✗ Branch 2 → 4 not taken.
801 if (obj)
65 801 obj->release();
66 801 obj = ptr.obj;
67
2/4
vs_intrusive_ptr<VSArrayBase>::operator=(vs_intrusive_ptr<VSArrayBase> const&):
✓ Branch 4 → 5 taken 19 times.
✗ Branch 4 → 6 not taken.
vs_intrusive_ptr<VSMapStorage>::operator=(vs_intrusive_ptr<VSMapStorage> const&):
✓ Branch 4 → 5 taken 782 times.
✗ Branch 4 → 6 not taken.
801 if (obj)
68 801 obj->add_ref();
69 801 return *this;
70 }
71
72 2409 T* operator->() const noexcept {
73 2409 return obj;
74 }
75
76 115 T& operator*() const noexcept {
77 115 return *obj;
78 }
79
80 operator bool() const noexcept {
81 return !!obj;
82 }
83
84 282 T* get() const noexcept {
85 282 return obj;
86 }
87
88 void reset() noexcept {
89 if (obj) {
90 obj->release();
91 obj = nullptr;
92 }
93 }
94
95 void swap(vs_intrusive_ptr& ptr) noexcept {
96 std::swap(obj, ptr.obj);
97 }
98 };
99
100 #define AVS_NOEXCEPT noexcept
101
102 // enums for frame property functions
103
104 // VS: typedef enum VSPropertyType
105 typedef enum AVSPropertyType {
106 PROPERTYTYPE_UNSET = 0, // ptUnset = 0,
107 PROPERTYTYPE_INT = 1, // ptInt = 1,
108 PROPERTYTYPE_FLOAT = 2, // ptFloat = 2,
109 PROPERTYTYPE_DATA = 3, // ptData = 3,
110 // ptFunction = 4, // Avisynth: functions not supported here
111 PROPERTYTYPE_CLIP = 5, // ptVideoNode = 5,
112 // ptAudioNode = 6, // Avisynth: no special audio clip
113 PROPERTYTYPE_FRAME = 7, // ptVideoFrame = 7,
114 // ptAudioFrame = 8 // Avisynth: no special audio frame
115 } AVSPropertyType;
116
117 class VSArrayBase {
118 protected:
119 std::atomic<long> refcount;
120 AVSPropertyType ftype;
121 size_t fsize = 0;
122 222 explicit VSArrayBase(AVSPropertyType type) : refcount(1), ftype(type) {}
123 222 virtual ~VSArrayBase() {}
124 public:
125 153 AVSPropertyType type() const {
126 153 return ftype;
127 }
128
129 279 size_t size() const {
130 279 return fsize;
131 }
132
133 1 bool unique() const noexcept {
134 1 return (refcount == 1);
135 }
136
137 263 void add_ref() noexcept {
138 263 ++refcount;
139 263 }
140
141 485 void release() noexcept {
142
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 485 times.
485 assert(refcount > 0);
143
2/2
✓ Branch 6 → 7 taken 222 times.
✓ Branch 6 → 9 taken 263 times.
485 if (--refcount == 0)
144
1/2
✓ Branch 7 → 8 taken 222 times.
✗ Branch 7 → 9 not taken.
222 delete this;
145 485 }
146
147 virtual VSArrayBase* copy() const noexcept = 0;
148 };
149
150 typedef vs_intrusive_ptr<VSArrayBase> PVSArrayBase;
151
152 template<typename T, AVSPropertyType propType>
153 class VSArray final : public VSArrayBase {
154 private:
155 T singleData = {};
156 std::vector<T> data;
157 public:
158 222 explicit VSArray() noexcept : VSArrayBase(propType) {}
159
160 explicit VSArray(const VSArray& other) noexcept : VSArrayBase(other.ftype) {
161 fsize = other.fsize;
162 if (fsize == 1)
163 singleData = other.singleData;
164 else if (fsize > 1)
165 data = other.data;
166 }
167
168 explicit VSArray(const T* val, size_t count) noexcept : VSArrayBase(propType) { // only enable for POD types
169 fsize = count;
170 if (count == 1) {
171 singleData = *val;
172 }
173 else {
174 data.resize(count);
175 memcpy(data.data(), val, sizeof(T) * count);
176 }
177 }
178
179 virtual VSArrayBase* copy() const noexcept {
180 return new VSArray(*this);
181 }
182
183 const T* getDataPointer() const noexcept { // only enable for POD types
184 if (fsize == 1)
185 return &singleData;
186 else
187 return data.data();
188 }
189
190 223 void push_back(const T& val) noexcept {
191
3/10
VSArray<PVideoFrame, (AVSPropertyType)7>::push_back(PVideoFrame const&):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
VSArray<PClip, (AVSPropertyType)5>::push_back(PClip const&):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
VSArray<VSMapData, (AVSPropertyType)3>::push_back(VSMapData const&):
✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 4 taken 1 time.
VSArray<double, (AVSPropertyType)2>::push_back(double const&):
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
VSArray<long, (AVSPropertyType)1>::push_back(long const&):
✓ Branch 2 → 3 taken 221 times.
✗ Branch 2 → 4 not taken.
223 if (fsize == 0) {
192 222 singleData = val;
193 }
194
1/10
VSArray<PVideoFrame, (AVSPropertyType)7>::push_back(PVideoFrame const&):
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 10 not taken.
VSArray<PClip, (AVSPropertyType)5>::push_back(PClip const&):
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 10 not taken.
VSArray<VSMapData, (AVSPropertyType)3>::push_back(VSMapData const&):
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 10 not taken.
VSArray<double, (AVSPropertyType)2>::push_back(double const&):
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 10 not taken.
VSArray<long, (AVSPropertyType)1>::push_back(long const&):
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 10 not taken.
1 else if (fsize == 1) {
195 1 data.reserve(8);
196 2 data.push_back(std::move(singleData));
197 1 data.push_back(val);
198 }
199 else {
200 if (data.capacity() == data.size())
201 data.reserve(data.capacity() * 2);
202 data.push_back(val);
203 }
204 223 fsize++;
205 223 }
206
207 151 const T& at(size_t pos) const noexcept {
208
2/10
VSArray<PVideoFrame, (AVSPropertyType)7>::at(unsigned long) const:
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
VSArray<PClip, (AVSPropertyType)5>::at(unsigned long) const:
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
VSArray<VSMapData, (AVSPropertyType)3>::at(unsigned long) const:
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 1 time.
VSArray<double, (AVSPropertyType)2>::at(unsigned long) const:
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
VSArray<long, (AVSPropertyType)1>::at(unsigned long) const:
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 150 times.
151 assert(pos < fsize);
209
2/10
VSArray<PVideoFrame, (AVSPropertyType)7>::at(unsigned long) const:
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 6 not taken.
VSArray<PClip, (AVSPropertyType)5>::at(unsigned long) const:
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 6 not taken.
VSArray<VSMapData, (AVSPropertyType)3>::at(unsigned long) const:
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 1 time.
VSArray<double, (AVSPropertyType)2>::at(unsigned long) const:
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 6 not taken.
VSArray<long, (AVSPropertyType)1>::at(unsigned long) const:
✓ Branch 4 → 5 taken 150 times.
✗ Branch 4 → 6 not taken.
151 if (fsize == 1)
210 150 return singleData;
211 else
212 1 return data.at(pos);
213 }
214 };
215
216 // variant types
217 class VSMapData {
218 public:
219 AVSPropDataTypeHint typeHint;
220 std::string data;
221 };
222
223 typedef VSArray<int64_t, AVSPropertyType::PROPERTYTYPE_INT> VSIntArray; // ptInt
224 typedef VSArray<double, AVSPropertyType::PROPERTYTYPE_FLOAT> VSFloatArray; // ptFloat
225 typedef VSArray<VSMapData, AVSPropertyType::PROPERTYTYPE_DATA> VSDataArray; // ptData
226 typedef VSArray<PClip, AVSPropertyType::PROPERTYTYPE_CLIP> VSVideoNodeArray; // ptVideoNode
227 typedef VSArray<PVideoFrame, AVSPropertyType::PROPERTYTYPE_FRAME> VSVideoFrameArray; // ptVideoFrame
228 //typedef VSArray<PFunction, ptFunction> VSFunctionArray;
229
230
231 typedef std::vector<int64_t> IntList;
232 typedef std::vector<double> FloatList;
233 typedef std::vector<VSMapData> DataList;
234 typedef std::vector<PClip> ClipList;
235 typedef std::vector<PVideoFrame> FrameList;
236 //typedef std::vector<PFunction> FuncList;
237
238
239 class VSMapStorage {
240 private:
241 std::atomic<long> refcount;
242 public:
243 std::map<std::string, PVSArrayBase> data;
244 bool error;
245
246 1626 explicit VSMapStorage() : refcount(1), error(false) {}
247
248 115 explicit VSMapStorage(const VSMapStorage& s) : refcount(1), data(s.data), error(s.error) {
249 115 }
250
251 6 void clear() noexcept {
252 6 data.clear();
253 6 error = false;
254 6 }
255
256 344 bool unique() noexcept {
257 344 return (refcount == 1);
258 };
259
260 782 void add_ref() noexcept {
261 782 ++refcount;
262 782 }
263
264 2523 void release() noexcept {
265
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 2523 times.
2523 assert(refcount > 0);
266
2/2
✓ Branch 6 → 7 taken 1741 times.
✓ Branch 6 → 10 taken 782 times.
2523 if (--refcount == 0)
267
1/2
✓ Branch 7 → 8 taken 1741 times.
✗ Branch 7 → 10 not taken.
1741 delete this;
268 2523 }
269 };
270
271 typedef vs_intrusive_ptr<VSMapStorage> PVSMapStorage;
272
273 // This one is referenced in avisynth.h.
274 // For avoiding dual plugin name collisions, renamed VSMap->AVSMap
275 struct AVSMap {
276 private:
277 PVSMapStorage data;
278 public:
279
4/12
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 1583 times.
✓ Branch 4 → 5 taken 1583 times.
✗ Branch 4 → 11 not taken.
✓ Branch 7 → 8 taken 1583 times.
✗ Branch 7 → 10 not taken.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 1583 times.
✗ Branch 11 → 12 not taken.
✗ Branch 11 → 14 not taken.
✗ Branch 12 → 13 not taken.
✗ Branch 12 → 14 not taken.
1583 AVSMap(const AVSMap* map = nullptr) : data(map ? map->data : new VSMapStorage()) {
280 1583 }
281
282 624 AVSMap& operator=(const AVSMap& map) {
283 624 data = map.data;
284 624 return *this;
285 }
286
287 295 bool detach() {
288
2/2
✓ Branch 4 → 5 taken 115 times.
✓ Branch 4 → 14 taken 180 times.
295 if (!data->unique()) {
289
3/8
✓ Branch 5 → 6 taken 115 times.
✗ Branch 5 → 19 not taken.
✓ Branch 7 → 8 taken 115 times.
✗ Branch 7 → 16 not taken.
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 115 times.
✗ Branch 16 → 17 not taken.
✗ Branch 16 → 18 not taken.
115 data = new VSMapStorage(*data);
290 115 return true;
291 }
292 180 return false;
293 }
294
295 369 VSArrayBase* find(const std::string& key) const {
296
1/2
✓ Branch 3 → 4 taken 369 times.
✗ Branch 3 → 14 not taken.
369 auto it = data->data.find(key);
297
2/2
✓ Branch 7 → 8 taken 88 times.
✓ Branch 7 → 9 taken 281 times.
369 return (it == data->data.end()) ? nullptr : it->second.get();
298 }
299
300 1 VSArrayBase* detach(const std::string& key) {
301
1/2
✓ Branch 2 → 3 taken 1 time.
✗ Branch 2 → 26 not taken.
1 detach();
302
1/2
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 26 not taken.
1 auto it = data->data.find(key);
303
1/2
✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 23 not taken.
1 if (it != data->data.end()) {
304
1/2
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 21 taken 1 time.
1 if (!it->second->unique())
305 it->second = it->second->copy();
306 1 return it->second.get();
307 }
308 return nullptr;
309 }
310
311 122 bool erase(const std::string& key) {
312
1/2
✓ Branch 3 → 4 taken 122 times.
✗ Branch 3 → 18 not taken.
122 auto it = data->data.find(key);
313
2/2
✓ Branch 7 → 8 taken 72 times.
✓ Branch 7 → 15 taken 50 times.
122 if (it != data->data.end()) {
314
3/4
✓ Branch 8 → 9 taken 72 times.
✗ Branch 8 → 18 not taken.
✓ Branch 9 → 10 taken 70 times.
✓ Branch 9 → 12 taken 2 times.
72 if (detach())
315
1/2
✓ Branch 11 → 12 taken 70 times.
✗ Branch 11 → 18 not taken.
70 it = data->data.find(key);
316
1/2
✓ Branch 13 → 14 taken 72 times.
✗ Branch 13 → 18 not taken.
72 data->data.erase(it);
317 72 return true;
318 }
319 50 return false;
320 }
321
322 222 void insert(const std::string& key, VSArrayBase* val) {
323
1/2
✓ Branch 2 → 3 taken 222 times.
✗ Branch 2 → 23 not taken.
222 detach();
324
1/2
✓ Branch 4 → 5 taken 222 times.
✗ Branch 4 → 23 not taken.
222 auto it = data->data.find(key);
325
2/2
✓ Branch 8 → 9 taken 19 times.
✓ Branch 8 → 14 taken 203 times.
222 if (it != data->data.end()) {
326 19 it->second = val;
327 }
328 else {
329
2/4
✓ Branch 15 → 16 taken 203 times.
✗ Branch 15 → 22 not taken.
✓ Branch 16 → 17 taken 203 times.
✗ Branch 16 → 20 not taken.
203 data->data.insert(std::make_pair(key, val));
330 }
331 222 }
332
333 void copy(const AVSMap* src) {
334 if (src == this)
335 return;
336
337 detach();
338 for (auto& iter : src->data->data)
339 data->data[iter.first] = iter.second;
340 }
341
342 133 size_t size() const {
343 133 return data->data.size();
344 }
345
346 49 void clear() {
347
2/2
✓ Branch 4 → 5 taken 6 times.
✓ Branch 4 → 7 taken 43 times.
49 if (data->unique())
348 6 data->clear();
349 else
350
2/4
✓ Branch 7 → 8 taken 43 times.
✗ Branch 7 → 16 not taken.
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 43 times.
43 data = new VSMapStorage();
351 49 }
352
353 1 const char* key(size_t n) const {
354
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 1 time.
1 if (n >= size())
355 return nullptr;
356 1 auto iter = data->data.cbegin();
357 std::advance(iter, n);
358 1 return iter->first.c_str();
359 }
360
361 void setError(const std::string& errMsg) {
362 clear();
363 VSDataArray* arr = new VSDataArray();
364 arr->push_back({ AVSPropDataTypeHint::PROPDATATYPEHINT_UTF8, errMsg }); // dtUtf8
365 data->data.insert(std::make_pair("_Error", arr));
366 data->error = true;
367 }
368
369 151 bool hasError() const {
370 151 return data->error;
371 }
372
373 const char* getErrorMessage() const {
374 if (data->error) {
375 return reinterpret_cast<VSDataArray*>(data->data.at("_Error").get())->at(0).data.c_str();
376 }
377 else {
378 return nullptr;
379 }
380 }
381
382 //bool isV3Compatible() const noexcept; // VS special
383 };
384