File Coverage

lib/Doubly/Pointer.xs
Criterion Covered Total %
statement 205 230 89.1
branch 77 100 77.0
condition n/a
subroutine n/a
pod n/a
total 282 330 85.4


line stmt bran cond sub pod time code
1             #include "EXTERN.h" // globals/constant import locations
2             #include "perl.h" // Perl symbols, structures and constants definition
3             #include "XSUB.h" // xsubpp functions and macros
4              
5             typedef struct DoublyPointer {
6             SV* data;
7             struct DoublyPointer* next;
8             struct DoublyPointer* prev;
9             } *DoublyPointer;
10              
11 219022           int _is_undef (DoublyPointer self) {
12             dTHX;
13              
14 219022 100         if (SvOK(self->data)) {
15 218311           return 0;
16             }
17              
18 711 50         if (self->next != NULL) {
19 0           return 0;
20             }
21              
22 711 50         if(self->prev != NULL) {
23 0           return 0;
24             }
25              
26 711           return 1;
27             }
28              
29 707           DoublyPointer _set_data (DoublyPointer self, SV* data) {
30 707           self->data = data;
31 707           return self;
32             }
33              
34 111185           DoublyPointer _new (SV* data) {
35 111185           DoublyPointer node = (DoublyPointer)malloc(sizeof(struct DoublyPointer));
36 111185           node->data = data;
37 111185           node->next = NULL;
38 111185           node->prev = NULL;
39 111185           return node;
40             }
41              
42 980           DoublyPointer _goto_start (DoublyPointer self) {
43 1100 100         while (self->prev != NULL) {
44 120           self = self->prev;
45             }
46              
47 980           return self;
48             }
49              
50 6           int _is_start (DoublyPointer self) {
51 6 50         if (self->prev != NULL) {
52 0           return 0;
53             }
54 6           return 1;
55             }
56              
57 108566           DoublyPointer _goto_end (DoublyPointer self) {
58 331027 100         while (self->next != NULL) {
59 222461           self = self->next;
60             }
61              
62 108566           return self;
63             }
64              
65 4           int _is_end (DoublyPointer self) {
66 4 50         if (self->next != NULL) {
67 0           return 0;
68             }
69 4           return 1;
70             }
71              
72 124           int _length (DoublyPointer self) {
73             dTHX;
74 124           self = _goto_start(self);
75              
76 124 100         int len = self->next != NULL ? 1 : SvOK(self->data) ? 1 : 0;
    50          
77              
78 100567 100         while (self->next != NULL) {
79 100443           self = self->next;
80 100443           len++;
81             }
82              
83 124           return len;
84             }
85              
86 1           DoublyPointer _find (DoublyPointer self, SV * cb) {
87             dTHX;
88              
89 1           DoublyPointer find = _goto_start(self);
90              
91 1           dSP;
92 1 50         PUSHMARK(SP);
93 1 50         XPUSHs(find->data);
94 1           PUTBACK;
95 1           call_sv(cb, G_SCALAR);
96 1 50         if (SvTRUEx(*PL_stack_sp)) {
97 0           POPs;
98 0           return find;
99             }
100 1           POPs;
101              
102 1 50         while (find->next != NULL) {
103 1           find = find->next;
104              
105 1           dSP;
106 1 50         PUSHMARK(SP);
107 1 50         XPUSHs(find->data);
108 1           PUTBACK;
109 1           call_sv(cb, G_SCALAR);
110 1 50         if (SvTRUEx(*PL_stack_sp)) {
111 1           POPs;
112 1           return find;
113             }
114 0           POPs;
115             }
116              
117 0           croak("No match found for find cb");
118             }
119              
120 103           DoublyPointer _insert_before (DoublyPointer self, SV * data) {
121 103 100         if (_is_undef(self)) {
122 1           return _set_data(self, data);
123             }
124              
125 102           DoublyPointer node = _new(data);
126              
127 102           node->next = self;
128              
129 102 50         if (self->prev) {
130 0           node->prev = self->prev;
131 0           self->prev->next = node;
132             }
133              
134 102           self->prev = node;
135              
136 102           return node;
137             }
138              
139 117           DoublyPointer _insert_after (DoublyPointer self, SV * data) {
140 117 100         if (_is_undef(self)) {
141 1           return _set_data(self, data);
142             }
143              
144 116           DoublyPointer node = _new(data);
145              
146 116           node->prev = self;
147              
148 116 50         if (self->next) {
149 0           node->next = self->next;
150 0           self->next->prev = node;
151             }
152              
153 116           self->next = node;
154              
155 116           return node;
156             }
157              
158 1           DoublyPointer _insert_find (DoublyPointer self, SV * cb, SV * data) {
159 1 50         if (_is_undef(self)) {
160 1           return _set_data(self, data);
161             }
162              
163 0           self = _find(self, cb);
164              
165 0           return _insert_before(self, data);
166             }
167              
168 3           DoublyPointer _insert_at_pos (DoublyPointer self, int pos, SV * data) {
169 3 100         if (_is_undef(self)) {
170 1           return _set_data(self, data);
171             }
172              
173 2           self = _goto_start(self);
174              
175 2           int i = 0;
176 5 100         for (i = 0; i < pos; i++) {
177 3 100         if (self->next != NULL) {
178 1           self = self->next;
179             }
180             }
181              
182 2           return _insert_after(self, data);
183             }
184              
185 315           DoublyPointer _insert_at_start (DoublyPointer self, SV * data) {
186 315 100         if (_is_undef(self)) {
187 13           return _set_data(self, data);
188             }
189              
190 302           self = _goto_start(self);
191              
192 302           DoublyPointer node = _new(data);
193              
194 302           self->prev = node;
195 302           node->next = self;
196              
197 302           return node;
198             }
199              
200 108620           DoublyPointer _insert_at_end(DoublyPointer self, SV * data) {
201 108620 100         if (_is_undef(self)) {
202 686           return _set_data(self, data);
203             }
204              
205 107934           self = _goto_end(self);
206              
207 107934           DoublyPointer newNode = _new(data);
208              
209 107934           self->next = newNode;
210 107934           newNode->prev = self;
211              
212 107934           return newNode;
213             }
214              
215             /* Helper function for destroy() - doesn't allocate return value */
216 108566           void _destroy_node (SV * var, DoublyPointer self) {
217             dTHX;
218 108566 100         if (_is_undef(self)) {
219 3           return;
220             }
221              
222 108563           DoublyPointer prev = self->prev;
223 108563           DoublyPointer next = self->next;
224 108563 50         if (prev != NULL) {
225 0 0         if (next != NULL) {
226 0           sv_setref_pv(var, "Doubly::Pointer", next);
227 0           next->prev = prev;
228 0           prev->next = next;
229             } else {
230 0           sv_setref_pv(var, "Doubly::Pointer", prev);
231 0           prev->next = NULL;
232             }
233 0           self->prev = NULL;
234 0           self->next = NULL;
235 0           SvREFCNT_dec(self->data);
236 0           free(self);
237 108563 100         } else if (next != NULL) {
238 105931           sv_setref_pv(var, "Doubly::Pointer", next);
239 105931           next->prev = NULL;
240 105931           self->prev = NULL;
241 105931           self->next = NULL;
242 105931           SvREFCNT_dec(self->data);
243 105931           free(self);
244             } else {
245             /* Last node - free the data but keep the empty node */
246 2632 50         if (self->data != &PL_sv_undef) {
247 2632           SvREFCNT_dec(self->data);
248             }
249 2632           self->data = &PL_sv_undef;
250             }
251             }
252              
253 752           SV * _remove (SV * var, DoublyPointer self) {
254             dTHX;
255 752 100         if (_is_undef(self)) {
256 2           return &PL_sv_undef;
257             }
258              
259 750           SV * data = newSVsv(self->data);
260              
261 750           DoublyPointer prev = self->prev;
262 750           DoublyPointer next = self->next;
263 750 100         if (prev != NULL) {
264 222 100         if (next != NULL) {
265 2           sv_setref_pv(var, "Doubly::Pointer", next);
266 2           next->prev = prev;
267 2           prev->next = next;
268             } else {
269 220           sv_setref_pv(var, "Doubly::Pointer", prev);
270 220           prev->next = NULL;
271             }
272 222           self->prev = NULL;
273 222           self->next = NULL;
274 222           SvREFCNT_dec(self->data);
275 222           free(self);
276 528 100         } else if (next != NULL) {
277 520           sv_setref_pv(var, "Doubly::Pointer", next);
278 520           next->prev = NULL;
279 520           self->prev = NULL;
280 520           self->next = NULL;
281 520           SvREFCNT_dec(self->data);
282 520           free(self);
283             } else {
284             /* Last node - free the data but keep the empty node */
285 8 50         if (self->data != &PL_sv_undef) {
286 8           SvREFCNT_dec(self->data);
287             }
288 8           self->data = &PL_sv_undef;
289             }
290              
291 750           return data;
292             }
293              
294 322           SV * _remove_from_start(SV * var, DoublyPointer self) {
295 322 100         if (_is_undef(self)) {
296 2           return &PL_sv_undef;
297             }
298              
299 320           self = _goto_start(self);
300              
301 320           return _remove(var, self);
302             }
303              
304 219           SV * _remove_from_end(SV * var, DoublyPointer self) {
305 219 50         if (_is_undef(self)) {
306 0           return &PL_sv_undef;
307             }
308              
309 219           self = _goto_end(self);
310              
311 219           return _remove(var, self);
312             }
313              
314 4           SV * _remove_from_pos(SV * var, DoublyPointer self, int pos) {
315 4 100         if (_is_undef(self)) {
316 1           return &PL_sv_undef;
317             }
318              
319 3           self = _goto_start(self);
320              
321 3           int i = 0;
322 6 100         for (i = 0; i < pos; i++) {
323 3 50         if (self->next != NULL) {
324 3           self = self->next;
325             }
326             }
327              
328 3           return _remove(var, self);
329             }
330              
331              
332             MODULE = Doubly::Pointer PACKAGE = Doubly::Pointer
333             PROTOTYPES: DISABLE
334              
335             DoublyPointer
336             new(...)
337             CODE:
338 2731 100         RETVAL = _new(items > 1 ? newSVsv(ST(1)) : &PL_sv_undef);
339             OUTPUT:
340             RETVAL
341              
342             int
343             length(self)
344             DoublyPointer self
345             CODE:
346 124           RETVAL = _length(self);
347             OUTPUT:
348             RETVAL
349              
350             SV *
351             data(self, ...)
352             DoublyPointer self
353             CODE:
354 85 100         if (items > 1) {
355 4           self = _set_data(self, newSVsv(ST(1)));
356             }
357              
358 85           RETVAL = newSVsv(self->data);
359             OUTPUT:
360             RETVAL
361              
362             DoublyPointer
363             start(self)
364             DoublyPointer self
365             CODE:
366 228           RETVAL = _goto_start(self);
367             OUTPUT:
368             RETVAL
369              
370             int
371             is_start(self)
372             DoublyPointer self
373             CODE:
374 6           RETVAL = _is_start(self);
375             OUTPUT:
376             RETVAL
377              
378             DoublyPointer
379             end(self)
380             DoublyPointer self
381             CODE:
382 209           RETVAL = _goto_end(self);
383             OUTPUT:
384             RETVAL
385              
386             int
387             is_end(self)
388             DoublyPointer self
389             CODE:
390 4           RETVAL = _is_end(self);
391             OUTPUT:
392             RETVAL
393              
394             DoublyPointer
395             next(self)
396             DoublyPointer self
397             CODE:
398 244           RETVAL = self->next;
399             OUTPUT:
400             RETVAL
401              
402             DoublyPointer
403             prev(self, ...)
404             DoublyPointer self
405             CODE:
406 207           RETVAL = self->prev;
407             OUTPUT:
408             RETVAL
409              
410             DoublyPointer
411             bulk_add(self, ...)
412             DoublyPointer self
413             CODE:
414 204           self = _goto_end(self);
415 204 50         if (items > 1) {
416 204           int i = 1;
417 102214 100         for (i = 1; i < items; i++) {
418 102010           self = _insert_at_end(self, newSVsv(ST(i)));
419             }
420             }
421 204           RETVAL = self;
422             OUTPUT:
423             RETVAL
424              
425             DoublyPointer
426             add(self, ...)
427             DoublyPointer self
428             CODE:
429 6295           RETVAL = _insert_at_end(self, newSVsv(ST(1)));
430             OUTPUT:
431             RETVAL
432              
433             DoublyPointer
434             insert(self, cb, ...)
435             DoublyPointer self
436             SV * cb
437             CODE:
438 1           RETVAL = _insert_find(self, cb, newSVsv(ST(2)));
439             OUTPUT:
440             RETVAL
441              
442             DoublyPointer
443             insert_before(self, ...)
444             DoublyPointer self
445             CODE:
446 103           RETVAL = _insert_before(self, newSVsv(ST(1)));
447             OUTPUT:
448             RETVAL
449              
450             DoublyPointer
451             insert_after(self, ...)
452             DoublyPointer self
453             CODE:
454 115           RETVAL = _insert_after(self, newSVsv(ST(1)));
455             OUTPUT:
456             RETVAL
457              
458             DoublyPointer
459             insert_at_start(self, ...)
460             DoublyPointer self
461             CODE:
462 315           RETVAL = _insert_at_start(self, newSVsv(ST(1)));
463             OUTPUT:
464             RETVAL
465              
466             DoublyPointer
467             insert_at_end(self, ...)
468             DoublyPointer self
469             CODE:
470 315           RETVAL = _insert_at_end(self, newSVsv(ST(1)));
471             OUTPUT:
472             RETVAL
473              
474             DoublyPointer
475             insert_at_pos(self, ...)
476             DoublyPointer self
477             CODE:
478 3           RETVAL = _insert_at_pos(self, SvIV(ST(1)), newSVsv(ST(2)));
479             OUTPUT:
480             RETVAL
481              
482             SV *
483             remove(self, ...)
484             DoublyPointer self
485             CODE:
486 210           RETVAL = _remove(ST(0), self);
487             OUTPUT:
488             RETVAL
489              
490             SV *
491             remove_from_start(self, ...)
492             DoublyPointer self
493             CODE:
494 322 100         if (self->prev != NULL) {
495             /* Not at start - use a temporary SV to track the start, don't modify self */
496 2           SV * tmp = newSVsv(ST(0));
497 2           RETVAL = _remove_from_start(tmp, self);
498 2           SvREFCNT_dec(tmp);
499             } else {
500             /* At start - modify self to point to next node */
501 320           RETVAL = _remove_from_start(ST(0), self);
502             }
503             OUTPUT:
504             RETVAL
505              
506             SV *
507             remove_from_end(self, ...)
508             DoublyPointer self
509             CODE:
510 219 100         if (self->next != NULL) {
511             /* Not at end - use a temporary SV to track the end, don't modify self */
512 215           SV * tmp = newSVsv(ST(0));
513 215           RETVAL = _remove_from_end(tmp, self);
514 215           SvREFCNT_dec(tmp);
515             } else {
516             /* At end - modify self to point to prev node */
517 4           RETVAL = _remove_from_end(ST(0), self);
518             }
519             OUTPUT:
520             RETVAL
521              
522             SV *
523             remove_from_pos(self, pos)
524             DoublyPointer self
525             SV * pos
526             CODE:
527 4           RETVAL = _remove_from_pos(ST(0), self, SvIV(pos));
528             OUTPUT:
529             RETVAL
530              
531             DoublyPointer
532             find(self, cb)
533             DoublyPointer self
534             SV * cb
535             CODE:
536 1           RETVAL = _find(self, cb);
537             OUTPUT:
538             RETVAL
539              
540             void
541             destroy(self, ...)
542             DoublyPointer self
543             CODE:
544             DoublyPointer next;
545             /* First go to start of the list */
546 103434 100         while ( self->prev != NULL ) {
547 100799           self = self->prev;
548             }
549             /* Now destroy all nodes going forward */
550 108566 100         while ( self->next != NULL ) {
551 105931           next = self->next;
552 105931           _destroy_node(ST(0), self);
553 105931           self = next;
554             }
555 2635           _destroy_node(ST(0), self);