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   85196 use strict;
  4         7  
  4         308  
6             package String::Slice;
7              
8             our $VERSION = '0.08';
9              
10 4     4   24 use Exporter 'import';
  4         6  
  4         203  
11             our @EXPORT = qw(slice);
12              
13 4     4   40 use Config;
  4         7  
  4         252  
14 4     4   3171 use Inline C => Config => ccflags => $Config::Config{ccflags} . " -Wall";
  4         80584  
  4         2827  
15              
16 4     4   10642 use String::Slice::Inline C => <<'...';
  4         9  
  4         141  
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              
33             // Set up local variables:
34             U8* slice_ptr = SvPVX(slice);
35             I32 slice_off;
36              
37             U8* string_ptr = SvPVX(string);
38             U8* string_end = SvEND(string);
39              
40             U8* base_ptr;
41              
42             // Force string and slice to be string-type-scalars (SVt_PV):
43             #if PERL_VERSION > 18
44             if(SvIsCOW(slice)) sv_force_normal(slice);
45             #endif
46              
47             // Is this a new slice? Start at beginning of string:
48             if (slice_ptr < string_ptr || slice_ptr > string_end) {
49             // Link the refcnt of string to slice: (rafl++)
50             sv_magicext(slice, string, PERL_MAGIC_ext, NULL, NULL, 0);
51              
52             // Special way to tell perl it doesn't own the slice memory: (jdb++)
53             SvLEN_set(slice, 0);
54              
55             // Make slice be utf8 if string is utf8:
56             if (SvUTF8(string))
57             SvUTF8_on(slice);
58              
59             // Make the SVs readonly:
60             SvREADONLY_on(slice);
61             SvREADONLY_on(string);
62              
63             base_ptr = string_ptr;
64             slice_off = 0;
65             }
66             // Existing slice. Use it as starting point:
67             else {
68             base_ptr = slice_ptr;
69             slice_off = SvIVX(slice);
70             }
71              
72             if (SvUTF8(string)) {
73             // Hop to the new offset:
74             slice_ptr = utf8_hop(base_ptr, (offset - slice_off));
75             } else {
76             slice_ptr = base_ptr + (offset - slice_off);
77             }
78              
79             // New offset is out of bounds. Handle failure:
80             if (slice_ptr < string_ptr || slice_ptr > string_end) {
81             // Reset the slice:
82             SvPV_set(slice, 0);
83             SvCUR_set(slice, 0);
84             SvIVX(slice) = 0;
85              
86             // Failure:
87             return 0;
88             }
89             // New offset is OK. Handle success:
90             else {
91             // Set the slice pointer:
92             SvPV_set(slice, slice_ptr);
93              
94             // Set the slice character offset (sneaky hack into IV slot):
95             SvIVX(slice) = offset;
96              
97             // Calculate and set the proper byte length for the utf8 slice:
98              
99             if (length < 0) {
100             SvCUR_set(slice, string_end - slice_ptr);
101             }
102             else if (SvUTF8(string)) {
103             if (length >= utf8_distance(string_end, slice_ptr)) {
104             SvCUR_set(slice, string_end - slice_ptr);
105             }
106             else
107             SvCUR_set(slice, utf8_hop(slice_ptr, length) - slice_ptr);
108             } else {
109             if (length >= string_end - slice_ptr)
110             SvCUR_set(slice, string_end - slice_ptr);
111             else
112             SvCUR_set(slice, length);
113             }
114              
115             // Success:
116             return 1;
117             }
118             }
119             }
120             ...
121              
122             1;