File Coverage

blib/lib/String/Slice.pm
Criterion Covered Total %
statement 15 15 100.0
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 20 20 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 4     4   72119 use strict;
  4         8  
  4         234  
6             package String::Slice;
7              
8             our $VERSION = '0.07';
9              
10 4     4   16 use Exporter 'import';
  4         6  
  4         157  
11             our @EXPORT = qw(slice);
12              
13 4     4   24 use Config;
  4         6  
  4         177  
14 4     4   3079 use Inline C => Config => ccflags => $Config::Config{ccflags} . " -Wall";
  4         64886  
  4         2510  
15              
16 4     4   9879 use String::Slice::Inline C => <<'...';
  4         8  
  4         212  
17             int slice (SV* dummy, ...) {
18             dVAR; dXSARGS;
19              
20             // Validate input:
21             if (items < 2 || items > 4)
22             croak("Usage: String::Slice::slice($slice, $string, $offset=0, $length=-1)");
23             if (! SvPOKp(ST(0)))
24             croak("String::Slice::slice '$slice' argument is not a string");
25             if (! SvPOKp(ST(1)))
26             croak("String::Slice::slice '$string' argument is not a string");
27             {
28             SV* slice = ST(0);
29             SV* string = ST(1);
30             I32 offset = items < 3 ? 0 : (I32)SvIV(ST(2));
31             STRLEN length = items < 4 ? -1 : (STRLEN)SvUV(ST(3));
32             dXSTARG;
33              
34             // Set up local variables:
35             U8* slice_ptr = SvPVX(slice);
36             I32 slice_off;
37              
38             U8* string_ptr = SvPVX(string);
39             U8* string_end = SvEND(string);
40              
41             U8* base_ptr;
42              
43             // Force string and slice to be string-type-scalars (SVt_PV):
44             #if PERL_VERSION > 18
45             if(SvIsCOW(slice)) sv_force_normal(slice);
46             #endif
47              
48             // Is this a new slice? Start at beginning of string:
49             if (slice_ptr < string_ptr || slice_ptr > string_end) {
50             // Link the refcnt of string to slice: (rafl++)
51             sv_magicext(slice, string, PERL_MAGIC_ext, NULL, NULL, 0);
52              
53             // Special way to tell perl it doesn't own the slice memory: (jdb++)
54             SvLEN_set(slice, 0);
55              
56             // Make slice be utf8 if string is utf8:
57             if (SvUTF8(string))
58             SvUTF8_on(slice);
59              
60             // Make the SVs readonly:
61             SvREADONLY_on(slice);
62             SvREADONLY_on(string);
63              
64             base_ptr = string_ptr;
65             slice_off = 0;
66             }
67             // Existing slice. Use it as starting point:
68             else {
69             base_ptr = slice_ptr;
70             slice_off = SvIVX(slice);
71             }
72              
73             if (SvUTF8(string)) {
74             // Hop to the new offset:
75             slice_ptr = utf8_hop(base_ptr, (offset - slice_off));
76             } else {
77             slice_ptr = base_ptr + (offset - slice_off);
78             }
79              
80             // New offset is out of bounds. Handle failure:
81             if (slice_ptr < string_ptr || slice_ptr > string_end) {
82             // Reset the slice:
83             SvPV_set(slice, 0);
84             SvCUR_set(slice, 0);
85             SvIVX(slice) = 0;
86              
87             // Failure:
88             return 0;
89             }
90             // New offset is OK. Handle success:
91             else {
92             // Set the slice pointer:
93             SvPV_set(slice, slice_ptr);
94              
95             // Set the slice character offset (sneaky hack into IV slot):
96             SvIVX(slice) = offset;
97              
98             // Calculate and set the proper byte length for the utf8 slice:
99              
100             if (length < 0) {
101             SvCUR_set(slice, string_end - slice_ptr);
102             }
103             else if (SvUTF8(string)) {
104             if (length >= utf8_distance(string_end, slice_ptr)) {
105             SvCUR_set(slice, string_end - slice_ptr);
106             }
107             else
108             SvCUR_set(slice, utf8_hop(slice_ptr, length) - slice_ptr);
109             } else {
110             if (length >= string_end - slice_ptr)
111             SvCUR_set(slice, string_end - slice_ptr);
112             else
113             SvCUR_set(slice, length);
114             }
115              
116             // Success:
117             return 1;
118             }
119             }
120             }
121             ...
122              
123             1;