Line data Source code
1 : // Copyright Kevlin Henney, 2000-2005.
2 : // Copyright Alexander Nasonov, 2006-2010.
3 : // Copyright Antony Polukhin, 2011-2025.
4 : //
5 : // Distributed under the Boost Software License, Version 1.0. (See
6 : // accompanying file LICENSE_1_0.txt or copy at
7 : // http://www.boost.org/LICENSE_1_0.txt)
8 : //
9 : // what: lexical_cast custom keyword cast
10 : // who: contributed by Kevlin Henney,
11 : // enhanced with contributions from Terje Slettebo,
12 : // with additional fixes and suggestions from Gennaro Prota,
13 : // Beman Dawes, Dave Abrahams, Daryle Walker, Peter Dimov,
14 : // Alexander Nasonov, Antony Polukhin, Justin Viiret, Michael Hofmann,
15 : // Cheng Yang, Matthew Bradbury, David W. Birdsall, Pavel Korzh and other Boosters
16 : // when: November 2000, March 2003, June 2005, June 2006, March 2011 - 2014
17 :
18 : #ifndef BOOST_LEXICAL_CAST_DETAIL_CONVERTER_LEXICAL_HPP
19 : #define BOOST_LEXICAL_CAST_DETAIL_CONVERTER_LEXICAL_HPP
20 :
21 : #include <boost/config.hpp>
22 : #ifdef BOOST_HAS_PRAGMA_ONCE
23 : # pragma once
24 : #endif
25 :
26 : #if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_WSTRING)
27 : #define BOOST_LCAST_NO_WCHAR_T
28 : #endif
29 :
30 : #include <cstddef>
31 : #include <string>
32 : #include <type_traits>
33 : #include <boost/limits.hpp>
34 : #include <boost/detail/lcast_precision.hpp>
35 :
36 : #include <boost/lexical_cast/detail/widest_char.hpp>
37 : #include <boost/lexical_cast/detail/is_character.hpp>
38 : #include <boost/lexical_cast/detail/type_traits.hpp>
39 :
40 : #include <array>
41 :
42 : #ifndef BOOST_NO_CXX17_HDR_STRING_VIEW
43 : #include <string_view>
44 : #endif
45 :
46 : #include <boost/lexical_cast/detail/buffer_view.hpp>
47 : #include <boost/container/container_fwd.hpp>
48 :
49 : #include <boost/lexical_cast/detail/converter_lexical_streams.hpp>
50 :
51 : namespace boost {
52 :
53 : // Forward declaration
54 : template<class T, std::size_t N>
55 : class array;
56 : template<class IteratorT>
57 : class iterator_range;
58 :
59 : // Forward declaration of boost::basic_string_view from Utility
60 : template<class Ch, class Tr> class basic_string_view;
61 :
62 : namespace detail // normalize_single_byte_char<Char>
63 : {
64 : // Converts signed/unsigned char to char
65 : template < class Char >
66 : struct normalize_single_byte_char
67 : {
68 : using type = Char;
69 : };
70 :
71 : template <>
72 : struct normalize_single_byte_char< signed char >
73 : {
74 : using type = char;
75 : };
76 :
77 : template <>
78 : struct normalize_single_byte_char< unsigned char >
79 : {
80 : using type = char;
81 : };
82 : }
83 :
84 : namespace detail // deduce_character_type_later<T>
85 : {
86 : // Helper type, meaning that stram character for T must be deduced
87 : // at Stage 2 (See deduce_source_char<T> and deduce_target_char<T>)
88 : template < class T > struct deduce_character_type_later {};
89 : }
90 :
91 : namespace detail // stream_char_common<T>
92 : {
93 : // Selectors to choose stream character type (common for Source and Target)
94 : // Returns one of char, wchar_t, char16_t, char32_t or deduce_character_type_later<T> types
95 : // Executed on Stage 1 (See deduce_source_char<T> and deduce_target_char<T>)
96 : template < typename Type >
97 : struct stream_char_common: public std::conditional<
98 : boost::detail::is_character< Type >::value,
99 : Type,
100 : boost::detail::deduce_character_type_later< Type >
101 : > {};
102 :
103 : template < typename Char >
104 : struct stream_char_common< Char* >: public std::conditional<
105 : boost::detail::is_character< Char >::value,
106 : Char,
107 : boost::detail::deduce_character_type_later< Char* >
108 : > {};
109 :
110 : template < typename Char >
111 : struct stream_char_common< const Char* >: public std::conditional<
112 : boost::detail::is_character< Char >::value,
113 : Char,
114 : boost::detail::deduce_character_type_later< const Char* >
115 : > {};
116 :
117 : template < typename Char >
118 : struct stream_char_common< boost::conversion::detail::buffer_view< Char > >
119 : {
120 : using type = Char;
121 : };
122 :
123 : template < typename Char >
124 : struct stream_char_common< boost::iterator_range< Char* > >: public std::conditional<
125 : boost::detail::is_character< Char >::value,
126 : Char,
127 : boost::detail::deduce_character_type_later< boost::iterator_range< Char* > >
128 : > {};
129 :
130 : template < typename Char >
131 : struct stream_char_common< boost::iterator_range< const Char* > >: public std::conditional<
132 : boost::detail::is_character< Char >::value,
133 : Char,
134 : boost::detail::deduce_character_type_later< boost::iterator_range< const Char* > >
135 : > {};
136 :
137 : template < class Char, class Traits, class Alloc >
138 : struct stream_char_common< std::basic_string< Char, Traits, Alloc > >
139 : {
140 : using type = Char;
141 : };
142 :
143 : template < class Char, class Traits, class Alloc >
144 : struct stream_char_common< boost::container::basic_string< Char, Traits, Alloc > >
145 : {
146 : using type = Char;
147 : };
148 :
149 : template < typename Char, std::size_t N >
150 : struct stream_char_common< boost::array< Char, N > >: public std::conditional<
151 : boost::detail::is_character< Char >::value,
152 : Char,
153 : boost::detail::deduce_character_type_later< boost::array< Char, N > >
154 : > {};
155 :
156 : template < typename Char, std::size_t N >
157 : struct stream_char_common< boost::array< const Char, N > >: public std::conditional<
158 : boost::detail::is_character< Char >::value,
159 : Char,
160 : boost::detail::deduce_character_type_later< boost::array< const Char, N > >
161 : > {};
162 :
163 : #ifndef BOOST_NO_CXX11_HDR_ARRAY
164 : template < typename Char, std::size_t N >
165 : struct stream_char_common< std::array<Char, N > >: public std::conditional<
166 : boost::detail::is_character< Char >::value,
167 : Char,
168 : boost::detail::deduce_character_type_later< std::array< Char, N > >
169 : > {};
170 :
171 : template < typename Char, std::size_t N >
172 : struct stream_char_common< std::array< const Char, N > >: public std::conditional<
173 : boost::detail::is_character< Char >::value,
174 : Char,
175 : boost::detail::deduce_character_type_later< std::array< const Char, N > >
176 : > {};
177 : #endif
178 :
179 : #ifndef BOOST_NO_CXX17_HDR_STRING_VIEW
180 : template < class Char, class Traits >
181 : struct stream_char_common< std::basic_string_view< Char, Traits > >
182 : {
183 : using type = Char;
184 : };
185 : #endif
186 : template < class Char, class Traits >
187 : struct stream_char_common< boost::basic_string_view< Char, Traits > >
188 : {
189 : using type = Char;
190 : };
191 :
192 : #ifdef BOOST_HAS_INT128
193 : template <> struct stream_char_common< boost::int128_type >
194 : {
195 : using type = char;
196 : };
197 : template <> struct stream_char_common< boost::uint128_type >
198 : {
199 : using type = char;
200 : };
201 : #endif
202 :
203 : #if !defined(BOOST_LCAST_NO_WCHAR_T) && defined(BOOST_NO_INTRINSIC_WCHAR_T)
204 : template <>
205 : struct stream_char_common< wchar_t >
206 : {
207 : using type = char;
208 : };
209 : #endif
210 : }
211 :
212 : namespace detail // deduce_source_char_impl<T>
213 : {
214 : // If type T is `deduce_character_type_later` type, then tries to deduce
215 : // character type using streaming metafunctions.
216 : // Otherwise supplied type T is a character type, that must be normalized
217 : // using normalize_single_byte_char<Char>.
218 : // Executed at Stage 2 (See deduce_source_char<T> and deduce_target_char<T>)
219 : template < class Char >
220 : struct deduce_source_char_impl
221 : {
222 : typedef typename boost::detail::normalize_single_byte_char< Char >::type type;
223 : };
224 :
225 : template < class T >
226 : struct deduce_source_char_impl< deduce_character_type_later< T > >
227 : {
228 : template <class U>
229 : static auto left_shift_type(long)
230 : -> decltype( std::declval<std::basic_ostream< char >&>() << std::declval<const U&>(), char{});
231 :
232 : #if !defined(BOOST_LCAST_NO_WCHAR_T)
233 : template <class U>
234 : static auto left_shift_type(int)
235 : -> decltype( std::declval<std::basic_ostream< wchar_t >&>() << std::declval<const U&>(), wchar_t{});
236 : #endif
237 :
238 : template <class U>
239 : static void left_shift_type(...);
240 :
241 : using type = decltype(left_shift_type<T>(1L));
242 :
243 : static_assert(!std::is_same<type, void>::value,
244 : #if defined(BOOST_LCAST_NO_WCHAR_T)
245 : "Source type is not std::ostream`able and std::wostream`s are "
246 : "not supported by your STL implementation"
247 : #else
248 : "Source type is neither std::ostream`able nor std::wostream`able"
249 : #endif
250 : );
251 : };
252 : }
253 :
254 : namespace detail // deduce_target_char_impl<T>
255 : {
256 : // If type T is `deduce_character_type_later` type, then tries to deduce
257 : // character type using boost::has_right_shift<T> metafunction.
258 : // Otherwise supplied type T is a character type, that must be normalized
259 : // using normalize_single_byte_char<Char>.
260 : // Executed at Stage 2 (See deduce_source_char<T> and deduce_target_char<T>)
261 : template < class Char >
262 : struct deduce_target_char_impl
263 : {
264 : typedef typename normalize_single_byte_char< Char >::type type;
265 : };
266 :
267 : template < class T >
268 : struct deduce_target_char_impl< deduce_character_type_later<T> >
269 : {
270 : template <class U>
271 : static auto right_shift_type(long)
272 : -> decltype( std::declval<std::basic_istream< char >&>() >> std::declval<U&>(), char{});
273 :
274 : #if !defined(BOOST_LCAST_NO_WCHAR_T)
275 : template <class U>
276 : static auto right_shift_type(int)
277 : -> decltype( std::declval<std::basic_istream< wchar_t >&>() >> std::declval<U&>(), wchar_t{});
278 : #endif
279 :
280 : template <class U>
281 : static void right_shift_type(...);
282 :
283 : using type = decltype(right_shift_type<T>(1L));
284 :
285 : static_assert(!std::is_same<type, void>::value,
286 : #if defined(BOOST_LCAST_NO_WCHAR_T)
287 : "Target type is not std::istream`able and std::wistream`s are "
288 : "not supported by your STL implementation"
289 : #else
290 : "Target type is neither std::istream`able nor std::wistream`able"
291 : #endif
292 : );
293 : };
294 : }
295 :
296 : namespace detail // deduce_target_char<T> and deduce_source_char<T>
297 : {
298 : // We deduce stream character types in two stages.
299 : //
300 : // Stage 1 is common for Target and Source. At Stage 1 we get
301 : // non normalized character type (may contain unsigned/signed char)
302 : // or deduce_character_type_later<T> where T is the original type.
303 : // Stage 1 is executed by stream_char_common<T>
304 : //
305 : // At Stage 2 we normalize character types or try to deduce character
306 : // type using metafunctions.
307 : // Stage 2 is executed by deduce_target_char_impl<T> and
308 : // deduce_source_char_impl<T>
309 : //
310 : // deduce_target_char<T> and deduce_source_char<T> functions combine
311 : // both stages
312 :
313 : template < class T >
314 : struct deduce_target_char
315 : {
316 : typedef typename stream_char_common< T >::type stage1_type;
317 : typedef typename deduce_target_char_impl< stage1_type >::type type;
318 : };
319 :
320 : template < class T >
321 : struct deduce_source_char
322 : {
323 : typedef typename stream_char_common< T >::type stage1_type;
324 : typedef typename deduce_source_char_impl< stage1_type >::type type;
325 : };
326 : }
327 :
328 : namespace detail // array_to_pointer_decay<T>
329 : {
330 : template<class T>
331 : struct array_to_pointer_decay
332 : {
333 : typedef T type;
334 : };
335 :
336 : template<class T, std::size_t N>
337 : struct array_to_pointer_decay<T[N]>
338 : {
339 : typedef const T * type;
340 : };
341 : }
342 :
343 : namespace detail // lcast_src_length
344 : {
345 : // Return max. length of string representation of Source;
346 : template< class Source, // Source type of lexical_cast.
347 : class Enable = void // helper type
348 : >
349 : struct lcast_src_length
350 : {
351 : BOOST_STATIC_CONSTANT(std::size_t, value = 1);
352 : };
353 :
354 : // Helper for integral types.
355 : // Notes on length calculation:
356 : // Max length for 32bit int with grouping "\1" and thousands_sep ',':
357 : // "-2,1,4,7,4,8,3,6,4,7"
358 : // ^ - is_signed
359 : // ^ - 1 digit not counted by digits10
360 : // ^^^^^^^^^^^^^^^^^^ - digits10 * 2
361 : //
362 : // Constant is_specialized is used instead of constant 1
363 : // to prevent buffer overflow in a rare case when
364 : // <boost/limits.hpp> doesn't add missing specialization for
365 : // numeric_limits<T> for some integral type T.
366 : // When is_specialized is false, the whole expression is 0.
367 : template <class Source>
368 : struct lcast_src_length<
369 : Source, typename std::enable_if<boost::detail::lcast::is_integral<Source>::value >::type
370 : >
371 : {
372 : BOOST_STATIC_CONSTANT(std::size_t, value =
373 : std::numeric_limits<Source>::is_signed +
374 : std::numeric_limits<Source>::is_specialized + /* == 1 */
375 : std::numeric_limits<Source>::digits10 * 2
376 : );
377 : };
378 :
379 : // Helper for floating point types.
380 : // -1.23456789e-123456
381 : // ^ sign
382 : // ^ leading digit
383 : // ^ decimal point
384 : // ^^^^^^^^ lcast_precision<Source>::value
385 : // ^ "e"
386 : // ^ exponent sign
387 : // ^^^^^^ exponent (assumed 6 or less digits)
388 : // sign + leading digit + decimal point + "e" + exponent sign == 5
389 : template<class Source>
390 : struct lcast_src_length<
391 : Source, typename std::enable_if<std::is_floating_point<Source>::value >::type
392 : >
393 : {
394 : static_assert(
395 : std::numeric_limits<Source>::max_exponent10 <= 999999L &&
396 : std::numeric_limits<Source>::min_exponent10 >= -999999L
397 : , "");
398 :
399 : BOOST_STATIC_CONSTANT(std::size_t, value =
400 : 5 + lcast_precision<Source>::value + 6
401 : );
402 : };
403 : }
404 :
405 : namespace detail // lexical_cast_stream_traits<Source, Target>
406 : {
407 : template <class Source, class Target>
408 : struct lexical_cast_stream_traits {
409 : typedef typename boost::detail::array_to_pointer_decay<Source>::type src;
410 : typedef typename std::remove_cv<src>::type no_cv_src;
411 :
412 : typedef boost::detail::deduce_source_char<no_cv_src> deduce_src_char_metafunc;
413 : typedef typename deduce_src_char_metafunc::type src_char_t;
414 : typedef typename boost::detail::deduce_target_char<Target>::type target_char_t;
415 :
416 : typedef typename boost::detail::widest_char<
417 : target_char_t, src_char_t
418 : >::type char_type;
419 :
420 : #if !defined(BOOST_NO_CXX11_CHAR16_T) && defined(BOOST_NO_CXX11_UNICODE_LITERALS)
421 : static_assert(!std::is_same<char16_t, src_char_t>::value
422 : && !std::is_same<char16_t, target_char_t>::value,
423 : "Your compiler does not have full support for char16_t" );
424 : #endif
425 : #if !defined(BOOST_NO_CXX11_CHAR32_T) && defined(BOOST_NO_CXX11_UNICODE_LITERALS)
426 : static_assert(!std::is_same<char32_t, src_char_t>::value
427 : && !std::is_same<char32_t, target_char_t>::value,
428 : "Your compiler does not have full support for char32_t" );
429 : #endif
430 :
431 : typedef std::char_traits<char_type> traits;
432 :
433 : typedef boost::detail::lcast_src_length<no_cv_src> len_t;
434 : };
435 : }
436 :
437 : namespace detail
438 : {
439 : template<typename Target, typename Source>
440 : struct lexical_converter_impl
441 : {
442 : typedef lexical_cast_stream_traits<Source, Target> stream_trait;
443 :
444 : typedef detail::lcast::optimized_src_stream<
445 : typename stream_trait::char_type,
446 : typename stream_trait::traits,
447 : stream_trait::len_t::value + 1
448 : > optimized_src_stream;
449 :
450 : template <class T>
451 : static auto detect_type(int)
452 : -> decltype(std::declval<optimized_src_stream&>().stream_in(std::declval<lcast::exact<T>>()), optimized_src_stream{});
453 :
454 : template <class T>
455 : static lcast::ios_src_stream<typename stream_trait::char_type, typename stream_trait::traits> detect_type(...);
456 :
457 : using from_src_stream = decltype(detect_type<Source>(1));
458 :
459 : typedef detail::lcast::to_target_stream<
460 : typename stream_trait::char_type,
461 : typename stream_trait::traits
462 : > to_target_stream;
463 :
464 15000 : static inline bool try_convert(const Source& arg, Target& result) {
465 15000 : from_src_stream src_stream;
466 15000 : if (!src_stream.stream_in(lcast::exact<Source>{arg}))
467 0 : return false;
468 :
469 15000 : to_target_stream out(src_stream.cbegin(), src_stream.cend());
470 15000 : if (!out.stream_out(result))
471 0 : return false;
472 :
473 15000 : return true;
474 15000 : }
475 : };
476 : }
477 :
478 : } // namespace boost
479 :
480 : #undef BOOST_LCAST_NO_WCHAR_T
481 :
482 : #endif // BOOST_LEXICAL_CAST_DETAIL_CONVERTER_LEXICAL_HPP
483 :
|