File indexing completed on 2025-01-18 09:30:28
0001
0002
0003
0004
0005 #ifndef BOOST_CONVERT_STRTOL_CONVERTER_HPP
0006 #define BOOST_CONVERT_STRTOL_CONVERTER_HPP
0007
0008 #include <boost/convert/base.hpp>
0009 #include <boost/math/special_functions/round.hpp>
0010 #include <limits>
0011 #include <climits>
0012 #include <cstdlib>
0013
0014 namespace boost { namespace cnv { struct strtol; }}
0015
0016
0017
0018
0019 struct boost::cnv::strtol : boost::cnv::cnvbase<boost::cnv::strtol>
0020 {
0021 using this_type = boost::cnv::strtol;
0022 using base_type = boost::cnv::cnvbase<this_type>;
0023
0024 using base_type::operator();
0025
0026 private:
0027
0028 friend struct boost::cnv::cnvbase<this_type>;
0029
0030 template<typename string_type> void str_to(cnv::range<string_type> v, optional< int_type>& r) const { str_to_i (v, r); }
0031 template<typename string_type> void str_to(cnv::range<string_type> v, optional< sint_type>& r) const { str_to_i (v, r); }
0032 template<typename string_type> void str_to(cnv::range<string_type> v, optional< lint_type>& r) const { str_to_i (v, r); }
0033 template<typename string_type> void str_to(cnv::range<string_type> v, optional< llint_type>& r) const { str_to_i (v, r); }
0034 template<typename string_type> void str_to(cnv::range<string_type> v, optional< uint_type>& r) const { str_to_i (v, r); }
0035 template<typename string_type> void str_to(cnv::range<string_type> v, optional< usint_type>& r) const { str_to_i (v, r); }
0036 template<typename string_type> void str_to(cnv::range<string_type> v, optional< ulint_type>& r) const { str_to_i (v, r); }
0037 template<typename string_type> void str_to(cnv::range<string_type> v, optional<ullint_type>& r) const { str_to_i (v, r); }
0038 template<typename string_type> void str_to(cnv::range<string_type> v, optional< flt_type>& r) const { str_to_d (v, r); }
0039 template<typename string_type> void str_to(cnv::range<string_type> v, optional< dbl_type>& r) const { str_to_d (v, r); }
0040 template<typename string_type> void str_to(cnv::range<string_type> v, optional< ldbl_type>& r) const { str_to_d (v, r); }
0041
0042 template <typename char_type> cnv::range<char_type*> to_str ( int_type v, char_type* buf) const { return i_to_str(v, buf); }
0043 template <typename char_type> cnv::range<char_type*> to_str ( uint_type v, char_type* buf) const { return i_to_str(v, buf); }
0044 template <typename char_type> cnv::range<char_type*> to_str ( lint_type v, char_type* buf) const { return i_to_str(v, buf); }
0045 template <typename char_type> cnv::range<char_type*> to_str ( ulint_type v, char_type* buf) const { return i_to_str(v, buf); }
0046 template <typename char_type> cnv::range<char_type*> to_str ( llint_type v, char_type* buf) const { return i_to_str(v, buf); }
0047 template <typename char_type> cnv::range<char_type*> to_str (ullint_type v, char_type* buf) const { return i_to_str(v, buf); }
0048 template <typename char_type> cnv::range<char_type*> to_str ( dbl_type v, char_type* buf) const;
0049
0050 template<typename char_type, typename in_type> cnv::range<char_type*> i_to_str (in_type, char_type*) const;
0051 template<typename string_type, typename out_type> void str_to_i (cnv::range<string_type>, optional<out_type>&) const;
0052 template<typename string_type, typename out_type> void str_to_d (cnv::range<string_type>, optional<out_type>&) const;
0053
0054 static double adjust_fraction (double, int);
0055 static int get_char (int v) { return (v < 10) ? (v += '0') : (v += 'A' - 10); }
0056 };
0057
0058 template<typename char_type, typename Type>
0059 boost::cnv::range<char_type*>
0060 boost::cnv::strtol::i_to_str(Type in_value, char_type* buf) const
0061 {
0062
0063
0064 using unsigned_type = typename std::make_unsigned<Type>::type;
0065
0066 char_type* beg = buf + bufsize_ / 2;
0067 char_type* end = beg;
0068 bool const is_neg = std::is_signed<Type>::value && in_value < 0;
0069 unsigned_type value = static_cast<unsigned_type>(is_neg ? -in_value : in_value);
0070 int base = int(base_);
0071
0072 if (base == 10) for (; value; *(--beg) = int(value % 10) + '0', value /= 10);
0073 else for (; value; *(--beg) = get_char(value % base), value /= base);
0074
0075 if (beg == end) *(--beg) = '0';
0076 if (is_neg) *(--beg) = '-';
0077
0078 return cnv::range<char_type*>(beg, end);
0079 }
0080
0081 inline
0082 double
0083 boost::cnv::strtol::adjust_fraction(double fraction, int precision)
0084 {
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097 int const tens[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000 };
0098
0099 for (int k = precision / 8; k; --k) fraction *= 100000000;
0100
0101 fraction *= tens[precision % 8];
0102
0103
0104 return boost::math::round(fraction);
0105 }
0106
0107 template <typename char_type>
0108 inline
0109 boost::cnv::range<char_type*>
0110 boost::cnv::strtol::to_str(double value, char_type* buf) const
0111 {
0112 char_type* beg = buf + bufsize_ / 2;
0113 char_type* end = beg;
0114 char_type* ipos = end - 1;
0115 bool is_negative = (value < 0) ? (value = -value, true) : false;
0116 double ipart = std::floor(value);
0117 double fpart = adjust_fraction(value - ipart, precision_);
0118 int precision = precision_;
0119 int const base = 10;
0120
0121 for (; 1 <= ipart; ipart /= base)
0122 *(--beg) = get_char(int(ipart - std::floor(ipart / base) * base));
0123
0124 if (beg == end) *(--beg) = '0';
0125 if (precision) *(end++) = '.';
0126
0127 for (char_type* fpos = end += precision; precision; --precision, fpart /= base)
0128 *(--fpos) = get_char(int(fpart - std::floor(fpart / base) * base));
0129
0130 if (1 <= fpart)
0131 {
0132 for (; beg <= ipos; --ipos)
0133 if (*ipos == '9') *ipos = '0';
0134 else { ++*ipos; break; }
0135
0136 if (ipos < beg)
0137 *(beg = ipos) = '1';
0138 }
0139 if (is_negative) *(--beg) = '-';
0140
0141 return cnv::range<char_type*>(beg, end);
0142 }
0143
0144 template<typename string_type, typename out_type>
0145 void
0146 boost::cnv::strtol::str_to_i(cnv::range<string_type> range, boost::optional<out_type>& result_out) const
0147 {
0148 using uint_type = unsigned int;
0149 using unsigned_type = typename std::make_unsigned<out_type>::type;
0150 using range_type = cnv::range<string_type>;
0151 using iterator = typename range_type::iterator;
0152
0153 iterator s = range.begin();
0154 uint_type ch = *s;
0155 bool is_negative = ch == '-' ? (ch = *++s, true) : ch == '+' ? (ch = *++s, false) : false;
0156 bool is_unsigned = std::is_same<out_type, unsigned_type>::value;
0157 uint_type base = uint_type(base_);
0158
0159 if (is_negative && is_unsigned) return;
0160 else if ((base == 0 || base == 16) && ch == '0' && (*++s == 'x' || *s == 'X')) ++s, base = 16;
0161 else if (base == 0) base = ch == '0' ? (++s, 8) : 10;
0162
0163 unsigned_type max = (std::numeric_limits<out_type>::max)();
0164 unsigned_type umax = max + (is_negative ? 1 : 0);
0165 unsigned_type cutoff = umax / base;
0166 uint_type cutlim = umax % base;
0167 unsigned_type result = 0;
0168
0169 for (; s != range.sentry(); ++s)
0170 {
0171 ch = *s;
0172
0173 if (std::isdigit(ch)) ch -= '0';
0174 else if (std::isalpha(ch)) ch -= (std::isupper(ch) ? 'A' : 'a') - 10;
0175 else return;
0176
0177 if (base <= ch || cutoff < result || (result == cutoff && cutlim < ch))
0178 return;
0179
0180 result *= base;
0181 result += ch;
0182 }
0183 result_out = is_negative ? -out_type(result) : out_type(result);
0184 }
0185
0186 template<typename string_type, typename out_type>
0187 void
0188 boost::cnv::strtol::str_to_d(cnv::range<string_type> range, optional<out_type>& result_out) const
0189 {
0190
0191
0192
0193
0194
0195 using range_type = cnv::range<string_type>;
0196 using ch_type = typename range_type::value_type;
0197
0198 size_t const sz = 128;
0199 ch_type str[sz] = {0}; std::strncpy(str, &*range.begin(), (std::min)(sz - 1, range.size()));
0200 char* cnv_end = 0;
0201 ldbl_type result = strtold(str, &cnv_end);
0202 bool good = result != -HUGE_VALL && result != HUGE_VALL && *cnv_end == 0;
0203 out_type max = (std::numeric_limits<out_type>::max)();
0204
0205 if (good && -max <= result && result <= max)
0206 result_out = out_type(result);
0207 }
0208
0209 #endif