File Coverage

blib/lib/String/Slice.pm
Criterion Covered Total %
statement 9 9 100.0
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 12 12 100.0


line stmt bran cond sub pod time code
1             # TODO:
2             # - Maybe support negative length (like substr).
3             # - Get code review to see if char offset in IV is OK.
4             # - Maybe croak unless string/slice match on utf8-ness.
5 3     3   44737 use strict;
  3         5  
  3         155  
6             package String::Slice;
7              
8             our $VERSION = '0.06';
9              
10 3     3   11 use Exporter 'import';
  3         4  
  3         189  
11             our @EXPORT = qw(slice);
12              
13 3     3   986 use String::Slice::Inline C => <<'...';
  3         4  
  3         82  
14             int slice (SV* dummy, ...) {
15             dVAR; dXSARGS;
16              
17             // Validate input:
18             if (items < 2 || items > 4)
19             croak("Usage: String::Slice::slice($slice, $string, $offset=0, $length=-1)");
20             if (! SvPOKp(ST(0)))
21             croak("String::Slice::slice '$slice' argument is not a string");
22             if (! SvPOKp(ST(1)))
23             croak("String::Slice::slice '$string' argument is not a string");
24             {
25             SV* slice = ST(0);
26             SV* string = ST(1);
27             I32 offset = items < 3 ? 0 : (I32)SvIV(ST(2));
28             STRLEN length = items < 4 ? -1 : (STRLEN)SvUV(ST(3));
29             dXSTARG;
30              
31             // Set up local variables:
32             U8* slice_ptr = SvPVX(slice);
33             U8* slice_end;
34             I32 slice_off;
35              
36             U8* string_ptr = SvPVX(string);
37             U8* string_end = SvEND(string);
38              
39             U8* base_ptr;
40              
41             // Force string and slice to be string-type-scalars (SVt_PV):
42             #if PERL_VERSION > 18
43             if(SvIsCOW(slice)) sv_force_normal(slice);
44             #endif
45              
46             // Is this a new slice? Start at beginning of string:
47             if (slice_ptr < string_ptr || slice_ptr > string_end) {
48             // Link the refcnt of string to slice: (rafl++)
49             sv_magicext(slice, string, PERL_MAGIC_ext, NULL, NULL, 0);
50              
51             // Make slice be utf8 if string is utf8:
52             if (SvUTF8(string))
53             SvUTF8_on(slice);
54              
55             // Make the SVs readonly:
56             SvREADONLY_on(slice);
57             SvREADONLY_on(string);
58              
59             base_ptr = string_ptr;
60             slice_off = 0;
61             }
62             // Existing slice. Use it as starting point:
63             else {
64             base_ptr = slice_ptr;
65             slice_off = SvIVX(slice);
66             }
67              
68             // Hop to the new offset:
69             slice_ptr = utf8_hop(base_ptr, (offset - slice_off));
70              
71             // New offset is out of bounds. Handle failure:
72             if (slice_ptr < string_ptr || slice_ptr > string_end) {
73             // Reset the slice:
74             SvPV_set(slice, 0);
75             SvCUR_set(slice, 0);
76             SvIVX(slice) = 0;
77              
78             // Failure:
79             return 0;
80             }
81             // New offset is OK. Handle success:
82             else {
83             // Set the slice pointer:
84             SvPV_set(slice, slice_ptr);
85              
86             // Set the slice character offset (sneaky hack into IV slot):
87             SvIVX(slice) = offset;
88              
89             // Calculate the proper byte length for the utf8 slice:
90              
91             // If requested number of chars is negative (default) or too big,
92             // use the entire remainder of the string:
93             if (length < 0 || length >= utf8_distance(string_end, slice_ptr))
94             slice_end = string_end;
95             // Else find the end of utf8 slice:
96             else
97             slice_end = utf8_hop(slice_ptr, length);
98              
99             // Set the length of the slice buffer in bytes:
100             SvCUR_set(slice, slice_end - slice_ptr);
101              
102             // Special way to tell perl it doesn't own the slice memory: (jdb++)
103             SvLEN_set(slice, 0);
104              
105             // Success:
106             return 1;
107             }
108             }
109             }
110             ...
111              
112             1;