File Coverage

src/panda/from_chars.cc
Criterion Covered Total %
statement 91 98 92.8
branch 254 346 73.4
condition n/a
subroutine n/a
pod n/a
total 345 444 77.7


line stmt bran cond sub pod time code
1             #include "from_chars.h"
2             #include // isspace
3             #include // memcpy
4             #include
5              
6             namespace panda {
7              
8             static unsigned _index[256];
9             static char _rindex[36];
10              
11 18           static bool _init () {
12 4626 100         for (auto& val : _index) val = 255;
13 198 100         for (int i = 0; i <= 9; ++i) _index['0' + i] = i;
14 486 100         for (int i = 0; i <= 25; ++i) _index['a' + i] = i+10;
15 486 100         for (int i = 0; i <= 25; ++i) _index['A' + i] = i+10;
16 198 100         for (int i = 0; i <= 9; ++i) _rindex[i] = '0' + i;
17 486 100         for (int i = 0; i <= 25; ++i) _rindex[i + 10] = 'a' + i;
18 18           return true;
19             }
20 18           static const bool _inited = _init();
21              
22 758           static inline bool _is_space (unsigned char ch) { return std::isspace(ch); }
23             //static inline bool _is_space (unsigned wchar_t ch) { return std::iswspace(ch); }
24              
25             template
26             static inline bool _find_sign (const C*& ptr, const C* const end) {
27             if (ptr == end) return false;
28              
29             bool minus = false;
30             if (*ptr == '-') { ++ptr; minus = true; }
31             else if (*ptr == '+') ++ptr;
32              
33             return minus;
34             }
35              
36             template
37 223           static inline UT _parse (const UC*& ptr, const UC* const end, unsigned base, UT max, bool& overflow) {
38 223           UT res = 0;
39 223           UT maxmp = max / base;
40 223           overflow = false;
41              
42 909 0         for (; ptr != end; ++ptr) {
    100          
    100          
    100          
    100          
43             if (sizeof(UC) > 1 && *ptr > 255) break;
44 792           auto val = _index[*ptr];
45 792 0         if (val >= base) break;
    100          
    100          
    100          
    100          
46 718 0         if (res > maxmp) { overflow = true; res = max; break; }
    100          
    100          
    100          
    100          
47 702           res *= base;
48 702 0         if (val > (UT)(max - res)) { overflow = true; res = max; break; }
    100          
    100          
    100          
    100          
49 686           res += val;
50             }
51              
52 1050 0         if (overflow) for (; ptr != end; ++ptr) if ((sizeof(UC) > 1 && *ptr > 255) || _index[*ptr] >= base) break; // move to the end of the number
    0          
    0          
    100          
    100          
    50          
    100          
    100          
    50          
    100          
    100          
    50          
    100          
    100          
    50          
53              
54 223           return res;
55             }
56              
57             template
58 99           static inline typename std::enable_if::value, from_chars_result>::type _from_chars (const C* s, const C* send, UT& value, unsigned base) {
59             using UC = typename std::make_unsigned::type;
60 99           const UC* ptr = (const UC*)s;
61 99           const UC* const end = (const UC*)send;
62 99 0         if (base < 2 || base > 36) base = 10;
    0          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
63              
64 155 0         while (ptr != end && _is_space(*ptr)) ++ptr; // skip whitespaces in the beginning
    0          
    0          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
65              
66             bool overflow;
67 99           auto tmp = ptr;
68 99           value = _parse(ptr, end, base, std::numeric_limits::max(), overflow);
69              
70 99 0         if (ptr - tmp == 0) return {s, make_error_code(std::errc::invalid_argument)};
    100          
    100          
    100          
    100          
71 74 0         if (overflow) return {(const C*)ptr, make_error_code(std::errc::result_out_of_range)};
    100          
    100          
    100          
    100          
72 99           return {(const C*)ptr, std::error_code()};
73             }
74              
75             template
76 124           static inline typename std::enable_if::value, from_chars_result>::type _from_chars (const C* s, const C* send, T& value, unsigned base) {
77             using UC = typename std::make_unsigned::type;
78             using UT = typename std::make_unsigned::type;
79 124           const UC* ptr = (const UC*)s;
80 124           const UC* const end = (const UC*)send;
81 124 0         if (base < 2 || base > 36) base = 10;
    0          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
82              
83 232 0         while (ptr != end && _is_space(*ptr)) ++ptr; // skip whitespaces in the beginning
    0          
    0          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
84              
85 124           bool minus = false;
86 124 0         if (ptr != end && *ptr == '-') { ++ptr; minus = true; }
    0          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
87             bool overflow;
88 124           auto tmp = ptr;
89              
90 124 0         if (minus) {
    100          
    100          
    100          
    100          
91 48           UT max = (UT)std::numeric_limits::max() - (T)(std::numeric_limits::max() + std::numeric_limits::min());
92 48           UT tmp = _parse(ptr, end, base, max, overflow);
93 48           value = (T)0 - tmp;
94             } else {
95 76           value = _parse(ptr, end, base, (UT)std::numeric_limits::max(), overflow);
96             }
97              
98 124 0         if (ptr - tmp == 0) return {s, make_error_code(std::errc::invalid_argument)};
    100          
    100          
    100          
    100          
99 108 0         if (overflow) return {(const C*)ptr, make_error_code(std::errc::result_out_of_range)};
    100          
    100          
    100          
    100          
100 124           return {(const C*)ptr, std::error_code()};
101             }
102              
103 62           from_chars_result from_chars (const char* first, const char* last, int8_t& value, int base) { return _from_chars (first, last, value, base); }
104 62           from_chars_result from_chars (const char* first, const char* last, int16_t& value, int base) { return _from_chars (first, last, value, base); }
105 62           from_chars_result from_chars (const char* first, const char* last, int& value, int base) { return _from_chars (first, last, value, base); }
106 62           from_chars_result from_chars (const char* first, const char* last, long& value, int base) { return _from_chars (first, last, value, base); }
107 0           from_chars_result from_chars (const char* first, const char* last, long long& value, int base) { return _from_chars (first, last, value, base); }
108 46           from_chars_result from_chars (const char* first, const char* last, uint8_t& value, int base) { return _from_chars (first, last, value, base); }
109 46           from_chars_result from_chars (const char* first, const char* last, uint16_t& value, int base) { return _from_chars (first, last, value, base); }
110 46           from_chars_result from_chars (const char* first, const char* last, unsigned& value, int base) { return _from_chars (first, last, value, base); }
111 60           from_chars_result from_chars (const char* first, const char* last, unsigned long& value, int base) { return _from_chars (first, last, value, base); }
112 0           from_chars_result from_chars (const char* first, const char* last, unsigned long long& value, int base) { return _from_chars(first, last, value, base); }
113              
114             template
115 51           static inline C* _compile (C* ptr, UT value, int base) {
116 152 0         do {
    0          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
117 152           *--ptr = _rindex[value % base];
118 152           value /= base;
119             } while (value != 0);
120 51           return ptr;
121             }
122              
123             template
124 24           static inline typename std::enable_if::value, to_chars_result>::type _to_chars (C* d, C* dend, UT value, int base) {
125 24 0         if (base < 2 || base > 36) base = 10;
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
126 24           int maxsize = std::ceil(std::numeric_limits::digits * log(2) / log(base)); /* enough for UT-bit integer represented in given base */
127 24           char strval[maxsize];
128 24           char* end = strval + maxsize;
129 24           char* begin = _compile(end, value, base);
130 24           auto len = end - begin;
131 24 0         if (dend - d < len) return {dend, make_error_code(std::errc::value_too_large)};
    100          
    100          
    100          
    100          
132 20           std::memcpy(d, begin, len);
133 24           return {d + len, std::error_code()};
134             }
135              
136             template
137 27           static inline typename std::enable_if::value, to_chars_result>::type _to_chars (C* d, C* dend, T value, int base) {
138             using UT = typename std::make_unsigned::type;
139 27 0         if (base < 2 || base > 36) base = 10;
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
140 27           int maxsize = std::ceil(std::numeric_limits::digits * log(2) / log(base) + 1);
141 27           char strval[maxsize];
142 27           char* end = strval + maxsize;
143             char* begin;
144              
145 27 0         if (value >= 0) begin = _compile(end, value, base);
    50          
    50          
    50          
    50          
146             else {
147 0           UT positive_value = (UT)std::numeric_limits::max() - (T)(std::numeric_limits::max() + value);
148 0           begin = _compile(end, positive_value, base);
149 0           *--begin = '-';
150             }
151              
152 27           auto len = end - begin;
153 27 0         if (dend - d < len) return {dend, make_error_code(std::errc::value_too_large)};
    100          
    100          
    100          
    100          
154 23           std::memcpy(d, begin, len);
155 27           return {d + len, std::error_code()};
156             }
157              
158 12           to_chars_result to_chars (char* first, char* last, int8_t value, int base) { return _to_chars (first, last, value, base); }
159 12           to_chars_result to_chars (char* first, char* last, int16_t value, int base) { return _to_chars (first, last, value, base); }
160 18           to_chars_result to_chars (char* first, char* last, int value, int base) { return _to_chars (first, last, value, base); }
161 12           to_chars_result to_chars (char* first, char* last, long value, int base) { return _to_chars (first, last, value, base); }
162 0           to_chars_result to_chars (char* first, char* last, long long value, int base) { return _to_chars (first, last, value, base); }
163 12           to_chars_result to_chars (char* first, char* last, uint8_t value, int base) { return _to_chars (first, last, value, base); }
164 12           to_chars_result to_chars (char* first, char* last, uint16_t value, int base) { return _to_chars(first, last, value, base); }
165 12           to_chars_result to_chars (char* first, char* last, unsigned value, int base) { return _to_chars(first, last, value, base); }
166 12           to_chars_result to_chars (char* first, char* last, unsigned long value, int base) { return _to_chars(first, last, value, base); }
167 0           to_chars_result to_chars (char* first, char* last, unsigned long long value, int base) { return _to_chars(first, last, value, base); }
168              
169 72 50         }
    50