File Coverage

/usr/local/lib/perl5/site_perl/5.26.1/x86_64-linux/XS/Framework.x/i/xs/Array.h
Criterion Covered Total %
statement 8 8 100.0
branch 2 4 50.0
condition n/a
subroutine n/a
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             #pragma once
2             #include <xs/Scalar.h>
3             #include <xs/KeyProxy.h>
4              
5             namespace xs {
6              
7             using xs::my_perl;
8              
9             struct Simple;
10              
11 2           struct Array : Sv {
12             enum create_type_t { ALIAS, COPY };
13              
14             static Array create () { return Array(newAV(), NONE); }
15              
16 1           static Array create (size_t cap) {
17 1           Array ret(newAV(), NONE);
18 1 50         ret.reserve(cap);
19 1           return ret;
20             }
21              
22             static Array create (size_t size, SV** content, create_type_t type = ALIAS);
23             static Array create (const std::initializer_list<Scalar>& l, create_type_t type = ALIAS) { return Array(l, type); }
24             static Array create (const Array& from, create_type_t type = ALIAS) { return create(from.size(), from._svlist(), type); }
25              
26             static Array noinc (SV* val) { return Array(val, NONE); }
27             static Array noinc (AV* val) { return Array(val, NONE); }
28              
29             Array (std::nullptr_t = nullptr) {}
30             Array (SV* sv, bool policy = INCREMENT) : Sv(sv, policy) { _validate(); }
31 2           Array (AV* sv, bool policy = INCREMENT) : Sv(sv, policy) {}
32              
33             Array (const Array& oth) : Sv(oth) {}
34             Array (Array&& oth) : Sv(std::move(oth)) {}
35             Array (const Sv& oth) : Sv(oth) { _validate(); }
36             Array (Sv&& oth) : Sv(std::move(oth)) { _validate(); }
37             Array (const Simple&) = delete;
38             Array (const Hash&) = delete;
39             Array (const Sub&) = delete;
40             Array (const Glob&) = delete;
41             Array (const Io&) = delete;
42              
43             Array (const std::initializer_list<Scalar>& l, create_type_t type = ALIAS);
44              
45             Array& operator= (SV* val) { Sv::operator=(val); _validate(); return *this; }
46             Array& operator= (AV* val) { Sv::operator=(val); return *this; }
47             Array& operator= (const Array& oth) { Sv::operator=(oth); return *this; }
48             Array& operator= (Array&& oth) { Sv::operator=(std::move(oth)); return *this; }
49             Array& operator= (const Sv& oth) { return operator=(oth.get()); }
50             Array& operator= (Sv&& oth) { Sv::operator=(std::move(oth)); _validate(); return *this; }
51             Array& operator= (const Simple&) = delete;
52             Array& operator= (const Hash&) = delete;
53             Array& operator= (const Sub&) = delete;
54             Array& operator= (const Glob&) = delete;
55             Array& operator= (const Io&) = delete;
56              
57             void set (SV* val) { Sv::operator=(val); }
58              
59             operator AV* () const { return (AV*)sv; }
60             operator HV* () const = delete;
61             operator CV* () const = delete;
62             operator GV* () const = delete;
63             operator IO* () const = delete;
64              
65             AV* operator-> () const { return (AV*)sv; }
66              
67             template <typename T = SV> panda::enable_if_one_of_t<T,SV,AV>* get () const { return (T*)sv; }
68              
69             Scalar fetch (size_t key) const {
70             if (!sv) return Scalar();
71             if (key >= _size()) return Scalar();
72             Scalar ret;
73             ret.set(_svlist()[key]);
74             return ret;
75             }
76              
77             Scalar front () const { return fetch(0); }
78             Scalar back () const { return sv && _size() ? fetch(_topi()) : Scalar(); }
79              
80             Scalar at (size_t key) const {
81             Scalar ret = fetch(key);
82             if (!ret) throw std::out_of_range("at: no key");
83             return ret;
84             }
85              
86             template <typename T, typename = panda::enable_if_arithmetic_t<T>>
87             Scalar operator[] (T key) const {
88             Scalar ret;
89             ret.set(_svlist()[key]);
90             return ret;
91             }
92              
93             void store (size_t key, const Scalar& val);
94             void store (size_t key, std::nullptr_t) { store(key, Scalar()); }
95             void store (size_t key, SV* v) { store(key, Scalar(v)); }
96             void store (size_t key, const Sv& v) { store(key, Scalar(v)); }
97             void store (size_t key, const Array&) = delete;
98             void store (size_t key, const Hash&) = delete;
99             void store (size_t key, const Sub&) = delete;
100             void store (size_t key, const Io&) = delete;
101              
102             template <typename T, typename = panda::enable_if_arithmetic_t<T>>
103             KeyProxy operator[] (T key) { return KeyProxy(_svlist() + key, true); }
104              
105             bool exists (size_t key) const {
106             if (key >= size()) return false;
107             return _svlist()[key];
108             }
109              
110             Scalar del (size_t key) {
111             Scalar ret = fetch(key);
112             if (ret) (*this)[key] = nullptr;
113             return ret;
114             }
115              
116             size_t size () const { return sv ? _size() : 0; }
117             size_t capacity () const { return sv ? _cap() : 0; }
118             SSize_t top_index () const { return sv ? _topi() : -1; }
119              
120             void resize (size_t newsz) { av_fill((AV*)sv, (SSize_t)newsz - 1); }
121 2           void reserve (size_t newcap) { av_extend((AV*)sv, (SSize_t)newcap - 1); }
122              
123             Scalar shift () {
124             if (!sv) return Scalar();
125             SV* retsv = av_shift((AV*)sv);
126             if (retsv == &PL_sv_undef) return Scalar();
127             Scalar ret;
128             ret.set(retsv);
129             SvREFCNT_dec(retsv); // because av_shift does not decrement, just transfers ownership
130             return ret;
131             }
132              
133             Scalar pop () {
134             if (!sv) return Scalar();
135             SV* retsv = av_pop((AV*)sv);
136             if (retsv == &PL_sv_undef) return Scalar();
137             Scalar ret;
138             ret.set(retsv);
139             SvREFCNT_dec(retsv); // because av_pop does not decrement, just transfers ownership
140             return ret;
141             }
142              
143             void push (const std::initializer_list<Scalar>& l);
144             void push (const List& l);
145             void push (const Scalar& v);
146             void push (const Array&) = delete;
147             void push (const Hash&) = delete;
148             void push (const Sub&) = delete;
149             void push (const Io&) = delete;
150             void push (SV* v) { push(Scalar(v)); }
151 3 50         void push (const Sv& v) { push(Scalar(v)); }
152              
153             void unshift (const std::initializer_list<Scalar>& l);
154             void unshift (const List& l);
155             void unshift (const Scalar& v);
156             void unshift (const Array&) = delete;
157             void unshift (const Hash&) = delete;
158             void unshift (const Sub&) = delete;
159             void unshift (const Io&) = delete;
160             void unshift (SV* v) { unshift(Scalar(v)); }
161             void unshift (const Sv& v) { unshift(Scalar(v)); }
162              
163             void undef () { if (sv) av_undef((AV*)sv); }
164             void clear () { if (sv) av_clear((AV*)sv); }
165              
166             struct const_iterator : private std::iterator<std::random_access_iterator_tag, const Scalar> {
167             const_iterator () : cur(nullptr) {}
168             const_iterator (SV** avfirst) : cur(avfirst) {}
169              
170             const_iterator& operator++ () { ++cur; return *this; }
171             const_iterator& operator-- () { --cur; return *this; }
172              
173             const_iterator operator++ (int) { const_iterator ret = *this; operator++(); return ret; }
174             const_iterator operator-- (int) { const_iterator ret = *this; operator--(); return ret; }
175              
176             const_iterator& operator+= (ptrdiff_t n) { cur += n; return *this; }
177             const_iterator& operator-= (ptrdiff_t n) { cur -= n; return *this; }
178              
179             bool operator== (const const_iterator& oth) const { return cur == oth.cur; }
180             bool operator!= (const const_iterator& oth) const { return cur != oth.cur; }
181              
182             const Scalar* operator-> () { return (const Scalar*)cur; }
183             const Scalar& operator* () { return *((const Scalar*)cur); }
184              
185             ptrdiff_t operator- (const const_iterator& rh) { return cur - rh.cur; }
186              
187             bool operator< (const const_iterator& rh) { return cur < rh.cur; }
188             bool operator<= (const const_iterator& rh) { return cur <= rh.cur; }
189             bool operator> (const const_iterator& rh) { return cur > rh.cur; }
190             bool operator>= (const const_iterator& rh) { return cur >= rh.cur; }
191              
192             const Scalar& operator[] (size_t key) { return *((const Scalar*)(cur+key)); }
193              
194             protected:
195             SV** cur;
196             };
197              
198             struct iterator : private std::iterator<std::random_access_iterator_tag, Scalar>, const_iterator {
199             using const_iterator::const_iterator;
200              
201             iterator& operator++ () { const_iterator::operator++(); return *this; }
202             iterator& operator-- () { const_iterator::operator--(); return *this; }
203              
204             iterator operator++ (int) { iterator ret = *this; const_iterator::operator++(); return ret; }
205             iterator operator-- (int) { iterator ret = *this; const_iterator::operator--(); return ret; }
206              
207             iterator& operator+= (ptrdiff_t n) { const_iterator::operator+=(n); return *this; }
208             iterator& operator-= (ptrdiff_t n) { const_iterator::operator-=(n); return *this; }
209              
210             Scalar* operator-> () { return (Scalar*)cur; }
211             KeyProxy operator* () { return KeyProxy(cur, true); }
212             KeyProxy operator[] (size_t key) { return KeyProxy(cur+key, true); }
213             };
214              
215             const_iterator cbegin () const { return sv ? const_iterator(_svlist()) : const_iterator(); }
216             const_iterator cend () const { return sv ? const_iterator(_svlist()+_size()) : const_iterator(); }
217             const_iterator begin () const { return cbegin(); }
218             const_iterator end () const { return cend(); }
219             iterator begin () { return sv ? iterator(_svlist()) : iterator(); }
220             iterator end () { return sv ? iterator(_svlist()+_size()) : iterator(); }
221              
222             U32 push_on_stack (SV** sp, U32 max = 0) const;
223              
224             private:
225             inline SV** _svlist () const { return AvARRAY((AV*)sv); }
226             inline size_t _size () const { return (size_t)(_topi()+1); }
227             inline void _size (size_t i) { AvFILLp((AV*)sv) = (SSize_t)i-1; }
228             inline size_t _cap () const { return (size_t)(AvMAX((AV*)sv)+1); }
229             inline SSize_t _topi () const { return AvFILLp((AV*)sv); }
230              
231             void _validate () {
232             if (!sv) return;
233             if (SvTYPE(sv) == SVt_PVAV) return;
234             if (SvROK(sv)) { // reference to array?
235             SV* val = SvRV(sv);
236             if (SvTYPE(val) == SVt_PVAV) {
237             Sv::operator=(val);
238             return;
239             }
240             }
241             if (is_undef()) return reset();
242             reset();
243             throw std::invalid_argument("SV is not an Array or Array reference");
244             }
245             };
246              
247             inline xs::Array::const_iterator operator+ (const xs::Array::const_iterator& lh, ptrdiff_t rh) { return xs::Array::const_iterator(lh) += rh; }
248             inline xs::Array::const_iterator operator+ (ptrdiff_t lh, const xs::Array::const_iterator& rh) { return xs::Array::const_iterator(rh) += lh; }
249             inline xs::Array::const_iterator operator- (const xs::Array::const_iterator& lh, ptrdiff_t rh) { return xs::Array::const_iterator(lh) -= rh; }
250             inline xs::Array::iterator operator+ (const xs::Array::iterator& lh, ptrdiff_t rh) { return xs::Array::iterator(lh) += rh; }
251             inline xs::Array::iterator operator+ (ptrdiff_t lh, const xs::Array::iterator& rh) { return xs::Array::iterator(rh) += lh; }
252             inline xs::Array::iterator operator- (const xs::Array::iterator& lh, ptrdiff_t rh) { return xs::Array::iterator(lh) -= rh; }
253              
254             struct List : public Array {
255             List () {}
256             List (SV* sv, bool policy = INCREMENT) : Array(sv, policy) {}
257             List (AV* sv, bool policy = INCREMENT) : Array(sv, policy) {}
258              
259             List (const Array& oth) : Array(oth) {}
260             List (Array&& oth) : Array(std::move(oth)) {}
261             List (const Sv& oth) : Array(oth) {}
262             List (Sv&& oth) : Array(std::move(oth)) {}
263              
264             List (const Simple&) = delete;
265             List (const Hash&) = delete;
266             List (const Sub&) = delete;
267             List (const Glob&) = delete;
268             List (const Io&) = delete;
269              
270             List& operator= (SV* val) { Array::operator=(val); return *this; }
271             List& operator= (AV* val) { Array::operator=(val); return *this; }
272             List& operator= (const Array& oth) { Array::operator=(oth); return *this; }
273             List& operator= (Array&& oth) { Array::operator=(std::move(oth)); return *this; }
274             List& operator= (const Sv& oth) { Array::operator=(oth); return *this; }
275             List& operator= (Sv&& oth) { Array::operator=(std::move(oth)); return *this; }
276              
277             List& operator= (const Simple&) = delete;
278             List& operator= (const Hash&) = delete;
279             List& operator= (const Sub&) = delete;
280             List& operator= (const Glob&) = delete;
281             List& operator= (const Io&) = delete;
282             };
283              
284             }
285              
286             // DEPRECATED, will be removed, use Array.begin()/end() instead
287             #define XS_AV_ITER(av,code) { \
288             SV** list = AvARRAY(av); \
289             SSize_t fillp = AvFILLp(av); \
290             for (SSize_t i = 0; i <= fillp; ++i) { SV* elem = *list++; code } \
291             }
292             #define XS_AV_ITER_NE(av,code) XS_AV_ITER(av,{if(!elem) continue; code})
293             #define XS_AV_ITER_NU(av,code) XS_AV_ITER(av,{if(!elem || !SvOK(elem)) continue; code})
294