GCC Code Coverage Report


Directory: avs_core/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 50.2% 146 / 0 / 291
Functions: 63.1% 41 / 0 / 65
Branches: 30.9% 58 / 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 1073 vs_intrusive_ptr(T* ptr = nullptr, bool add_ref = false) noexcept {
42 1073 obj = ptr;
43
2/8
vs_intrusive_ptr<VSArrayBase>::vs_intrusive_ptr(VSArrayBase*, bool):
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 5 taken 81 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 992 times.
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 5 not taken.
1073 if (add_ref && obj)
44 obj->add_ref();
45 1073 }
46
47 10 vs_intrusive_ptr(const vs_intrusive_ptr& ptr) noexcept {
48 10 obj = ptr.obj;
49
1/4
vs_intrusive_ptr<VSArrayBase>::vs_intrusive_ptr(vs_intrusive_ptr<VSArrayBase> const&):
✓ Branch 2 → 3 taken 10 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.
10 if (obj)
50 10 obj->add_ref();
51 10 }
52
53 vs_intrusive_ptr(vs_intrusive_ptr&& ptr) noexcept {
54 obj = ptr.obj;
55 ptr.obj = nullptr;
56 }
57
58 1083 ~vs_intrusive_ptr() noexcept {
59
2/4
vs_intrusive_ptr<VSArrayBase>::~vs_intrusive_ptr():
✓ Branch 2 → 3 taken 91 times.
✗ Branch 2 → 4 not taken.
vs_intrusive_ptr<VSMapStorage>::~vs_intrusive_ptr():
✓ Branch 2 → 3 taken 992 times.
✗ Branch 2 → 4 not taken.
1083 if (obj)
60 1083 obj->release();
61 1083 }
62
63 328 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 15 times.
✗ Branch 2 → 4 not taken.
vs_intrusive_ptr<VSMapStorage>::operator=(vs_intrusive_ptr<VSMapStorage> const&):
✓ Branch 2 → 3 taken 313 times.
✗ Branch 2 → 4 not taken.
328 if (obj)
65 328 obj->release();
66 328 obj = ptr.obj;
67
2/4
vs_intrusive_ptr<VSArrayBase>::operator=(vs_intrusive_ptr<VSArrayBase> const&):
✓ Branch 4 → 5 taken 15 times.
✗ Branch 4 → 6 not taken.
vs_intrusive_ptr<VSMapStorage>::operator=(vs_intrusive_ptr<VSMapStorage> const&):
✓ Branch 4 → 5 taken 313 times.
✗ Branch 4 → 6 not taken.
328 if (obj)
68 328 obj->add_ref();
69 328 return *this;
70 }
71
72 736 T* operator->() const noexcept {
73 736 return obj;
74 }
75
76 27 T& operator*() const noexcept {
77 27 return *obj;
78 }
79
80 operator bool() const noexcept {
81 return !!obj;
82 }
83
84 74 T* get() const noexcept {
85 74 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 81 explicit VSArrayBase(AVSPropertyType type) : refcount(1), ftype(type) {}
123 81 virtual ~VSArrayBase() {}
124 public:
125 44 AVSPropertyType type() const {
126 44 return ftype;
127 }
128
129 71 size_t size() const {
130 71 return fsize;
131 }
132
133 1 bool unique() const noexcept {
134 1 return (refcount == 1);
135 }
136
137 25 void add_ref() noexcept {
138 25 ++refcount;
139 25 }
140
141 106 void release() noexcept {
142
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 106 times.
106 assert(refcount > 0);
143
2/2
✓ Branch 6 → 7 taken 81 times.
✓ Branch 6 → 9 taken 25 times.
106 if (--refcount == 0)
144
1/2
✓ Branch 7 → 8 taken 81 times.
✗ Branch 7 → 9 not taken.
81 delete this;
145 106 }
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 81 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 82 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 80 times.
✗ Branch 2 → 4 not taken.
82 if (fsize == 0) {
192 81 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 82 fsize++;
205 82 }
206
207 42 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 41 times.
42 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 41 times.
✗ Branch 4 → 6 not taken.
42 if (fsize == 1)
210 41 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 965 explicit VSMapStorage() : refcount(1), error(false) {}
247
248 27 explicit VSMapStorage(const VSMapStorage& s) : refcount(1), data(s.data), error(s.error) {
249 27 }
250
251 2 void clear() noexcept {
252 2 data.clear();
253 2 error = false;
254 2 }
255
256 96 bool unique() noexcept {
257 96 return (refcount == 1);
258 };
259
260 313 void add_ref() noexcept {
261 313 ++refcount;
262 313 }
263
264 1305 void release() noexcept {
265
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 1305 times.
1305 assert(refcount > 0);
266
2/2
✓ Branch 6 → 7 taken 992 times.
✓ Branch 6 → 10 taken 313 times.
1305 if (--refcount == 0)
267
1/2
✓ Branch 7 → 8 taken 992 times.
✗ Branch 7 → 10 not taken.
992 delete this;
268 1305 }
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 955 times.
✓ Branch 4 → 5 taken 955 times.
✗ Branch 4 → 11 not taken.
✓ Branch 7 → 8 taken 955 times.
✗ Branch 7 → 10 not taken.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 955 times.
✗ Branch 11 → 12 not taken.
✗ Branch 11 → 14 not taken.
✗ Branch 12 → 13 not taken.
✗ Branch 12 → 14 not taken.
955 AVSMap(const AVSMap* map = nullptr) : data(map ? map->data : new VSMapStorage()) {
280 955 }
281
282 276 AVSMap& operator=(const AVSMap& map) {
283 276 data = map.data;
284 276 return *this;
285 }
286
287 84 bool detach() {
288
2/2
✓ Branch 4 → 5 taken 27 times.
✓ Branch 4 → 14 taken 57 times.
84 if (!data->unique()) {
289
3/8
✓ Branch 5 → 6 taken 27 times.
✗ Branch 5 → 19 not taken.
✓ Branch 7 → 8 taken 27 times.
✗ Branch 7 → 16 not taken.
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 27 times.
✗ Branch 16 → 17 not taken.
✗ Branch 16 → 18 not taken.
27 data = new VSMapStorage(*data);
290 27 return true;
291 }
292 57 return false;
293 }
294
295 121 VSArrayBase* find(const std::string& key) const {
296
1/2
✓ Branch 3 → 4 taken 121 times.
✗ Branch 3 → 14 not taken.
121 auto it = data->data.find(key);
297
2/2
✓ Branch 7 → 8 taken 48 times.
✓ Branch 7 → 9 taken 73 times.
121 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 34 bool erase(const std::string& key) {
312
1/2
✓ Branch 3 → 4 taken 34 times.
✗ Branch 3 → 18 not taken.
34 auto it = data->data.find(key);
313
2/2
✓ Branch 7 → 8 taken 2 times.
✓ Branch 7 → 15 taken 32 times.
34 if (it != data->data.end()) {
314
2/4
✓ Branch 8 → 9 taken 2 times.
✗ Branch 8 → 18 not taken.
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 12 taken 2 times.
2 if (detach())
315 it = data->data.find(key);
316
1/2
✓ Branch 13 → 14 taken 2 times.
✗ Branch 13 → 18 not taken.
2 data->data.erase(it);
317 2 return true;
318 }
319 32 return false;
320 }
321
322 81 void insert(const std::string& key, VSArrayBase* val) {
323
1/2
✓ Branch 2 → 3 taken 81 times.
✗ Branch 2 → 23 not taken.
81 detach();
324
1/2
✓ Branch 4 → 5 taken 81 times.
✗ Branch 4 → 23 not taken.
81 auto it = data->data.find(key);
325
2/2
✓ Branch 8 → 9 taken 15 times.
✓ Branch 8 → 14 taken 66 times.
81 if (it != data->data.end()) {
326 15 it->second = val;
327 }
328 else {
329
2/4
✓ Branch 15 → 16 taken 66 times.
✗ Branch 15 → 22 not taken.
✓ Branch 16 → 17 taken 66 times.
✗ Branch 16 → 20 not taken.
66 data->data.insert(std::make_pair(key, val));
330 }
331 81 }
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 52 size_t size() const {
343 52 return data->data.size();
344 }
345
346 12 void clear() {
347
2/2
✓ Branch 4 → 5 taken 2 times.
✓ Branch 4 → 7 taken 10 times.
12 if (data->unique())
348 2 data->clear();
349 else
350
2/4
✓ Branch 7 → 8 taken 10 times.
✗ Branch 7 → 16 not taken.
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 10 times.
10 data = new VSMapStorage();
351 12 }
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 42 bool hasError() const {
370 42 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