2015-05-29 François Dumont fdumont@gcc.gnu.org>
[official-gcc.git] / libstdc++-v3 / include / bits / locale_conv.h
blob8b0a77ce317db779c500afacb74517c8528fd5d0
1 // wstring_convert implementation -*- C++ -*-
3 // Copyright (C) 2015 Free Software Foundation, Inc.
4 //
5 // This file is part of the GNU ISO C++ Library. This library is free
6 // software; you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 3, or (at your option)
9 // any later version.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // Under Section 7 of GPL version 3, you are granted additional
17 // permissions described in the GCC Runtime Library Exception, version
18 // 3.1, as published by the Free Software Foundation.
20 // You should have received a copy of the GNU General Public License and
21 // a copy of the GCC Runtime Library Exception along with this program;
22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 // <http://www.gnu.org/licenses/>.
25 /** @file bits/locale_conv.h
26 * This is an internal header file, included by other library headers.
27 * Do not attempt to use it directly. @headername{locale}
30 #ifndef _LOCALE_CONV_H
31 #define _LOCALE_CONV_H 1
33 #if __cplusplus < 201103L
34 # include <bits/c++0x_warning.h>
35 #else
37 #include <streambuf>
38 #include "stringfwd.h"
39 #include "allocator.h"
40 #include "codecvt.h"
41 #include "unique_ptr.h"
43 namespace std _GLIBCXX_VISIBILITY(default)
45 _GLIBCXX_BEGIN_NAMESPACE_VERSION
47 #ifdef _GLIBCXX_USE_WCHAR_T
49 /**
50 * @addtogroup locales
51 * @{
54 template<typename _OutStr, typename _InChar, typename _Codecvt,
55 typename _State, typename _Fn>
56 bool
57 __do_str_codecvt(const _InChar* __first, const _InChar* __last,
58 _OutStr& __outstr, const _Codecvt& __cvt, _State& __state,
59 size_t& __count, _Fn __fn)
61 size_t __outchars = 0;
62 auto __next = __first;
63 const auto __maxlen = __cvt.max_length();
65 codecvt_base::result __result;
68 __outstr.resize(__outstr.size() + (__last - __next) + __maxlen);
69 auto __outnext = &__outstr.front() + __outchars;
70 auto const __outlast = &__outstr.back() + 1;
71 __result = (__cvt.*__fn)(__state, __next, __last, __next,
72 __outnext, __outlast, __outnext);
73 __outchars = __outnext - &__outstr.front();
75 while (__result == codecvt_base::partial && __next != __last
76 && (__outstr.size() - __outchars) < __maxlen);
78 if (__result == codecvt_base::error)
79 return false;
81 if (__result == codecvt_base::noconv)
83 __outstr.assign(__first, __last);
84 __count = __last - __first;
86 else
88 __outstr.resize(__outchars);
89 __count = __next - __first;
92 return true;
95 // Convert narrow character string to wide.
96 template<typename _CharT, typename _Traits, typename _Alloc, typename _State>
97 inline bool
98 __str_codecvt_in(const char* __first, const char* __last,
99 basic_string<_CharT, _Traits, _Alloc>& __outstr,
100 const codecvt<_CharT, char, _State>& __cvt,
101 _State& __state, size_t& __count)
103 using _Codecvt = codecvt<_CharT, char, _State>;
104 using _ConvFn
105 = codecvt_base::result
106 (_Codecvt::*)(_State&, const char*, const char*, const char*&,
107 _CharT*, _CharT*, _CharT*&) const;
108 _ConvFn __fn = &codecvt<_CharT, char, _State>::in;
109 return __do_str_codecvt(__first, __last, __outstr, __cvt, __state,
110 __count, __fn);
113 template<typename _CharT, typename _Traits, typename _Alloc, typename _State>
114 inline bool
115 __str_codecvt_in(const char* __first, const char* __last,
116 basic_string<_CharT, _Traits, _Alloc>& __outstr,
117 const codecvt<_CharT, char, _State>& __cvt)
119 _State __state = {};
120 size_t __n;
121 return __str_codecvt_in(__first, __last, __outstr, __cvt, __state, __n);
124 // Convert wide character string to narrow.
125 template<typename _CharT, typename _Traits, typename _Alloc, typename _State>
126 inline bool
127 __str_codecvt_out(const _CharT* __first, const _CharT* __last,
128 basic_string<char, _Traits, _Alloc>& __outstr,
129 const codecvt<_CharT, char, _State>& __cvt,
130 _State& __state, size_t& __count)
132 using _Codecvt = codecvt<_CharT, char, _State>;
133 using _ConvFn
134 = codecvt_base::result
135 (_Codecvt::*)(_State&, const _CharT*, const _CharT*, const _CharT*&,
136 char*, char*, char*&) const;
137 _ConvFn __fn = &codecvt<_CharT, char, _State>::out;
138 return __do_str_codecvt(__first, __last, __outstr, __cvt, __state,
139 __count, __fn);
142 template<typename _CharT, typename _Traits, typename _Alloc, typename _State>
143 inline bool
144 __str_codecvt_out(const _CharT* __first, const _CharT* __last,
145 basic_string<char, _Traits, _Alloc>& __outstr,
146 const codecvt<_CharT, char, _State>& __cvt)
148 _State __state = {};
149 size_t __n;
150 return __str_codecvt_out(__first, __last, __outstr, __cvt, __state, __n);
153 /// String conversions
154 template<typename _Codecvt, typename _Elem = wchar_t,
155 typename _Wide_alloc = allocator<_Elem>,
156 typename _Byte_alloc = allocator<char>>
157 class wstring_convert
159 public:
160 typedef basic_string<char, char_traits<char>, _Byte_alloc> byte_string;
161 typedef basic_string<_Elem, char_traits<_Elem>, _Wide_alloc> wide_string;
162 typedef typename _Codecvt::state_type state_type;
163 typedef typename wide_string::traits_type::int_type int_type;
165 /** Default constructor.
167 * @param __pcvt The facet to use for conversions.
169 * Takes ownership of @p __pcvt and will delete it in the destructor.
171 explicit
172 wstring_convert(_Codecvt* __pcvt = new _Codecvt()) : _M_cvt(__pcvt)
174 if (!_M_cvt)
175 __throw_logic_error("wstring_convert");
178 /** Construct with an initial converstion state.
180 * @param __pcvt The facet to use for conversions.
181 * @param __state Initial conversion state.
183 * Takes ownership of @p __pcvt and will delete it in the destructor.
184 * The object's conversion state will persist between conversions.
186 wstring_convert(_Codecvt* __pcvt, state_type __state)
187 : _M_cvt(__pcvt), _M_state(__state), _M_with_cvtstate(true)
189 if (!_M_cvt)
190 __throw_logic_error("wstring_convert");
193 /** Construct with error strings.
195 * @param __byte_err A string to return on failed conversions.
196 * @param __wide_err A wide string to return on failed conversions.
198 explicit
199 wstring_convert(const byte_string& __byte_err,
200 const wide_string& __wide_err = wide_string())
201 : _M_cvt(new _Codecvt),
202 _M_byte_err_string(__byte_err), _M_wide_err_string(__wide_err),
203 _M_with_strings(true)
205 if (!_M_cvt)
206 __throw_logic_error("wstring_convert");
209 ~wstring_convert() = default;
211 // _GLIBCXX_RESOLVE_LIB_DEFECTS
212 // 2176. Special members for wstring_convert and wbuffer_convert
213 wstring_convert(const wstring_convert&) = delete;
214 wstring_convert& operator=(const wstring_convert&) = delete;
216 /// @{ Convert from bytes.
217 wide_string
218 from_bytes(char __byte)
220 char __bytes[2] = { __byte };
221 return from_bytes(__bytes, __bytes+1);
224 wide_string
225 from_bytes(const char* __ptr)
226 { return from_bytes(__ptr, __ptr+char_traits<char>::length(__ptr)); }
228 wide_string
229 from_bytes(const byte_string& __str)
231 auto __ptr = __str.data();
232 return from_bytes(__ptr, __ptr + __str.size());
235 wide_string
236 from_bytes(const char* __first, const char* __last)
238 if (!_M_with_cvtstate)
239 _M_state = state_type();
240 wide_string __out{ _M_wide_err_string.get_allocator() };
241 if (__str_codecvt_in(__first, __last, __out, *_M_cvt, _M_state,
242 _M_count))
243 return __out;
244 if (_M_with_strings)
245 return _M_wide_err_string;
246 __throw_range_error("wstring_convert::from_bytes");
248 /// @}
250 /// @{ Convert to bytes.
251 byte_string
252 to_bytes(_Elem __wchar)
254 _Elem __wchars[2] = { __wchar };
255 return to_bytes(__wchars, __wchars+1);
258 byte_string
259 to_bytes(const _Elem* __ptr)
261 return to_bytes(__ptr, __ptr+wide_string::traits_type::length(__ptr));
264 byte_string
265 to_bytes(const wide_string& __wstr)
267 auto __ptr = __wstr.data();
268 return to_bytes(__ptr, __ptr + __wstr.size());
271 byte_string
272 to_bytes(const _Elem* __first, const _Elem* __last)
274 if (!_M_with_cvtstate)
275 _M_state = state_type();
276 byte_string __out{ _M_byte_err_string.get_allocator() };
277 if (__str_codecvt_out(__first, __last, __out, *_M_cvt, _M_state,
278 _M_count))
279 return __out;
280 if (_M_with_strings)
281 return _M_byte_err_string;
282 __throw_range_error("wstring_convert::to_bytes");
284 /// @}
286 // _GLIBCXX_RESOLVE_LIB_DEFECTS
287 // 2174. wstring_convert::converted() should be noexcept
288 /// The number of elements successfully converted in the last conversion.
289 size_t converted() const noexcept { return _M_count; }
291 /// The final conversion state of the last conversion.
292 state_type state() const { return _M_state; }
294 private:
295 unique_ptr<_Codecvt> _M_cvt;
296 byte_string _M_byte_err_string;
297 wide_string _M_wide_err_string;
298 state_type _M_state = state_type();
299 size_t _M_count = 0;
300 bool _M_with_cvtstate = false;
301 bool _M_with_strings = false;
304 /// Buffer conversions
305 template<typename _Codecvt, typename _Elem = wchar_t,
306 typename _Tr = char_traits<_Elem>>
307 class wbuffer_convert : public basic_streambuf<_Elem, _Tr>
309 typedef basic_streambuf<_Elem, _Tr> _Wide_streambuf;
311 public:
312 typedef typename _Codecvt::state_type state_type;
314 /** Default constructor.
316 * @param __bytebuf The underlying byte stream buffer.
317 * @param __pcvt The facet to use for conversions.
318 * @param __state Initial conversion state.
320 * Takes ownership of @p __pcvt and will delete it in the destructor.
322 explicit
323 wbuffer_convert(streambuf* __bytebuf = 0, _Codecvt* __pcvt = new _Codecvt,
324 state_type __state = state_type())
325 : _M_buf(__bytebuf), _M_cvt(__pcvt), _M_state(__state)
327 if (!_M_cvt)
328 __throw_logic_error("wstring_convert");
330 _M_always_noconv = _M_cvt->always_noconv();
332 if (_M_buf)
334 this->setp(_M_put_area, _M_put_area + _S_buffer_length);
335 this->setg(_M_get_area + _S_putback_length,
336 _M_get_area + _S_putback_length,
337 _M_get_area + _S_putback_length);
341 ~wbuffer_convert() = default;
343 // _GLIBCXX_RESOLVE_LIB_DEFECTS
344 // 2176. Special members for wstring_convert and wbuffer_convert
345 wbuffer_convert(const wbuffer_convert&) = delete;
346 wbuffer_convert& operator=(const wbuffer_convert&) = delete;
348 streambuf* rdbuf() const noexcept { return _M_buf; }
350 streambuf*
351 rdbuf(streambuf *__bytebuf) noexcept
353 auto __prev = _M_buf;
354 _M_buf = __bytebuf;
355 return __prev;
358 /// The conversion state following the last conversion.
359 state_type state() const noexcept { return _M_state; }
361 protected:
363 sync()
364 { return _M_buf && _M_conv_put() && _M_buf->pubsync() ? 0 : -1; }
366 typename _Wide_streambuf::int_type
367 overflow(typename _Wide_streambuf::int_type __out)
369 if (!_M_buf || !_M_conv_put())
370 return _Tr::eof();
371 else if (!_Tr::eq_int_type(__out, _Tr::eof()))
372 return this->sputc(__out);
373 return _Tr::not_eof(__out);
376 typename _Wide_streambuf::int_type
377 underflow()
379 if (!_M_buf)
380 return _Tr::eof();
382 if (this->gptr() < this->egptr() || (_M_buf && _M_conv_get()))
383 return _Tr::to_int_type(*this->gptr());
384 else
385 return _Tr::eof();
388 streamsize
389 xsputn(const typename _Wide_streambuf::char_type* __s, streamsize __n)
391 if (!_M_buf || __n == 0)
392 return 0;
393 streamsize __done = 0;
396 auto __nn = std::min<streamsize>(this->epptr() - this->pptr(),
397 __n - __done);
398 _Tr::copy(this->pptr(), __s + __done, __nn);
399 this->pbump(__nn);
400 __done += __nn;
401 } while (__done < __n && _M_conv_put());
402 return __done;
405 private:
406 // fill the get area from converted contents of the byte stream buffer
407 bool
408 _M_conv_get()
410 const streamsize __pb1 = this->gptr() - this->eback();
411 const streamsize __pb2 = _S_putback_length;
412 const streamsize __npb = std::min(__pb1, __pb2);
414 _Tr::move(_M_get_area + _S_putback_length - __npb,
415 this->gptr() - __npb, __npb);
417 streamsize __nbytes = sizeof(_M_get_buf) - _M_unconv;
418 __nbytes = std::min(__nbytes, _M_buf->in_avail());
419 if (__nbytes < 1)
420 __nbytes == 1;
421 __nbytes = _M_buf->sgetn(_M_get_buf + _M_unconv, __nbytes);
422 if (__nbytes < 1)
423 return false;
424 __nbytes += _M_unconv;
426 // convert _M_get_buf into _M_get_area
428 _Elem* __outbuf = _M_get_area + _S_putback_length;
429 _Elem* __outnext = __outbuf;
430 const char* __bnext = _M_get_buf;
432 codecvt_base::result __result;
433 if (_M_always_noconv)
434 __result = codecvt_base::noconv;
435 else
437 _Elem* __outend = _M_get_area + _S_buffer_length;
439 __result = _M_cvt->in(_M_state,
440 __bnext, __bnext + __nbytes, __bnext,
441 __outbuf, __outend, __outnext);
444 if (__result == codecvt_base::noconv)
446 // cast is safe because noconv means _Elem is same type as char
447 auto __get_buf = reinterpret_cast<const _Elem*>(_M_get_buf);
448 _Tr::copy(__outbuf, __get_buf, __nbytes);
449 _M_unconv = 0;
450 return true;
453 if ((_M_unconv = _M_get_buf + __nbytes - __bnext))
454 char_traits<char>::move(_M_get_buf, __bnext, _M_unconv);
456 this->setg(__outbuf, __outbuf, __outnext);
458 return __result != codecvt_base::error;
461 // unused
462 bool
463 _M_put(...)
464 { return false; }
466 bool
467 _M_put(const char* __p, streamsize __n)
469 if (_M_buf->sputn(__p, __n) < __n)
470 return false;
473 // convert the put area and write to the byte stream buffer
474 bool
475 _M_conv_put()
477 _Elem* const __first = this->pbase();
478 const _Elem* const __last = this->pptr();
479 const streamsize __pending = __last - __first;
481 if (_M_always_noconv)
482 return _M_put(__first, __pending);
484 char __outbuf[2 * _S_buffer_length];
486 const _Elem* __next = __first;
487 const _Elem* __start;
490 __start = __next;
491 char* __outnext = __outbuf;
492 char* const __outlast = __outbuf + sizeof(__outbuf);
493 auto __result = _M_cvt->out(_M_state, __next, __last, __next,
494 __outnext, __outlast, __outnext);
495 if (__result == codecvt_base::error)
496 return false;
497 else if (__result == codecvt_base::noconv)
498 return _M_put(__next, __pending);
500 if (!_M_put(__outbuf, __outnext - __outbuf))
501 return false;
503 while (__next != __last && __next != __start);
505 if (__next != __last)
506 _Tr::move(__first, __next, __last - __next);
508 this->pbump(__first - __next);
509 return __next != __first;
512 streambuf* _M_buf;
513 unique_ptr<_Codecvt> _M_cvt;
514 state_type _M_state;
516 static const streamsize _S_buffer_length = 32;
517 static const streamsize _S_putback_length = 3;
518 _Elem _M_put_area[_S_buffer_length];
519 _Elem _M_get_area[_S_buffer_length];
520 streamsize _M_unconv = 0;
521 char _M_get_buf[_S_buffer_length-_S_putback_length];
522 bool _M_always_noconv;
525 /// @} group locales
527 #endif // _GLIBCXX_USE_WCHAR_T
529 _GLIBCXX_END_NAMESPACE_VERSION
530 } // namespace
532 #endif // __cplusplus
534 #endif /* _LOCALE_CONV_H */