1 // Copyright (c) 2009-2020 Vladimir Batov.
2 // Use, modification and distribution are subject to the Boost Software License,
3 // Version 1.0. See http://www.boost.org/LICENSE_1_0.txt.
4 
5 #ifndef BOOST_CONVERT_BASE_HPP
6 #define BOOST_CONVERT_BASE_HPP
7 
8 #include <boost/convert/parameters.hpp>
9 #include <boost/convert/detail/is_string.hpp>
10 #include <algorithm>
11 #include <cstring>
12 
13 namespace boost { namespace cnv
14 {
15     template<typename> struct cnvbase;
16 }}
17 
18 #define BOOST_CNV_TO_STRING                                                 \
19     template<typename string_type>                                          \
20     typename std::enable_if<cnv::is_string<string_type>::value, void>::type \
21     operator()
22 
23 #define BOOST_CNV_STRING_TO                                                 \
24     template<typename string_type>                                          \
25     typename std::enable_if<cnv::is_string<string_type>::value, void>::type \
26     operator()
27 
28 #define BOOST_CNV_PARAM_SET(param_name)   \
29     template <typename argument_pack>     \
30     void set_(                            \
31         argument_pack const& arg,         \
32         cnv::parameter::type::param_name, \
33         mpl::true_)
34 
35 #define BOOST_CNV_PARAM_TRY(param_name)     \
36     this->set_(                             \
37         arg,                                \
38         cnv::parameter::type::param_name(), \
39         typename mpl::has_key<              \
40             argument_pack, cnv::parameter::type::param_name>::type());
41 
42 template<typename derived_type>
43 struct boost::cnv::cnvbase
44 {
45     using   this_type = cnvbase;
46     using    int_type = int;
47     using   uint_type = unsigned int;
48     using   lint_type = long int;
49     using  ulint_type = unsigned long int;
50     using   sint_type = short int;
51     using  usint_type = unsigned short int;
52     using  llint_type = long long int;
53     using ullint_type = unsigned long long int;
54     using    flt_type = float;
55     using    dbl_type = double;
56     using   ldbl_type = long double;
57 
58     // Integration of user-types via operator>>()
59     template<typename type_in, typename type_out>
60     void
operator ()boost::cnv::cnvbase61     operator()(type_in const& in, boost::optional<type_out>& out) const
62     {
63         in >> out;
64     }
65 
66     // Basic type to string
BOOST_CNV_TO_STRINGboost::cnv::cnvbase67     BOOST_CNV_TO_STRING (   int_type v, optional<string_type>& r) const { to_str_(v, r); }
BOOST_CNV_TO_STRINGboost::cnv::cnvbase68     BOOST_CNV_TO_STRING (  uint_type v, optional<string_type>& r) const { to_str_(v, r); }
BOOST_CNV_TO_STRINGboost::cnv::cnvbase69     BOOST_CNV_TO_STRING (  lint_type v, optional<string_type>& r) const { to_str_(v, r); }
BOOST_CNV_TO_STRINGboost::cnv::cnvbase70     BOOST_CNV_TO_STRING ( llint_type v, optional<string_type>& r) const { to_str_(v, r); }
BOOST_CNV_TO_STRINGboost::cnv::cnvbase71     BOOST_CNV_TO_STRING ( ulint_type v, optional<string_type>& r) const { to_str_(v, r); }
BOOST_CNV_TO_STRINGboost::cnv::cnvbase72     BOOST_CNV_TO_STRING (ullint_type v, optional<string_type>& r) const { to_str_(v, r); }
BOOST_CNV_TO_STRINGboost::cnv::cnvbase73     BOOST_CNV_TO_STRING (  sint_type v, optional<string_type>& r) const { to_str_(v, r); }
BOOST_CNV_TO_STRINGboost::cnv::cnvbase74     BOOST_CNV_TO_STRING ( usint_type v, optional<string_type>& r) const { to_str_(v, r); }
BOOST_CNV_TO_STRINGboost::cnv::cnvbase75     BOOST_CNV_TO_STRING (   flt_type v, optional<string_type>& r) const { to_str_(v, r); }
BOOST_CNV_TO_STRINGboost::cnv::cnvbase76     BOOST_CNV_TO_STRING (   dbl_type v, optional<string_type>& r) const { to_str_(v, r); }
BOOST_CNV_TO_STRINGboost::cnv::cnvbase77     BOOST_CNV_TO_STRING (  ldbl_type v, optional<string_type>& r) const { to_str_(v, r); }
78     // String to basic type
BOOST_CNV_STRING_TOboost::cnv::cnvbase79     BOOST_CNV_STRING_TO (string_type const& s, optional<   int_type>& r) const { str_to_(s, r); }
BOOST_CNV_STRING_TOboost::cnv::cnvbase80     BOOST_CNV_STRING_TO (string_type const& s, optional<  uint_type>& r) const { str_to_(s, r); }
BOOST_CNV_STRING_TOboost::cnv::cnvbase81     BOOST_CNV_STRING_TO (string_type const& s, optional<  lint_type>& r) const { str_to_(s, r); }
BOOST_CNV_STRING_TOboost::cnv::cnvbase82     BOOST_CNV_STRING_TO (string_type const& s, optional< llint_type>& r) const { str_to_(s, r); }
BOOST_CNV_STRING_TOboost::cnv::cnvbase83     BOOST_CNV_STRING_TO (string_type const& s, optional< ulint_type>& r) const { str_to_(s, r); }
BOOST_CNV_STRING_TOboost::cnv::cnvbase84     BOOST_CNV_STRING_TO (string_type const& s, optional<ullint_type>& r) const { str_to_(s, r); }
BOOST_CNV_STRING_TOboost::cnv::cnvbase85     BOOST_CNV_STRING_TO (string_type const& s, optional<  sint_type>& r) const { str_to_(s, r); }
BOOST_CNV_STRING_TOboost::cnv::cnvbase86     BOOST_CNV_STRING_TO (string_type const& s, optional< usint_type>& r) const { str_to_(s, r); }
BOOST_CNV_STRING_TOboost::cnv::cnvbase87     BOOST_CNV_STRING_TO (string_type const& s, optional<   flt_type>& r) const { str_to_(s, r); }
BOOST_CNV_STRING_TOboost::cnv::cnvbase88     BOOST_CNV_STRING_TO (string_type const& s, optional<   dbl_type>& r) const { str_to_(s, r); }
BOOST_CNV_STRING_TOboost::cnv::cnvbase89     BOOST_CNV_STRING_TO (string_type const& s, optional<  ldbl_type>& r) const { str_to_(s, r); }
90 
91     template<typename argument_pack>
operator ()boost::cnv::cnvbase92     derived_type& operator()(argument_pack const& arg)
93     {
94         BOOST_CNV_PARAM_TRY(base);
95         BOOST_CNV_PARAM_TRY(adjust);
96         BOOST_CNV_PARAM_TRY(precision);
97         BOOST_CNV_PARAM_TRY(uppercase);
98         BOOST_CNV_PARAM_TRY(skipws);
99         BOOST_CNV_PARAM_TRY(width);
100         BOOST_CNV_PARAM_TRY(fill);
101 //      BOOST_CNV_PARAM_TRY(locale);
102 
103         return this->dncast();
104     }
105 
106     protected:
107 
cnvbaseboost::cnv::cnvbase108     cnvbase()
109     :
110         skipws_     (false),
111         precision_  (0),
112         uppercase_  (false),
113         width_      (0),
114         fill_       (' '),
115         base_       (boost::cnv::base::dec),
116         adjust_     (boost::cnv::adjust::right)
117     {}
118 
119     template<typename string_type, typename out_type>
120     void
str_to_boost::cnv::cnvbase121     str_to_(string_type const& str, optional<out_type>& result_out) const
122     {
123         cnv::range<string_type const> range (str);
124 
125         if (skipws_)
126             for (; !range.empty() && cnv::is_space(*range.begin()); ++range);
127 
128         if (range.empty())                 return;
129         if (cnv::is_space(*range.begin())) return;
130 
131         dncast().str_to(range, result_out);
132     }
133     template<typename in_type, typename string_type>
134     void
to_str_boost::cnv::cnvbase135     to_str_(in_type value_in, optional<string_type>& result_out) const
136     {
137         using  char_type = typename cnv::range<string_type>::value_type;
138         using range_type = cnv::range<char_type*>;
139         using   buf_type = char_type[bufsize_];
140 
141         buf_type     buf;
142         range_type range = dncast().to_str(value_in, buf);
143         char_type*   beg = range.begin();
144         char_type*   end = range.end();
145         int     str_size = end - beg;
146 
147         if (str_size <= 0)
148             return;
149 
150         if (uppercase_)
151             for (char_type* p = beg; p < end; ++p) *p = cnv::to_upper(*p);
152 
153         if (width_)
154         {
155             int  num_fill = (std::max)(0, int(width_ - (end - beg)));
156             int  num_left = adjust_ == cnv::adjust::left ? 0
157                           : adjust_ == cnv::adjust::right ? num_fill
158                           : (num_fill / 2);
159             int num_right = num_fill - num_left;
160             bool     move = (beg < buf + num_left) // No room for left fillers
161                          || (buf + bufsize_ < end + num_right); // No room for right fillers
162             if (move)
163             {
164                 std::memmove(buf + num_left, beg, str_size * sizeof(char_type));
165                 beg = buf + num_left;
166                 end = beg + str_size;
167             }
168             for (int k = 0; k <  num_left; *(--beg) = fill_, ++k);
169             for (int k = 0; k < num_right; *(end++) = fill_, ++k);
170         }
171         result_out = string_type(beg, end);
172     }
173 
dncastboost::cnv::cnvbase174     derived_type const& dncast () const { return *static_cast<derived_type const*>(this); }
dncastboost::cnv::cnvbase175     derived_type&       dncast ()       { return *static_cast<derived_type*>(this); }
176 
177     template<typename argument_pack, typename keyword_tag>
set_boost::cnv::cnvbase178     void set_(argument_pack const&, keyword_tag, mpl::false_) {}
179 
180     // Formatters
BOOST_CNV_PARAM_SETboost::cnv::cnvbase181     BOOST_CNV_PARAM_SET(base)      { base_      = arg[cnv::parameter::     base]; }
BOOST_CNV_PARAM_SETboost::cnv::cnvbase182     BOOST_CNV_PARAM_SET(adjust)    { adjust_    = arg[cnv::parameter::   adjust]; }
BOOST_CNV_PARAM_SETboost::cnv::cnvbase183     BOOST_CNV_PARAM_SET(precision) { precision_ = arg[cnv::parameter::precision]; }
BOOST_CNV_PARAM_SETboost::cnv::cnvbase184     BOOST_CNV_PARAM_SET(uppercase) { uppercase_ = arg[cnv::parameter::uppercase]; }
BOOST_CNV_PARAM_SETboost::cnv::cnvbase185     BOOST_CNV_PARAM_SET(skipws)    { skipws_    = arg[cnv::parameter::   skipws]; }
BOOST_CNV_PARAM_SETboost::cnv::cnvbase186     BOOST_CNV_PARAM_SET(width)     { width_     = arg[cnv::parameter::    width]; }
BOOST_CNV_PARAM_SETboost::cnv::cnvbase187     BOOST_CNV_PARAM_SET(fill)      { fill_      = arg[cnv::parameter::     fill]; }
188 //  BOOST_CNV_PARAM_SET(locale)    { locale_    = arg[cnv::parameter::   locale]; }
189 
190     // ULONG_MAX(8 bytes) = 18446744073709551615 (20(10) or 32(2) characters)
191     // double (8 bytes) max is 316 chars
192     static int BOOST_CONSTEXPR_OR_CONST bufsize_ = 512;
193 
194     bool        skipws_;
195     int      precision_;
196     bool     uppercase_;
197     int          width_;
198     int           fill_;
199     cnv::base     base_;
200     cnv::adjust adjust_;
201 //  std::locale locale_;
202 };
203 
204 #undef BOOST_CNV_TO_STRING
205 #undef BOOST_CNV_STRING_TO
206 #undef BOOST_CNV_PARAM_SET
207 #undef BOOST_CNV_PARAM_TRY
208 
209 #endif // BOOST_CONVERT_BASE_HPP
210