File Coverage

lib/smallnum/XS.xs
Criterion Covered Total %
statement 52 52 100.0
branch 25 28 89.2
condition n/a
subroutine n/a
pod n/a
total 77 80 96.2


line stmt bran cond sub pod time code
1             #define PERL_NO_GET_CONTEXT
2             #include "EXTERN.h"
3             #include "perl.h"
4             #include "XSUB.h"
5             #include
6             #include
7              
8              
9             typedef double snum_t;
10             #define SN_FLOOR floor
11             #define SN_CEIL ceil
12             #define SN_NV(sv) (SvNV(sv))
13             static snum_t PRECISION = 0.01;
14             static snum_t OFFSET = 0.5555555;
15 280           static int precision_places(snum_t prec) {
16 280           int places = 0;
17 280           snum_t p = prec;
18 565 100         while (p < 1.0) {
19 285           p *= 10.0;
20 285           places++;
21 285 50         if (places > 18) break;
22             }
23 280           return places;
24             }
25              
26 280           static SV *sn_to_sv(snum_t val) {
27             dTHX;
28 280           int places = precision_places(PRECISION);
29             char fmt[16];
30 280           snprintf(fmt, sizeof(fmt), "%%.%df", places);
31 280           char *num = Perl_form(fmt, val);
32 280           size_t len = strlen(num);
33 280           char *dot = strchr(num, '.');
34 280 100         if (dot) {
35 386 50         while (len > 1 && num[len - 1] == '0') {
    100          
36 197           num[--len] = '\0';
37             }
38 189 50         if (len > 0 && num[len - 1] == '.') {
    100          
39 126           num[--len] = '\0';
40             }
41             }
42 280           snum_t val_out = strtod(num, NULL);
43 280 100         if (val_out < val) {
44 32           return newSVnv(val);
45             }
46 248           return newSVpv(num, 0);
47             }
48              
49 155           static SV * new (snum_t num) {
50             dTHX;
51 155           return sv_bless(newRV_noinc(sn_to_sv(num)), gv_stashsv(newSVpv("smallnum::XS", 12), 0));
52             }
53              
54 162           static snum_t _sref (SV * n) {
55             dTHX;
56             snum_t num;
57 162 100         if (SvROK(n)) {
58 158           num = SN_NV(SvRV(n));
59             } else {
60 4           num = SN_NV(n);
61             }
62 162           return num;
63             }
64              
65             MODULE = smallnum::XS PACKAGE = smallnum::XS
66             PROTOTYPES: ENABLE
67             FALLBACK: TRUE
68              
69             SV * _smallnum (...)
70             CODE:
71 135           snum_t num = SN_NV(ST(0));
72 135           RETVAL = new(num);
73             OUTPUT:
74             RETVAL
75              
76             SV * _set_precision (num)
77             SV * num
78             CODE:
79 2           PRECISION = SN_NV(num);
80 2           RETVAL = sn_to_sv(PRECISION);
81             OUTPUT:
82             RETVAL
83              
84             SV * _set_offset (num)
85             SV * num
86             CODE:
87 1           OFFSET = SN_NV(num);
88 1           RETVAL = sn_to_sv(OFFSET);
89             OUTPUT:
90             RETVAL
91              
92             SV * _num (...)
93             OVERLOAD: \"\"
94             CODE:
95 122           snum_t num = _sref(ST(0));
96 122           snum_t out = num >= 0
97 121           ? PRECISION * SN_FLOOR((num + (OFFSET * PRECISION)) / PRECISION)
98 122 100         : PRECISION * SN_CEIL((num - OFFSET * PRECISION) / PRECISION);
99 122           RETVAL = sn_to_sv(out);
100             OUTPUT:
101             RETVAL
102              
103             SV * _divide (...)
104             OVERLOAD: /
105             CODE:
106 13           snum_t num1 = _sref(ST(0));
107 13           snum_t num2 = _sref(ST(1));
108 12 100         snum_t out = (num1 && num2)
109 7 100         ? (SvOK(ST(2)) && SvIV(ST(2)) > 0
110             ? num2 / num1
111 18 100         : num1 / num2)
112 25 100         : 0;
113 13           RETVAL = new(out);
114             OUTPUT:
115             RETVAL
116              
117             SV * _multiply (...)
118             OVERLOAD: *
119             CODE:
120 7           snum_t num1 = _sref(ST(0));
121 7           snum_t num2 = _sref(ST(1));
122 7           snum_t out = num2 * num1;
123 7           RETVAL = new(out);
124             OUTPUT:
125             RETVAL