1 | /// @file |
2 | // Boost.Convert |
3 | // Copyright (c) 2009-2014 Vladimir Batov. |
4 | // |
5 | // Many thanks to Julian Gonggrijp, Rob Stewart, Andrzej Krzemienski, Matus Chochlik, Jeroen Habraken, |
6 | // Hartmut Kaiser, Joel De Guzman, Thijs (M.A.) van den Berg, Roland Bock, Gavin Lambert, Paul Bristow, |
7 | // Alex Hagen-Zanker, Christopher Kormanyos for taking part in the Boost.Convert review. |
8 | // |
9 | // Special thanks to: |
10 | // |
11 | // 1. Alex Hagen-Zanker, Roland Bock, Rob Stewart for their considerable contributions to the design |
12 | // and implementation of the library; |
13 | // 2. Andrzej Krzemienski for helping to partition responsibilities and to ultimately pave |
14 | // the way for the boost::optional and future std::tr2::optional deployment; |
15 | // 3. Edward Diener the Boost Review Manager for helping with the converters' design, his continuous |
16 | // involvement, technical and administrative help, guidance and advice; |
17 | // 4. Joel De Guzman, Rob Stewart and Alex Hagen-Zanker for making sure the performance tests work |
18 | // as they should; |
19 | // 5. Paul Bristow for helping great deal with the documentation; |
20 | // 6. Kevlin Henney and Dave Abrahams for their lexical_cast-related insights and explanations. |
21 | // |
22 | // Use, modification and distribution are subject to the Boost Software License, |
23 | // Version 1.0. See http://www.boost.org/LICENSE_1_0.txt. |
24 | |
25 | #ifndef BOOST_CONVERT_HPP |
26 | #define BOOST_CONVERT_HPP |
27 | |
28 | #include <boost/convert/detail/is_fun.hpp> |
29 | #include <boost/ref.hpp> |
30 | |
31 | namespace boost |
32 | { |
33 | namespace detail { enum throw_on_failure {}; } |
34 | |
35 | /// @details The boost::throw_on_failure is the name of an object of the |
36 | /// boost::detail::throw_on_failure type that is used to indicate |
37 | /// desired exception-throwing behavior. |
38 | detail::throw_on_failure const throw_on_failure = detail::throw_on_failure(0); |
39 | |
40 | namespace cnv |
41 | { |
42 | template<typename, typename, typename> struct reference; |
43 | struct by_default; |
44 | } |
45 | |
46 | /// @brief Boost.Convert main deployment interface |
47 | /// @param[in] value_in Value of the TypeIn type to be converted to the TyeOut type |
48 | /// @param[in] converter Converter to be used for conversion |
49 | /// @return boost::optional<TypeOut> result of conversion together with the indication of |
50 | /// success or failure of the conversion request. |
51 | /// @details For example, |
52 | /// @code |
53 | /// boost::cnv::cstream cnv; |
54 | /// |
55 | /// boost::optional<int> i = boost::convert<int>("12", cnv); |
56 | /// boost::optional<string> s = boost::convert<string>(123.456, cnv); |
57 | /// @endcode |
58 | |
59 | template<typename TypeOut, typename TypeIn, typename Converter> |
60 | boost::optional<TypeOut> |
61 | convert(TypeIn const& value_in, Converter const& converter) |
62 | { |
63 | optional<TypeOut> result; |
64 | boost::unwrap_ref(converter)(value_in, result); |
65 | return result; |
66 | } |
67 | |
68 | namespace cnv { namespace detail |
69 | { |
70 | template<typename TypeOut, typename TypeIn, typename Converter =boost::cnv::by_default> |
71 | struct delayed_resolution |
72 | { |
73 | static optional<TypeOut> convert(TypeIn const& value_in) |
74 | { |
75 | return boost::convert<TypeOut>(value_in, Converter()); |
76 | } |
77 | }; |
78 | }} |
79 | /// @brief Boost.Convert deployment interface with the default converter |
80 | /// @details For example, |
81 | /// @code |
82 | /// struct boost::cnv::by_default : public boost::cnv::cstream {}; |
83 | /// |
84 | /// // boost::cnv::cstream (through boost::cnv::by_default) is deployed |
85 | /// // as the default converter when no converter is provided explicitly. |
86 | /// boost::optional<int> i = boost::convert<int>("12"); |
87 | /// boost::optional<string> s = boost::convert<string>(123.456); |
88 | /// @endcode |
89 | |
90 | template<typename TypeOut, typename TypeIn> |
91 | boost::optional<TypeOut> |
92 | convert(TypeIn const& value_in) |
93 | { |
94 | return cnv::detail::delayed_resolution<TypeOut, TypeIn>::convert(value_in); |
95 | } |
96 | } |
97 | |
98 | namespace boost |
99 | { |
100 | /// @brief Boost.Convert non-optional deployment interface |
101 | |
102 | template<typename TypeOut, typename TypeIn, typename Converter> |
103 | TypeOut |
104 | convert(TypeIn const& value_in, Converter const& converter, boost::detail::throw_on_failure) |
105 | { |
106 | return convert<TypeOut>(value_in, converter).value(); |
107 | } |
108 | |
109 | template<typename TypeOut, typename TypeIn, typename Converter, typename Fallback> |
110 | typename enable_if<is_convertible<Fallback, TypeOut>, TypeOut>::type |
111 | convert(TypeIn const& value_in, Converter const& converter, Fallback const& fallback) |
112 | { |
113 | return convert<TypeOut>(value_in, converter).value_or(fallback); |
114 | } |
115 | |
116 | template<typename TypeOut, typename TypeIn, typename Converter, typename Fallback> |
117 | typename enable_if<cnv::is_fun<Fallback, TypeOut>, TypeOut>::type |
118 | convert(TypeIn const& value_in, Converter const& converter, Fallback fallback) |
119 | { |
120 | return convert<TypeOut>(value_in, converter).value_or_eval(fallback); |
121 | } |
122 | } |
123 | |
124 | namespace boost { namespace cnv |
125 | { |
126 | template<typename Converter, typename TypeOut, typename TypeIn> |
127 | struct reference |
128 | { |
129 | typedef reference this_type; |
130 | |
131 | reference(Converter const& cnv) : converter_(cnv) {} |
132 | |
133 | #ifdef BOOST_CONVERT_CXX11 |
134 | reference(Converter&& cnv) : converter_(std::move(cnv)) {} |
135 | #endif |
136 | |
137 | this_type& |
138 | value_or(TypeOut const& fallback) |
139 | { |
140 | return (fallback_ = fallback, *this); |
141 | } |
142 | |
143 | TypeOut |
144 | operator()(TypeIn const& value_in) |
145 | { |
146 | optional<TypeOut> result = convert<TypeOut>(value_in, converter_); |
147 | return result ? result.get() : fallback_.value(); |
148 | } |
149 | |
150 | private: |
151 | |
152 | Converter converter_; |
153 | optional<TypeOut> fallback_; |
154 | }; |
155 | template<typename Converter, typename TypeOut> |
156 | struct reference<Converter, TypeOut, void> |
157 | { |
158 | typedef reference this_type; |
159 | |
160 | reference(Converter const& cnv) : converter_(cnv) {} |
161 | |
162 | #ifdef BOOST_CONVERT_CXX11 |
163 | reference(Converter&& cnv) : converter_(std::move(cnv)) {} |
164 | #endif |
165 | |
166 | this_type& |
167 | value_or(TypeOut const& fallback) |
168 | { |
169 | return (fallback_ = fallback, *this); |
170 | } |
171 | |
172 | template<typename TypeIn> |
173 | TypeOut |
174 | operator()(TypeIn const& value_in) |
175 | { |
176 | optional<TypeOut> result = convert<TypeOut>(value_in, converter_); |
177 | return result ? result.get() : fallback_.value(); |
178 | } |
179 | |
180 | private: |
181 | |
182 | Converter converter_; |
183 | optional<TypeOut> fallback_; |
184 | }; |
185 | |
186 | /// @brief Boost.Convert deployment interface with algorithms |
187 | /// @details For example, |
188 | /// @code |
189 | /// boost::array<char const*, 3> strs = {{ " 5", "0XF", "not an int" }}; |
190 | /// std::vector<int> ints; |
191 | /// boost::cnv::cstream cnv; |
192 | /// |
193 | /// cnv(std::hex)(std::skipws); |
194 | /// |
195 | /// std::transform( |
196 | /// strs.begin(), |
197 | /// strs.end(), |
198 | /// std::back_inserter(ints), |
199 | /// boost::cnv::apply<int>(boost::cref(cnv)).value_or(-1)); |
200 | /// @endcode |
201 | |
202 | template<typename TypeOut, typename TypeIn, typename Converter> |
203 | reference<Converter, TypeOut, TypeIn> |
204 | apply(Converter const& cnv) |
205 | { |
206 | return cnv::reference<Converter, TypeOut, TypeIn>(cnv); |
207 | } |
208 | template<typename TypeOut, typename Converter> |
209 | reference<Converter, TypeOut, void> |
210 | apply(Converter const& cnv) |
211 | { |
212 | return cnv::reference<Converter, TypeOut, void>(cnv); |
213 | } |
214 | }} |
215 | |
216 | #endif // BOOST_CONVERT_HPP |
217 | |