]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Copyright Kevlin Henney, 2000-2005. |
2 | // Copyright Alexander Nasonov, 2006-2010. | |
3 | // Copyright Antony Polukhin, 2011-2014. | |
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_STREAMS_HPP | |
19 | #define BOOST_LEXICAL_CAST_DETAIL_CONVERTER_LEXICAL_STREAMS_HPP | |
20 | ||
21 | #include <boost/config.hpp> | |
22 | #ifdef BOOST_HAS_PRAGMA_ONCE | |
23 | # pragma once | |
24 | #endif | |
25 | ||
26 | ||
27 | #if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_WSTRING) | |
28 | #define BOOST_LCAST_NO_WCHAR_T | |
29 | #endif | |
30 | ||
31 | #include <cstddef> | |
32 | #include <string> | |
33 | #include <cstring> | |
34 | #include <cstdio> | |
35 | #include <boost/limits.hpp> | |
36 | #include <boost/mpl/if.hpp> | |
37 | #include <boost/type_traits/is_pointer.hpp> | |
38 | #include <boost/static_assert.hpp> | |
39 | #include <boost/detail/workaround.hpp> | |
40 | ||
41 | ||
42 | #ifndef BOOST_NO_STD_LOCALE | |
43 | # include <locale> | |
44 | #else | |
45 | # ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE | |
46 | // Getting error at this point means, that your STL library is old/lame/misconfigured. | |
47 | // If nothing can be done with STL library, define BOOST_LEXICAL_CAST_ASSUME_C_LOCALE, | |
48 | // but beware: lexical_cast will understand only 'C' locale delimeters and thousands | |
49 | // separators. | |
50 | # error "Unable to use <locale> header. Define BOOST_LEXICAL_CAST_ASSUME_C_LOCALE to force " | |
51 | # error "boost::lexical_cast to use only 'C' locale during conversions." | |
52 | # endif | |
53 | #endif | |
54 | ||
55 | #ifdef BOOST_NO_STRINGSTREAM | |
56 | #include <strstream> | |
57 | #else | |
58 | #include <sstream> | |
59 | #endif | |
60 | ||
61 | #include <boost/lexical_cast/detail/lcast_char_constants.hpp> | |
62 | #include <boost/lexical_cast/detail/lcast_unsigned_converters.hpp> | |
63 | #include <boost/lexical_cast/detail/inf_nan.hpp> | |
64 | ||
65 | #include <istream> | |
66 | ||
67 | #ifndef BOOST_NO_CXX11_HDR_ARRAY | |
68 | #include <array> | |
69 | #endif | |
70 | ||
71 | #include <boost/array.hpp> | |
72 | #include <boost/type_traits/make_unsigned.hpp> | |
73 | #include <boost/type_traits/is_integral.hpp> | |
74 | #include <boost/type_traits/is_float.hpp> | |
75 | #include <boost/range/iterator_range_core.hpp> | |
76 | #include <boost/container/container_fwd.hpp> | |
77 | #include <boost/integer.hpp> | |
78 | #include <boost/detail/basic_pointerbuf.hpp> | |
79 | #include <boost/noncopyable.hpp> | |
80 | #ifndef BOOST_NO_CWCHAR | |
81 | # include <cwchar> | |
82 | #endif | |
83 | ||
84 | namespace boost { | |
85 | ||
86 | namespace detail // basic_unlockedbuf | |
87 | { | |
88 | // acts as a stream buffer which wraps around a pair of pointers | |
89 | // and gives acces to internals | |
90 | template <class BufferType, class CharT> | |
91 | class basic_unlockedbuf : public basic_pointerbuf<CharT, BufferType> { | |
92 | public: | |
93 | typedef basic_pointerbuf<CharT, BufferType> base_type; | |
94 | typedef BOOST_DEDUCED_TYPENAME base_type::streamsize streamsize; | |
95 | ||
96 | #ifndef BOOST_NO_USING_TEMPLATE | |
97 | using base_type::pptr; | |
98 | using base_type::pbase; | |
99 | using base_type::setbuf; | |
100 | #else | |
101 | charT* pptr() const { return base_type::pptr(); } | |
102 | charT* pbase() const { return base_type::pbase(); } | |
103 | BufferType* setbuf(char_type* s, streamsize n) { return base_type::setbuf(s, n); } | |
104 | #endif | |
105 | }; | |
106 | } | |
107 | ||
108 | namespace detail | |
109 | { | |
110 | struct do_not_construct_out_stream_t{}; | |
111 | ||
112 | template <class CharT, class Traits> | |
113 | struct out_stream_helper_trait { | |
114 | #if defined(BOOST_NO_STRINGSTREAM) | |
115 | typedef std::ostrstream out_stream_t; | |
116 | typedef void buffer_t; | |
117 | #elif defined(BOOST_NO_STD_LOCALE) | |
118 | typedef std::ostringstream out_stream_t; | |
119 | typedef basic_unlockedbuf<std::streambuf, char> buffer_t; | |
120 | #else | |
121 | typedef std::basic_ostringstream<CharT, Traits> | |
122 | out_stream_t; | |
123 | typedef basic_unlockedbuf<std::basic_streambuf<CharT, Traits>, CharT> | |
124 | buffer_t; | |
125 | #endif | |
126 | }; | |
127 | } | |
128 | ||
129 | namespace detail // optimized stream wrappers | |
130 | { | |
131 | template< class CharT // a result of widest_char transformation | |
132 | , class Traits | |
133 | , bool RequiresStringbuffer | |
134 | , std::size_t CharacterBufferSize | |
135 | > | |
136 | class lexical_istream_limited_src: boost::noncopyable { | |
137 | typedef BOOST_DEDUCED_TYPENAME out_stream_helper_trait<CharT, Traits>::buffer_t | |
138 | buffer_t; | |
139 | ||
140 | typedef BOOST_DEDUCED_TYPENAME out_stream_helper_trait<CharT, Traits>::out_stream_t | |
141 | out_stream_t; | |
142 | ||
143 | typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c< | |
144 | RequiresStringbuffer, | |
145 | out_stream_t, | |
146 | do_not_construct_out_stream_t | |
147 | >::type deduced_out_stream_t; | |
148 | ||
149 | // A string representation of Source is written to `buffer`. | |
150 | deduced_out_stream_t out_stream; | |
151 | CharT buffer[CharacterBufferSize]; | |
152 | ||
153 | // After the `operator <<` finishes, `[start, finish)` is | |
154 | // the range to output by `operator >>` | |
155 | const CharT* start; | |
156 | const CharT* finish; | |
157 | ||
158 | public: | |
159 | lexical_istream_limited_src() BOOST_NOEXCEPT | |
160 | : start(buffer) | |
161 | , finish(buffer + CharacterBufferSize) | |
162 | {} | |
163 | ||
164 | const CharT* cbegin() const BOOST_NOEXCEPT { | |
165 | return start; | |
166 | } | |
167 | ||
168 | const CharT* cend() const BOOST_NOEXCEPT { | |
169 | return finish; | |
170 | } | |
171 | ||
172 | private: | |
173 | // Undefined: | |
174 | lexical_istream_limited_src(lexical_istream_limited_src const&); | |
175 | void operator=(lexical_istream_limited_src const&); | |
176 | ||
177 | /************************************ HELPER FUNCTIONS FOR OPERATORS << ( ... ) ********************************/ | |
178 | bool shl_char(CharT ch) BOOST_NOEXCEPT { | |
179 | Traits::assign(buffer[0], ch); | |
180 | finish = start + 1; | |
181 | return true; | |
182 | } | |
183 | ||
184 | #ifndef BOOST_LCAST_NO_WCHAR_T | |
185 | template <class T> | |
186 | bool shl_char(T ch) { | |
187 | BOOST_STATIC_ASSERT_MSG(( sizeof(T) <= sizeof(CharT)) , | |
188 | "boost::lexical_cast does not support narrowing of char types." | |
189 | "Use boost::locale instead" ); | |
190 | #ifndef BOOST_LEXICAL_CAST_ASSUME_C_LOCALE | |
191 | std::locale loc; | |
192 | CharT const w = BOOST_USE_FACET(std::ctype<CharT>, loc).widen(ch); | |
193 | #else | |
194 | CharT const w = static_cast<CharT>(ch); | |
195 | #endif | |
196 | Traits::assign(buffer[0], w); | |
197 | finish = start + 1; | |
198 | return true; | |
199 | } | |
200 | #endif | |
201 | ||
202 | bool shl_char_array(CharT const* str) BOOST_NOEXCEPT { | |
203 | start = str; | |
204 | finish = start + Traits::length(str); | |
205 | return true; | |
206 | } | |
207 | ||
208 | template <class T> | |
209 | bool shl_char_array(T const* str) { | |
210 | BOOST_STATIC_ASSERT_MSG(( sizeof(T) <= sizeof(CharT)), | |
211 | "boost::lexical_cast does not support narrowing of char types." | |
212 | "Use boost::locale instead" ); | |
213 | return shl_input_streamable(str); | |
214 | } | |
215 | ||
216 | bool shl_char_array_limited(CharT const* str, std::size_t max_size) BOOST_NOEXCEPT { | |
217 | start = str; | |
218 | finish = std::find(start, start + max_size, Traits::to_char_type(0)); | |
219 | return true; | |
220 | } | |
221 | ||
222 | template<typename InputStreamable> | |
223 | bool shl_input_streamable(InputStreamable& input) { | |
224 | #if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_LOCALE) | |
225 | // If you have compilation error at this point, than your STL library | |
226 | // does not support such conversions. Try updating it. | |
227 | BOOST_STATIC_ASSERT((boost::is_same<char, CharT>::value)); | |
228 | #endif | |
229 | ||
230 | #ifndef BOOST_NO_EXCEPTIONS | |
231 | out_stream.exceptions(std::ios::badbit); | |
232 | try { | |
233 | #endif | |
234 | bool const result = !(out_stream << input).fail(); | |
235 | const buffer_t* const p = static_cast<buffer_t*>( | |
236 | static_cast<std::basic_streambuf<CharT, Traits>*>(out_stream.rdbuf()) | |
237 | ); | |
238 | start = p->pbase(); | |
239 | finish = p->pptr(); | |
240 | return result; | |
241 | #ifndef BOOST_NO_EXCEPTIONS | |
242 | } catch (const ::std::ios_base::failure& /*f*/) { | |
243 | return false; | |
244 | } | |
245 | #endif | |
246 | } | |
247 | ||
248 | template <class T> | |
249 | inline bool shl_unsigned(const T n) { | |
250 | CharT* tmp_finish = buffer + CharacterBufferSize; | |
251 | start = lcast_put_unsigned<Traits, T, CharT>(n, tmp_finish).convert(); | |
252 | finish = tmp_finish; | |
253 | return true; | |
254 | } | |
255 | ||
256 | template <class T> | |
257 | inline bool shl_signed(const T n) { | |
258 | CharT* tmp_finish = buffer + CharacterBufferSize; | |
259 | typedef BOOST_DEDUCED_TYPENAME boost::make_unsigned<T>::type utype; | |
260 | CharT* tmp_start = lcast_put_unsigned<Traits, utype, CharT>(lcast_to_unsigned(n), tmp_finish).convert(); | |
261 | if (n < 0) { | |
262 | --tmp_start; | |
263 | CharT const minus = lcast_char_constants<CharT>::minus; | |
264 | Traits::assign(*tmp_start, minus); | |
265 | } | |
266 | start = tmp_start; | |
267 | finish = tmp_finish; | |
268 | return true; | |
269 | } | |
270 | ||
271 | template <class T, class SomeCharT> | |
272 | bool shl_real_type(const T& val, SomeCharT* /*begin*/) { | |
273 | lcast_set_precision(out_stream, &val); | |
274 | return shl_input_streamable(val); | |
275 | } | |
276 | ||
277 | bool shl_real_type(float val, char* begin) { | |
278 | using namespace std; | |
279 | const double val_as_double = val; | |
280 | finish = start + | |
281 | #if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(__SGI_STL_PORT) && !defined(_STLPORT_VERSION) | |
282 | sprintf_s(begin, CharacterBufferSize, | |
283 | #else | |
284 | sprintf(begin, | |
285 | #endif | |
286 | "%.*g", static_cast<int>(boost::detail::lcast_get_precision<float>()), val_as_double); | |
287 | return finish > start; | |
288 | } | |
289 | ||
290 | bool shl_real_type(double val, char* begin) { | |
291 | using namespace std; | |
292 | finish = start + | |
293 | #if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(__SGI_STL_PORT) && !defined(_STLPORT_VERSION) | |
294 | sprintf_s(begin, CharacterBufferSize, | |
295 | #else | |
296 | sprintf(begin, | |
297 | #endif | |
298 | "%.*g", static_cast<int>(boost::detail::lcast_get_precision<double>()), val); | |
299 | return finish > start; | |
300 | } | |
301 | ||
302 | #ifndef __MINGW32__ | |
303 | bool shl_real_type(long double val, char* begin) { | |
304 | using namespace std; | |
305 | finish = start + | |
306 | #if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(__SGI_STL_PORT) && !defined(_STLPORT_VERSION) | |
307 | sprintf_s(begin, CharacterBufferSize, | |
308 | #else | |
309 | sprintf(begin, | |
310 | #endif | |
311 | "%.*Lg", static_cast<int>(boost::detail::lcast_get_precision<long double>()), val ); | |
312 | return finish > start; | |
313 | } | |
314 | #endif | |
315 | ||
316 | ||
317 | #if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_SWPRINTF) && !defined(__MINGW32__) | |
318 | bool shl_real_type(float val, wchar_t* begin) { | |
319 | using namespace std; | |
320 | const double val_as_double = val; | |
321 | finish = start + swprintf(begin, CharacterBufferSize, | |
322 | L"%.*g", | |
323 | static_cast<int>(boost::detail::lcast_get_precision<float >()), | |
324 | val_as_double ); | |
325 | return finish > start; | |
326 | } | |
327 | ||
328 | bool shl_real_type(double val, wchar_t* begin) { | |
329 | using namespace std; | |
330 | finish = start + swprintf(begin, CharacterBufferSize, | |
331 | L"%.*g", static_cast<int>(boost::detail::lcast_get_precision<double >()), val ); | |
332 | return finish > start; | |
333 | } | |
334 | ||
335 | bool shl_real_type(long double val, wchar_t* begin) { | |
336 | using namespace std; | |
337 | finish = start + swprintf(begin, CharacterBufferSize, | |
338 | L"%.*Lg", static_cast<int>(boost::detail::lcast_get_precision<long double >()), val ); | |
339 | return finish > start; | |
340 | } | |
341 | #endif | |
342 | template <class T> | |
343 | bool shl_real(T val) { | |
344 | CharT* tmp_finish = buffer + CharacterBufferSize; | |
345 | if (put_inf_nan(buffer, tmp_finish, val)) { | |
346 | finish = tmp_finish; | |
347 | return true; | |
348 | } | |
349 | ||
350 | return shl_real_type(val, static_cast<CharT*>(buffer)); | |
351 | } | |
352 | ||
353 | /************************************ OPERATORS << ( ... ) ********************************/ | |
354 | public: | |
355 | template<class Alloc> | |
356 | bool operator<<(std::basic_string<CharT,Traits,Alloc> const& str) BOOST_NOEXCEPT { | |
357 | start = str.data(); | |
358 | finish = start + str.length(); | |
359 | return true; | |
360 | } | |
361 | ||
362 | template<class Alloc> | |
363 | bool operator<<(boost::container::basic_string<CharT,Traits,Alloc> const& str) BOOST_NOEXCEPT { | |
364 | start = str.data(); | |
365 | finish = start + str.length(); | |
366 | return true; | |
367 | } | |
368 | ||
369 | bool operator<<(bool value) BOOST_NOEXCEPT { | |
370 | CharT const czero = lcast_char_constants<CharT>::zero; | |
371 | Traits::assign(buffer[0], Traits::to_char_type(czero + value)); | |
372 | finish = start + 1; | |
373 | return true; | |
374 | } | |
375 | ||
376 | template <class C> | |
377 | BOOST_DEDUCED_TYPENAME boost::disable_if<boost::is_const<C>, bool>::type | |
378 | operator<<(const iterator_range<C*>& rng) BOOST_NOEXCEPT { | |
379 | return (*this) << iterator_range<const C*>(rng.begin(), rng.end()); | |
380 | } | |
381 | ||
382 | bool operator<<(const iterator_range<const CharT*>& rng) BOOST_NOEXCEPT { | |
383 | start = rng.begin(); | |
384 | finish = rng.end(); | |
385 | return true; | |
386 | } | |
387 | ||
388 | bool operator<<(const iterator_range<const signed char*>& rng) BOOST_NOEXCEPT { | |
389 | return (*this) << iterator_range<const char*>( | |
390 | reinterpret_cast<const char*>(rng.begin()), | |
391 | reinterpret_cast<const char*>(rng.end()) | |
392 | ); | |
393 | } | |
394 | ||
395 | bool operator<<(const iterator_range<const unsigned char*>& rng) BOOST_NOEXCEPT { | |
396 | return (*this) << iterator_range<const char*>( | |
397 | reinterpret_cast<const char*>(rng.begin()), | |
398 | reinterpret_cast<const char*>(rng.end()) | |
399 | ); | |
400 | } | |
401 | ||
402 | bool operator<<(char ch) { return shl_char(ch); } | |
403 | bool operator<<(unsigned char ch) { return ((*this) << static_cast<char>(ch)); } | |
404 | bool operator<<(signed char ch) { return ((*this) << static_cast<char>(ch)); } | |
405 | #if !defined(BOOST_LCAST_NO_WCHAR_T) | |
406 | bool operator<<(wchar_t const* str) { return shl_char_array(str); } | |
407 | bool operator<<(wchar_t * str) { return shl_char_array(str); } | |
408 | #ifndef BOOST_NO_INTRINSIC_WCHAR_T | |
409 | bool operator<<(wchar_t ch) { return shl_char(ch); } | |
410 | #endif | |
411 | #endif | |
412 | #if !defined(BOOST_NO_CXX11_CHAR16_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) | |
413 | bool operator<<(char16_t ch) { return shl_char(ch); } | |
414 | bool operator<<(char16_t * str) { return shl_char_array(str); } | |
415 | bool operator<<(char16_t const * str) { return shl_char_array(str); } | |
416 | #endif | |
417 | #if !defined(BOOST_NO_CXX11_CHAR32_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) | |
418 | bool operator<<(char32_t ch) { return shl_char(ch); } | |
419 | bool operator<<(char32_t * str) { return shl_char_array(str); } | |
420 | bool operator<<(char32_t const * str) { return shl_char_array(str); } | |
421 | #endif | |
422 | bool operator<<(unsigned char const* ch) { return ((*this) << reinterpret_cast<char const*>(ch)); } | |
423 | bool operator<<(unsigned char * ch) { return ((*this) << reinterpret_cast<char *>(ch)); } | |
424 | bool operator<<(signed char const* ch) { return ((*this) << reinterpret_cast<char const*>(ch)); } | |
425 | bool operator<<(signed char * ch) { return ((*this) << reinterpret_cast<char *>(ch)); } | |
426 | bool operator<<(char const* str) { return shl_char_array(str); } | |
427 | bool operator<<(char* str) { return shl_char_array(str); } | |
428 | bool operator<<(short n) { return shl_signed(n); } | |
429 | bool operator<<(int n) { return shl_signed(n); } | |
430 | bool operator<<(long n) { return shl_signed(n); } | |
431 | bool operator<<(unsigned short n) { return shl_unsigned(n); } | |
432 | bool operator<<(unsigned int n) { return shl_unsigned(n); } | |
433 | bool operator<<(unsigned long n) { return shl_unsigned(n); } | |
434 | ||
435 | #if defined(BOOST_HAS_LONG_LONG) | |
436 | bool operator<<(boost::ulong_long_type n) { return shl_unsigned(n); } | |
437 | bool operator<<(boost::long_long_type n) { return shl_signed(n); } | |
438 | #elif defined(BOOST_HAS_MS_INT64) | |
439 | bool operator<<(unsigned __int64 n) { return shl_unsigned(n); } | |
440 | bool operator<<( __int64 n) { return shl_signed(n); } | |
441 | #endif | |
442 | ||
443 | #ifdef BOOST_HAS_INT128 | |
444 | bool operator<<(const boost::uint128_type& n) { return shl_unsigned(n); } | |
445 | bool operator<<(const boost::int128_type& n) { return shl_signed(n); } | |
446 | #endif | |
447 | bool operator<<(float val) { return shl_real(val); } | |
448 | bool operator<<(double val) { return shl_real(val); } | |
449 | bool operator<<(long double val) { | |
450 | #ifndef __MINGW32__ | |
451 | return shl_real(val); | |
452 | #else | |
453 | return shl_real(static_cast<double>(val)); | |
454 | #endif | |
455 | } | |
456 | ||
457 | // Adding constness to characters. Constness does not change layout | |
458 | template <class C, std::size_t N> | |
459 | BOOST_DEDUCED_TYPENAME boost::disable_if<boost::is_const<C>, bool>::type | |
460 | operator<<(boost::array<C, N> const& input) BOOST_NOEXCEPT { | |
461 | BOOST_STATIC_ASSERT_MSG( | |
462 | (sizeof(boost::array<const C, N>) == sizeof(boost::array<C, N>)), | |
463 | "boost::array<C, N> and boost::array<const C, N> must have exactly the same layout." | |
464 | ); | |
465 | return ((*this) << reinterpret_cast<boost::array<const C, N> const& >(input)); | |
466 | } | |
467 | ||
468 | template <std::size_t N> | |
469 | bool operator<<(boost::array<const CharT, N> const& input) BOOST_NOEXCEPT { | |
470 | return shl_char_array_limited(input.data(), N); | |
471 | } | |
472 | ||
473 | template <std::size_t N> | |
474 | bool operator<<(boost::array<const unsigned char, N> const& input) BOOST_NOEXCEPT { | |
475 | return ((*this) << reinterpret_cast<boost::array<const char, N> const& >(input)); | |
476 | } | |
477 | ||
478 | template <std::size_t N> | |
479 | bool operator<<(boost::array<const signed char, N> const& input) BOOST_NOEXCEPT { | |
480 | return ((*this) << reinterpret_cast<boost::array<const char, N> const& >(input)); | |
481 | } | |
482 | ||
483 | #ifndef BOOST_NO_CXX11_HDR_ARRAY | |
484 | // Making a Boost.Array from std::array | |
485 | template <class C, std::size_t N> | |
486 | bool operator<<(std::array<C, N> const& input) BOOST_NOEXCEPT { | |
487 | BOOST_STATIC_ASSERT_MSG( | |
488 | (sizeof(std::array<C, N>) == sizeof(boost::array<C, N>)), | |
489 | "std::array and boost::array must have exactly the same layout. " | |
490 | "Bug in implementation of std::array or boost::array." | |
491 | ); | |
492 | return ((*this) << reinterpret_cast<boost::array<C, N> const& >(input)); | |
493 | } | |
494 | #endif | |
495 | template <class InStreamable> | |
496 | bool operator<<(const InStreamable& input) { return shl_input_streamable(input); } | |
497 | }; | |
498 | ||
499 | ||
500 | template <class CharT, class Traits> | |
501 | class lexical_ostream_limited_src: boost::noncopyable { | |
502 | //`[start, finish)` is the range to output by `operator >>` | |
503 | const CharT* start; | |
504 | const CharT* const finish; | |
505 | ||
506 | public: | |
507 | lexical_ostream_limited_src(const CharT* begin, const CharT* end) BOOST_NOEXCEPT | |
508 | : start(begin) | |
509 | , finish(end) | |
510 | {} | |
511 | ||
512 | /************************************ HELPER FUNCTIONS FOR OPERATORS >> ( ... ) ********************************/ | |
513 | private: | |
514 | template <typename Type> | |
515 | bool shr_unsigned(Type& output) { | |
516 | if (start == finish) return false; | |
517 | CharT const minus = lcast_char_constants<CharT>::minus; | |
518 | CharT const plus = lcast_char_constants<CharT>::plus; | |
519 | bool const has_minus = Traits::eq(minus, *start); | |
520 | ||
521 | /* We won`t use `start' any more, so no need in decrementing it after */ | |
522 | if (has_minus || Traits::eq(plus, *start)) { | |
523 | ++start; | |
524 | } | |
525 | ||
526 | bool const succeed = lcast_ret_unsigned<Traits, Type, CharT>(output, start, finish).convert(); | |
527 | ||
528 | if (has_minus) { | |
529 | output = static_cast<Type>(0u - output); | |
530 | } | |
531 | ||
532 | return succeed; | |
533 | } | |
534 | ||
535 | template <typename Type> | |
536 | bool shr_signed(Type& output) { | |
537 | if (start == finish) return false; | |
538 | CharT const minus = lcast_char_constants<CharT>::minus; | |
539 | CharT const plus = lcast_char_constants<CharT>::plus; | |
540 | typedef BOOST_DEDUCED_TYPENAME make_unsigned<Type>::type utype; | |
541 | utype out_tmp = 0; | |
542 | bool const has_minus = Traits::eq(minus, *start); | |
543 | ||
544 | /* We won`t use `start' any more, so no need in decrementing it after */ | |
545 | if (has_minus || Traits::eq(plus, *start)) { | |
546 | ++start; | |
547 | } | |
548 | ||
549 | bool succeed = lcast_ret_unsigned<Traits, utype, CharT>(out_tmp, start, finish).convert(); | |
550 | if (has_minus) { | |
551 | utype const comp_val = (static_cast<utype>(1) << std::numeric_limits<Type>::digits); | |
552 | succeed = succeed && out_tmp<=comp_val; | |
553 | output = static_cast<Type>(0u - out_tmp); | |
554 | } else { | |
555 | utype const comp_val = static_cast<utype>((std::numeric_limits<Type>::max)()); | |
556 | succeed = succeed && out_tmp<=comp_val; | |
557 | output = static_cast<Type>(out_tmp); | |
558 | } | |
559 | return succeed; | |
560 | } | |
561 | ||
562 | template<typename InputStreamable> | |
563 | bool shr_using_base_class(InputStreamable& output) | |
564 | { | |
565 | BOOST_STATIC_ASSERT_MSG( | |
566 | (!boost::is_pointer<InputStreamable>::value), | |
567 | "boost::lexical_cast can not convert to pointers" | |
568 | ); | |
569 | ||
570 | #if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_LOCALE) | |
571 | BOOST_STATIC_ASSERT_MSG((boost::is_same<char, CharT>::value), | |
572 | "boost::lexical_cast can not convert, because your STL library does not " | |
573 | "support such conversions. Try updating it." | |
574 | ); | |
575 | #endif | |
576 | typedef BOOST_DEDUCED_TYPENAME out_stream_helper_trait<CharT, Traits>::buffer_t | |
577 | buffer_t; | |
578 | ||
579 | #if defined(BOOST_NO_STRINGSTREAM) | |
580 | std::istrstream stream(start, finish - start); | |
581 | #else | |
582 | ||
583 | buffer_t buf; | |
584 | // Usually `istream` and `basic_istream` do not modify | |
585 | // content of buffer; `buffer_t` assures that this is true | |
586 | buf.setbuf(const_cast<CharT*>(start), finish - start); | |
587 | #if defined(BOOST_NO_STD_LOCALE) | |
588 | std::istream stream(&buf); | |
589 | #else | |
590 | std::basic_istream<CharT, Traits> stream(&buf); | |
591 | #endif // BOOST_NO_STD_LOCALE | |
592 | #endif // BOOST_NO_STRINGSTREAM | |
593 | ||
594 | #ifndef BOOST_NO_EXCEPTIONS | |
595 | stream.exceptions(std::ios::badbit); | |
596 | try { | |
597 | #endif | |
598 | stream.unsetf(std::ios::skipws); | |
599 | lcast_set_precision(stream, static_cast<InputStreamable*>(0)); | |
600 | ||
601 | return (stream >> output) | |
602 | && (stream.get() == Traits::eof()); | |
603 | ||
604 | #ifndef BOOST_NO_EXCEPTIONS | |
605 | } catch (const ::std::ios_base::failure& /*f*/) { | |
606 | return false; | |
607 | } | |
608 | #endif | |
609 | } | |
610 | ||
611 | template<class T> | |
612 | inline bool shr_xchar(T& output) BOOST_NOEXCEPT { | |
613 | BOOST_STATIC_ASSERT_MSG(( sizeof(CharT) == sizeof(T) ), | |
614 | "boost::lexical_cast does not support narrowing of character types." | |
615 | "Use boost::locale instead" ); | |
616 | bool const ok = (finish - start == 1); | |
617 | if (ok) { | |
618 | CharT out; | |
619 | Traits::assign(out, *start); | |
620 | output = static_cast<T>(out); | |
621 | } | |
622 | return ok; | |
623 | } | |
624 | ||
625 | template <std::size_t N, class ArrayT> | |
626 | bool shr_std_array(ArrayT& output) BOOST_NOEXCEPT { | |
627 | using namespace std; | |
628 | const std::size_t size = static_cast<std::size_t>(finish - start); | |
629 | if (size > N - 1) { // `-1` because we need to store \0 at the end | |
630 | return false; | |
631 | } | |
632 | ||
633 | memcpy(&output[0], start, size * sizeof(CharT)); | |
634 | output[size] = Traits::to_char_type(0); | |
635 | return true; | |
636 | } | |
637 | ||
638 | /************************************ OPERATORS >> ( ... ) ********************************/ | |
639 | public: | |
640 | bool operator>>(unsigned short& output) { return shr_unsigned(output); } | |
641 | bool operator>>(unsigned int& output) { return shr_unsigned(output); } | |
642 | bool operator>>(unsigned long int& output) { return shr_unsigned(output); } | |
643 | bool operator>>(short& output) { return shr_signed(output); } | |
644 | bool operator>>(int& output) { return shr_signed(output); } | |
645 | bool operator>>(long int& output) { return shr_signed(output); } | |
646 | #if defined(BOOST_HAS_LONG_LONG) | |
647 | bool operator>>(boost::ulong_long_type& output) { return shr_unsigned(output); } | |
648 | bool operator>>(boost::long_long_type& output) { return shr_signed(output); } | |
649 | #elif defined(BOOST_HAS_MS_INT64) | |
650 | bool operator>>(unsigned __int64& output) { return shr_unsigned(output); } | |
651 | bool operator>>(__int64& output) { return shr_signed(output); } | |
652 | #endif | |
653 | ||
654 | #ifdef BOOST_HAS_INT128 | |
655 | bool operator>>(boost::uint128_type& output) { return shr_unsigned(output); } | |
656 | bool operator>>(boost::int128_type& output) { return shr_signed(output); } | |
657 | #endif | |
658 | ||
659 | bool operator>>(char& output) { return shr_xchar(output); } | |
660 | bool operator>>(unsigned char& output) { return shr_xchar(output); } | |
661 | bool operator>>(signed char& output) { return shr_xchar(output); } | |
662 | #if !defined(BOOST_LCAST_NO_WCHAR_T) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) | |
663 | bool operator>>(wchar_t& output) { return shr_xchar(output); } | |
664 | #endif | |
665 | #if !defined(BOOST_NO_CXX11_CHAR16_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) | |
666 | bool operator>>(char16_t& output) { return shr_xchar(output); } | |
667 | #endif | |
668 | #if !defined(BOOST_NO_CXX11_CHAR32_T) && !defined(BOOST_NO_CXX11_UNICODE_LITERALS) | |
669 | bool operator>>(char32_t& output) { return shr_xchar(output); } | |
670 | #endif | |
671 | template<class Alloc> | |
672 | bool operator>>(std::basic_string<CharT,Traits,Alloc>& str) { | |
673 | str.assign(start, finish); return true; | |
674 | } | |
675 | ||
676 | template<class Alloc> | |
677 | bool operator>>(boost::container::basic_string<CharT,Traits,Alloc>& str) { | |
678 | str.assign(start, finish); return true; | |
679 | } | |
680 | ||
681 | template <std::size_t N> | |
682 | bool operator>>(boost::array<CharT, N>& output) BOOST_NOEXCEPT { | |
683 | return shr_std_array<N>(output); | |
684 | } | |
685 | ||
686 | template <std::size_t N> | |
687 | bool operator>>(boost::array<unsigned char, N>& output) BOOST_NOEXCEPT { | |
688 | return ((*this) >> reinterpret_cast<boost::array<char, N>& >(output)); | |
689 | } | |
690 | ||
691 | template <std::size_t N> | |
692 | bool operator>>(boost::array<signed char, N>& output) BOOST_NOEXCEPT { | |
693 | return ((*this) >> reinterpret_cast<boost::array<char, N>& >(output)); | |
694 | } | |
695 | ||
696 | #ifndef BOOST_NO_CXX11_HDR_ARRAY | |
697 | template <class C, std::size_t N> | |
698 | bool operator>>(std::array<C, N>& output) BOOST_NOEXCEPT { | |
699 | BOOST_STATIC_ASSERT_MSG( | |
700 | (sizeof(std::array<C, N>) == sizeof(boost::array<C, N>)), | |
701 | "std::array<C, N> and boost::array<C, N> must have exactly the same layout." | |
702 | ); | |
703 | return ((*this) >> reinterpret_cast<boost::array<C, N>& >(output)); | |
704 | } | |
705 | #endif | |
706 | ||
707 | bool operator>>(bool& output) BOOST_NOEXCEPT { | |
708 | output = false; // Suppress warning about uninitalized variable | |
709 | ||
710 | if (start == finish) return false; | |
711 | CharT const zero = lcast_char_constants<CharT>::zero; | |
712 | CharT const plus = lcast_char_constants<CharT>::plus; | |
713 | CharT const minus = lcast_char_constants<CharT>::minus; | |
714 | ||
715 | const CharT* const dec_finish = finish - 1; | |
716 | output = Traits::eq(*dec_finish, zero + 1); | |
717 | if (!output && !Traits::eq(*dec_finish, zero)) { | |
718 | return false; // Does not ends on '0' or '1' | |
719 | } | |
720 | ||
721 | if (start == dec_finish) return true; | |
722 | ||
723 | // We may have sign at the beginning | |
724 | if (Traits::eq(plus, *start) || (Traits::eq(minus, *start) && !output)) { | |
725 | ++ start; | |
726 | } | |
727 | ||
728 | // Skipping zeros | |
729 | while (start != dec_finish) { | |
730 | if (!Traits::eq(zero, *start)) { | |
731 | return false; // Not a zero => error | |
732 | } | |
733 | ||
734 | ++ start; | |
735 | } | |
736 | ||
737 | return true; | |
738 | } | |
739 | ||
740 | private: | |
741 | // Not optimised converter | |
742 | template <class T> | |
743 | bool float_types_converter_internal(T& output) { | |
744 | if (parse_inf_nan(start, finish, output)) return true; | |
745 | bool const return_value = shr_using_base_class(output); | |
746 | ||
747 | /* Some compilers and libraries successfully | |
748 | * parse 'inf', 'INFINITY', '1.0E', '1.0E-'... | |
749 | * We are trying to provide a unified behaviour, | |
750 | * so we just forbid such conversions (as some | |
751 | * of the most popular compilers/libraries do) | |
752 | * */ | |
753 | CharT const minus = lcast_char_constants<CharT>::minus; | |
754 | CharT const plus = lcast_char_constants<CharT>::plus; | |
755 | CharT const capital_e = lcast_char_constants<CharT>::capital_e; | |
756 | CharT const lowercase_e = lcast_char_constants<CharT>::lowercase_e; | |
757 | if ( return_value && | |
758 | ( | |
759 | Traits::eq(*(finish-1), lowercase_e) // 1.0e | |
760 | || Traits::eq(*(finish-1), capital_e) // 1.0E | |
761 | || Traits::eq(*(finish-1), minus) // 1.0e- or 1.0E- | |
762 | || Traits::eq(*(finish-1), plus) // 1.0e+ or 1.0E+ | |
763 | ) | |
764 | ) return false; | |
765 | ||
766 | return return_value; | |
767 | } | |
768 | ||
769 | public: | |
770 | bool operator>>(float& output) { return float_types_converter_internal(output); } | |
771 | bool operator>>(double& output) { return float_types_converter_internal(output); } | |
772 | bool operator>>(long double& output) { return float_types_converter_internal(output); } | |
773 | ||
774 | // Generic istream-based algorithm. | |
775 | // lcast_streambuf_for_target<InputStreamable>::value is true. | |
776 | template <typename InputStreamable> | |
777 | bool operator>>(InputStreamable& output) { | |
778 | return shr_using_base_class(output); | |
779 | } | |
780 | }; | |
781 | } | |
782 | } // namespace boost | |
783 | ||
784 | #undef BOOST_LCAST_NO_WCHAR_T | |
785 | ||
786 | #endif // BOOST_LEXICAL_CAST_DETAIL_CONVERTER_LEXICAL_HPP | |
787 |