This defines the C++11 header <codecvt> and adds the wstring_convert and wbuffer_convert utilities.
These need lots more tests, so if anyone understands how to use them please test them and report problems to Bugzilla. Tested x86_64-linux, committed to trunk.
commit dd8ed5fe16c0d0a5805504da9ea98da86837a550 Author: Jonathan Wakely <jwak...@redhat.com> Date: Fri Jan 16 23:07:50 2015 +0000 Implement C++11 <codecvt> header. * config/abi/pre/gnu.ver: Export new symbols. * include/Makefile.am: Add codecvt. * include/Makefile.in: Regenerate. * include/std/codecvt: New header. * src/c++11/codecvt.cc (__codecvt_utf8_base, __codecvt_utf16_base, __codecvt_utf8_utf16_base): Define specializations. * testsuite/22_locale/codecvt/codecvt_utf8/requirements/1.cc: New. * testsuite/22_locale/codecvt/codecvt_utf16/requirements/1.cc: New. * testsuite/22_locale/codecvt/codecvt_utf8_utf16/requirements/1.cc: New. diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver index dc83ad4..d23306e 100644 --- a/libstdc++-v3/config/abi/pre/gnu.ver +++ b/libstdc++-v3/config/abi/pre/gnu.ver @@ -1769,6 +1769,17 @@ GLIBCXX_3.4.21 { std::__atomic_futex_unsigned_base*; }; + # codecvt_utf8 etc. + _ZNKSt19__codecvt_utf8_base*; + _ZNSt19__codecvt_utf8_base*; + _ZT[ISV]St19__codecvt_utf8_base*; + _ZNKSt20__codecvt_utf16_base*; + _ZNSt20__codecvt_utf16_base*; + _ZT[ISV]St20__codecvt_utf16_base*; + _ZNKSt25__codecvt_utf8_utf16_base*; + _ZNSt25__codecvt_utf8_utf16_base*; + _ZT[ISV]St25__codecvt_utf8_utf16_base*; + } GLIBCXX_3.4.20; diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am index 4772950..285a504 100644 --- a/libstdc++-v3/include/Makefile.am +++ b/libstdc++-v3/include/Makefile.am @@ -31,6 +31,7 @@ std_headers = \ ${std_srcdir}/atomic \ ${std_srcdir}/bitset \ ${std_srcdir}/chrono \ + ${std_srcdir}/codecvt \ ${std_srcdir}/complex \ ${std_srcdir}/condition_variable \ ${std_srcdir}/deque \ diff --git a/libstdc++-v3/include/std/codecvt b/libstdc++-v3/include/std/codecvt new file mode 100644 index 0000000..d58a0ec --- /dev/null +++ b/libstdc++-v3/include/std/codecvt @@ -0,0 +1,179 @@ +// <codecvt> -*- C++ -*- + +// Copyright (C) 2015 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// <http://www.gnu.org/licenses/>. + +// ISO C++ 14882: 22.5 Standard code conversion facets + +/** @file include/codecvt + * This is a Standard C++ Library header. + */ + +#ifndef _GLIBCXX_CODECVT +#define _GLIBCXX_CODECVT 1 + +#pragma GCC system_header + +#if __cplusplus < 201103L +# include <bits/c++0x_warning.h> +#else + +#include <bits/locale_classes.h> +#include <bits/codecvt.h> + +#ifdef _GLIBCXX_USE_C99_STDINT_TR1 + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + enum codecvt_mode + { + consume_header = 4, + generate_header = 2, + little_endian = 1 + }; + + template<typename _Elem, unsigned long _Maxcode = 0x10ffff, + codecvt_mode _Mode = (codecvt_mode)0> + class codecvt_utf8 : public codecvt<_Elem, char, mbstate_t> + { + public: + explicit + codecvt_utf8(size_t __refs = 0); + + ~codecvt_utf8(); + }; + + template<typename _Elem, unsigned long _Maxcode = 0x10ffff, + codecvt_mode _Mode = (codecvt_mode)0> + class codecvt_utf16 : public codecvt<_Elem, char, mbstate_t> + { + public: + explicit + codecvt_utf16(size_t __refs = 0); + + ~codecvt_utf16(); + }; + + template<typename _Elem, unsigned long _Maxcode = 0x10ffff, + codecvt_mode _Mode = (codecvt_mode)0> + class codecvt_utf8_utf16 : public codecvt<_Elem, char, mbstate_t> + { + public: + explicit + codecvt_utf8_utf16(size_t __refs = 0); + + ~codecvt_utf8_utf16(); + }; + +#define _GLIBCXX_CODECVT_SPECIALIZATION2(_NAME, _ELEM) \ + template<> \ + class _NAME<_ELEM> \ + : public codecvt<_ELEM, char, mbstate_t> \ + { \ + public: \ + typedef _ELEM intern_type; \ + typedef char extern_type; \ + typedef mbstate_t state_type; \ + \ + protected: \ + _NAME(unsigned long __maxcode, codecvt_mode __mode, size_t __refs) \ + : codecvt(__refs), _M_maxcode(__maxcode), _M_mode(__mode) { } \ + \ + virtual \ + ~_NAME(); \ + \ + virtual result \ + do_out(state_type& __state, const intern_type* __from, \ + const intern_type* __from_end, const intern_type*& __from_next, \ + extern_type* __to, extern_type* __to_end, \ + extern_type*& __to_next) const; \ + \ + virtual result \ + do_unshift(state_type& __state, \ + extern_type* __to, extern_type* __to_end, \ + extern_type*& __to_next) const; \ + \ + virtual result \ + do_in(state_type& __state, \ + const extern_type* __from, const extern_type* __from_end, \ + const extern_type*& __from_next, \ + intern_type* __to, intern_type* __to_end, \ + intern_type*& __to_next) const; \ + \ + virtual \ + int do_encoding() const throw(); \ + \ + virtual \ + bool do_always_noconv() const throw(); \ + \ + virtual \ + int do_length(state_type&, const extern_type* __from, \ + const extern_type* __end, size_t __max) const; \ + \ + virtual int \ + do_max_length() const throw(); \ + \ + private: \ + unsigned long _M_maxcode; \ + codecvt_mode _M_mode; \ + } + +#define _GLIBCXX_CODECVT_SPECIALIZATION(_NAME, _ELEM) \ + _GLIBCXX_CODECVT_SPECIALIZATION2(__ ## _NAME ## _base, _ELEM); \ + template<unsigned long _Maxcode, codecvt_mode _Mode> \ + class _NAME<_ELEM, _Maxcode, _Mode> \ + : public __ ## _NAME ## _base<_ELEM> \ + { \ + public: \ + explicit \ + _NAME(size_t __refs = 0) \ + : __ ## _NAME ## _base<_ELEM>(_Maxcode, _Mode, __refs) { } \ + } + + template<typename _Elem> class __codecvt_utf8_base; + template<typename _Elem> class __codecvt_utf16_base; + template<typename _Elem> class __codecvt_utf8_utf16_base; + + _GLIBCXX_CODECVT_SPECIALIZATION(codecvt_utf8, char16_t); + _GLIBCXX_CODECVT_SPECIALIZATION(codecvt_utf16, char16_t); + _GLIBCXX_CODECVT_SPECIALIZATION(codecvt_utf8_utf16, char16_t); + + _GLIBCXX_CODECVT_SPECIALIZATION(codecvt_utf8, char32_t); + _GLIBCXX_CODECVT_SPECIALIZATION(codecvt_utf16, char32_t); + _GLIBCXX_CODECVT_SPECIALIZATION(codecvt_utf8_utf16, char32_t); + +#ifdef _GLIBCXX_USE_WCHAR_T + _GLIBCXX_CODECVT_SPECIALIZATION(codecvt_utf8, wchar_t); + _GLIBCXX_CODECVT_SPECIALIZATION(codecvt_utf16, wchar_t); + _GLIBCXX_CODECVT_SPECIALIZATION(codecvt_utf8_utf16, wchar_t); +#endif + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#endif // _GLIBCXX_USE_C99_STDINT_TR1 + +#endif + +#endif /* _GLIBCXX_CODECVT */ diff --git a/libstdc++-v3/src/c++11/codecvt.cc b/libstdc++-v3/src/c++11/codecvt.cc index fdd4972..7eed903 100644 --- a/libstdc++-v3/src/c++11/codecvt.cc +++ b/libstdc++-v3/src/c++11/codecvt.cc @@ -22,10 +22,9 @@ // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see // <http://www.gnu.org/licenses/>. -#include <bits/locale_classes.h> -#include <bits/codecvt.h> -#include <bits/stl_algobase.h> // std::max +#include <codecvt> #include <cstring> // std::memcpy, std::memcmp +#include <bits/stl_algobase.h> // std::max #ifdef _GLIBCXX_USE_C99_STDINT_TR1 namespace std _GLIBCXX_VISIBILITY(default) @@ -51,6 +50,88 @@ namespace size_t size() const { return end - next; } }; + // Multibyte sequences can have "header" consisting of Byte Order Mark + const unsigned char utf8_bom[3] = { 0xEF, 0xBB, 0xBF }; + const unsigned char utf16_bom[4] = { 0xFE, 0xFF }; + const unsigned char utf16le_bom[4] = { 0xFF, 0xFE }; + + template<size_t N> + inline bool + write_bom(range<char>& to, const unsigned char (&bom)[N]) + { + if (to.size() < N) + return false; + memcpy(to.next, bom, N); + to.next += N; + return true; + } + + // If generate_header is set in mode write out UTF-8 BOM. + bool + write_utf8_bom(range<char>& to, codecvt_mode mode) + { + if (mode & generate_header) + return write_bom(to, utf8_bom); + return true; + } + + // If generate_header is set in mode write out the UTF-16 BOM indicated + // by whether little_endian is set in mode. + bool + write_utf16_bom(range<char16_t>& to, codecvt_mode mode) + { + if (mode & generate_header) + { + if (!to.size()) + return false; + auto* bom = (mode & little_endian) ? utf16le_bom : utf16_bom; + std::memcpy(to.next, bom, 2); + ++to.next; + } + return true; + } + + template<size_t N> + inline bool + read_bom(range<const char>& from, const unsigned char (&bom)[N]) + { + if (from.size() >= N && !memcmp(from.next, bom, N)) + { + from.next += N; + return true; + } + return false; + } + + // If consume_header is set in mode update from.next to after any BOM. + void + read_utf8_bom(range<const char>& from, codecvt_mode mode) + { + if (mode & consume_header) + read_bom(from, utf8_bom); + } + + // If consume_header is set in mode update from.next to after any BOM. + // Return little_endian iff the UTF-16LE BOM was present. + codecvt_mode + read_utf16_bom(range<const char16_t>& from, codecvt_mode mode) + { + if (mode & consume_header && from.size()) + { + if (*from.next == 0xFEFF) + ++from.next; + else if (*from.next == 0xFFFE) + { + ++from.next; + return little_endian; + } + } + return {}; + } + + // Read a codepoint from a UTF-8 multibyte sequence. + // Updates from.next if the codepoint is not greater than maxcode. + // Returns -1 if there is an invalid or incomplete multibyte character. char32_t read_utf8_code_point(range<const char>& from, unsigned long maxcode) { @@ -74,9 +155,8 @@ namespace if ((c2 & 0xC0) != 0x80) return -1; char32_t c = (c1 << 6) + c2 - 0x3080; - if (c > maxcode) - return -1; - from.next += 2; + if (c <= maxcode) + from.next += 2; return c; } else if (c1 < 0xF0) // 3-byte sequence @@ -92,9 +172,8 @@ namespace if ((c3 & 0xC0) != 0x80) return -1; char32_t c = (c1 << 12) + (c2 << 6) + c3 - 0xE2080; - if (c > maxcode) - return -1; - from.next += 3; + if (c <= maxcode) + from.next += 3; return c; } else if (c1 < 0xF5) // 4-byte sequence @@ -115,9 +194,8 @@ namespace if ((c4 & 0xC0) != 0x80) return -1; char32_t c = (c1 << 18) + (c2 << 12) + (c3 << 6) + c4 - 0x3C82080; - if (c > maxcode) - return -1; - from.next += 4; + if (c <= maxcode) + from.next += 4; return c; } else // > U+10FFFF @@ -162,9 +240,48 @@ namespace return true; } + inline char16_t + adjust_byte_order(char16_t c, codecvt_mode mode) + { +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + return (mode & little_endian) ? __builtin_bswap16(c) : c; +#else + return (mode & little_endian) ? c : __builtin_bswap16(c); +#endif + } + + // Read a codepoint from a UTF-16 multibyte sequence. + // The sequence's endianness is indicated by (mode & little_endian). + // Updates from.next if the codepoint is not greater than maxcode. + // Returns -1 if there is an incomplete multibyte character. + char32_t + read_utf16_code_point(range<const char16_t>& from, unsigned long maxcode, + codecvt_mode mode) + { + int inc = 1; + char32_t c = adjust_byte_order(from.next[0], mode); + if (c >= 0xD800 && c <= 0xDBFF) + { + if (from.size() < 2) + return -1; + const char16_t c2 = adjust_byte_order(from.next[1], mode); + if (c2 >= 0xDC00 && c2 <= 0xDFFF) + { + c = (c << 10) + c2 - 0x35FDC00; + inc = 2; + } + } + if (c <= maxcode) + from.next += inc; + return c; + } + + template<typename C> bool - write_utf16_code_point(range<char16_t>& to, char32_t codepoint) + write_utf16_code_point(range<C>& to, char32_t codepoint, codecvt_mode mode) { + static_assert(sizeof(C) >= 2, "a code unit must be at least 16-bit"); + if (codepoint < max_single_utf16_unit) { if (to.size() > 0) @@ -183,8 +300,8 @@ namespace char16_t trail = 0xDC00 + (codepoint & 0x3FF); char32_t utf16bytes = (lead << 10) + trail + SURROGATE_OFFSET; - to.next[0] = utf16bytes >> 16; - to.next[1] = utf16bytes & 0xFFFF; + to.next[0] = adjust_byte_order(utf16bytes >> 16, mode); + to.next[1] = adjust_byte_order(utf16bytes & 0xFFFF, mode); to.next += 2; return true; } @@ -194,12 +311,15 @@ namespace // utf8 -> ucs4 codecvt_base::result ucs4_in(range<const char>& from, range<char32_t>& to, - unsigned long maxcode = max_code_point) + unsigned long maxcode = max_code_point, codecvt_mode mode = {}) { + read_utf8_bom(from, mode); while (from.size() && to.size()) { const char32_t codepoint = read_utf8_code_point(from, maxcode); - if (codepoint == char32_t(-1) || codepoint > maxcode) + if (codepoint == char32_t(-1)) + break; + if (codepoint > maxcode) return codecvt_base::error; *to.next++ = codepoint; } @@ -209,8 +329,10 @@ namespace // ucs4 -> utf8 codecvt_base::result ucs4_out(range<const char32_t>& from, range<char>& to, - unsigned long maxcode = max_code_point) + unsigned long maxcode = max_code_point, codecvt_mode mode = {}) { + if (!write_utf8_bom(to, mode)) + return codecvt_base::partial; while (from.size()) { const char32_t c = from.next[0]; @@ -223,20 +345,62 @@ namespace return codecvt_base::ok; } + // utf16 -> ucs4 + codecvt_base::result + ucs4_in(range<const char16_t>& from, range<char32_t>& to, + unsigned long maxcode = max_code_point, codecvt_mode mode = {}) + { + if (read_utf16_bom(from, mode) == little_endian) + mode = codecvt_mode(mode & little_endian); + while (from.size() && to.size()) + { + const char32_t codepoint = read_utf16_code_point(from, maxcode, mode); + if (codepoint == char32_t(-1)) + break; + if (codepoint > maxcode) + return codecvt_base::error; + *to.next++ = codepoint; + } + return from.size() ? codecvt_base::partial : codecvt_base::ok; + } + + // ucs4 -> utf16 + codecvt_base::result + ucs4_out(range<const char32_t>& from, range<char16_t>& to, + unsigned long maxcode = max_code_point, codecvt_mode mode = {}) + { + if (!write_utf16_bom(to, mode)) + return codecvt_base::partial; + while (from.size()) + { + const char32_t c = from.next[0]; + if (c > maxcode) + return codecvt_base::error; + if (!write_utf16_code_point(to, c, mode)) + return codecvt_base::partial; + ++from.next; + } + return codecvt_base::ok; + } + // utf8 -> utf16 + template<typename C> codecvt_base::result - utf16_in(range<const char>& from, range<char16_t>& to, - unsigned long maxcode = max_code_point) + utf16_in(range<const char>& from, range<C>& to, + unsigned long maxcode = max_code_point, codecvt_mode mode = {}) { + read_utf8_bom(from, mode); while (from.size() && to.size()) { const char* first = from.next; if ((unsigned char)*first >= 0xF0 && to.size() < 2) return codecvt_base::partial; const char32_t codepoint = read_utf8_code_point(from, maxcode); - if (codepoint == char32_t(-1) || codepoint > maxcode) + if (codepoint == char32_t(-1)) + return codecvt_base::partial; + if (codepoint > maxcode) return codecvt_base::error; - if (!write_utf16_code_point(to, codepoint)) + if (!write_utf16_code_point(to, codepoint, {})) { from.next = first; return codecvt_base::partial; @@ -246,15 +410,18 @@ namespace } // utf16 -> utf8 + template<typename C> codecvt_base::result - utf16_out(range<const char16_t>& from, range<char>& to, - unsigned long maxcode = max_code_point) + utf16_out(range<const C>& from, range<char>& to, + unsigned long maxcode = max_code_point, codecvt_mode mode = {}) { + if (!write_utf8_bom(to, mode)) + return codecvt_base::partial; while (from.size()) { char32_t c = from.next[0]; int inc = 1; - if (c >= 0xD800 && c < 0xDBFF) // start of surrogate pair + if (c >= 0xD800 && c <= 0xDBFF) // start of surrogate pair { if (from.size() < 2) return codecvt_base::ok; // stop converting at this point @@ -278,11 +445,12 @@ namespace } // return pos such that [begin,pos) is valid UTF-16 string no longer than max - int - utf16_len(const char* begin, const char* end, size_t max, - char32_t maxcode = max_code_point) + const char* + utf16_span(const char* begin, const char* end, size_t max, + char32_t maxcode = max_code_point, codecvt_mode mode = {}) { range<const char> from{ begin, end }; + read_utf8_bom(from, mode); size_t count = 0; while (count+1 < max) { @@ -295,24 +463,117 @@ namespace } if (count+1 == max) // take one more character if it fits in a single unit read_utf8_code_point(from, std::max(max_single_utf16_unit, maxcode)); - return from.next - begin; + return from.next; } - // return pos such that [begin,pos) is valid UCS-4 string no longer than max - int - ucs4_len(const char* begin, const char* end, size_t max, - char32_t maxcode = max_code_point) + // utf8 -> ucs2 + codecvt_base::result + ucs2_in(range<const char>& from, range<char16_t>& to, + char32_t maxcode = max_code_point, codecvt_mode mode = {}) { - range<const char> from{ begin, end }; - size_t count = 0; - while (count < max) + return utf16_in(from, to, std::max(max_single_utf16_unit, maxcode), mode); + } + + // ucs2 -> utf8 + codecvt_base::result + ucs2_out(range<const char16_t>& from, range<char>& to, + char32_t maxcode = max_code_point, codecvt_mode mode = {}) + { + return utf16_out(from, to, std::max(max_single_utf16_unit, maxcode), mode); + } + + // ucs2 -> utf16 + codecvt_base::result + ucs2_out(range<const char16_t>& from, range<char16_t>& to, + char32_t maxcode = max_code_point, codecvt_mode mode = {}) + { + if (!write_utf16_bom(to, mode)) + return codecvt_base::partial; + while (from.size() && to.size()) { - char32_t c = read_utf8_code_point(from, maxcode); + char16_t c = from.next[0]; + if (c >= 0xD800 && c <= 0xDBFF) // start of surrogate pair + return codecvt_base::error; + if (c > maxcode) + return codecvt_base::error; + *to.next++ = adjust_byte_order(c, mode); + ++from.next; + } + return from.size() == 0 ? codecvt_base::ok : codecvt_base::partial; + } + + // utf16 -> ucs2 + codecvt_base::result + ucs2_in(range<const char16_t>& from, range<char16_t>& to, + char32_t maxcode = max_code_point, codecvt_mode mode = {}) + { + if (read_utf16_bom(from, mode) == little_endian) + mode = codecvt_mode(mode & little_endian); + maxcode = std::max(max_single_utf16_unit, maxcode); + while (from.size() && to.size()) + { + const char32_t c = read_utf16_code_point(from, maxcode, mode); if (c == char32_t(-1)) break; - ++count; + if (c >= maxcode) + return codecvt_base::error; + *to.next++ = c; } - return from.next - begin; + return from.size() == 0 ? codecvt_base::ok : codecvt_base::partial; + } + + const char16_t* + ucs2_span(const char16_t* begin, const char16_t* end, size_t max, + char32_t maxcode, codecvt_mode mode) + { + range<const char16_t> from{ begin, end }; + if (read_utf16_bom(from, mode) == little_endian) + mode = codecvt_mode(mode & little_endian); + maxcode = std::max(max_single_utf16_unit, maxcode); + char32_t c = 0; + while (max-- && c <= maxcode) + c = read_utf16_code_point(from, maxcode, mode); + return from.next; + } + + const char* + ucs2_span(const char* begin, const char* end, size_t max, + char32_t maxcode, codecvt_mode mode) + { + range<const char> from{ begin, end }; + read_utf8_bom(from, mode); + maxcode = std::max(max_single_utf16_unit, maxcode); + char32_t c = 0; + while (max-- && c <= maxcode) + c = read_utf8_code_point(from, maxcode); + return from.next; + } + + // return pos such that [begin,pos) is valid UCS-4 string no longer than max + const char* + ucs4_span(const char* begin, const char* end, size_t max, + char32_t maxcode = max_code_point, codecvt_mode mode = {}) + { + range<const char> from{ begin, end }; + read_utf8_bom(from, mode); + char32_t c = 0; + while (max-- && c <= maxcode) + c = read_utf8_code_point(from, maxcode); + return from.next; + } + + // return pos such that [begin,pos) is valid UCS-4 string no longer than max + const char16_t* + ucs4_span(const char16_t* begin, const char16_t* end, size_t max, + char32_t maxcode = max_code_point, codecvt_mode mode = {}) + { + range<const char16_t> from{ begin, end }; + if (read_utf16_bom(from, mode) == little_endian) + mode = codecvt_mode(mode & little_endian); + char32_t c = 0; + while (max-- && c <= maxcode) + c = read_utf16_code_point(from, maxcode, mode); + return from.next; } } @@ -376,7 +637,8 @@ codecvt<char16_t, char, mbstate_t>:: do_length(state_type&, const extern_type* __from, const extern_type* __end, size_t __max) const { - return utf16_len(__from, __end, __max); + __end = utf16_span(__from, __end, __max); + return __end - __from; } int @@ -446,13 +708,698 @@ codecvt<char32_t, char, mbstate_t>:: do_length(state_type&, const extern_type* __from, const extern_type* __end, size_t __max) const { - return ucs4_len(__from, __end, __max); + __end = ucs4_span(__from, __end, __max); + return __end - __from; } int codecvt<char32_t, char, mbstate_t>::do_max_length() const throw() { return 4; } +// Define members of codecvt_utf8<char16_t> base class implementation. +// Converts from UTF-8 to UCS-2. + +__codecvt_utf8_base<char16_t>::~__codecvt_utf8_base() { } + +codecvt_base::result +__codecvt_utf8_base<char16_t>:: +do_out(state_type&, const intern_type* __from, const intern_type* __from_end, + const intern_type*& __from_next, + extern_type* __to, extern_type* __to_end, + extern_type*& __to_next) const +{ + range<const char16_t> from{ __from, __from_end }; + range<char> to{ __to, __to_end }; + auto res = ucs2_out(from, to, _M_maxcode, _M_mode); + __from_next = from.next; + __to_next = to.next; + return res; +} + +codecvt_base::result +__codecvt_utf8_base<char16_t>:: +do_unshift(state_type&, extern_type* __to, extern_type*, + extern_type*& __to_next) const +{ + __to_next = __to; + return noconv; +} + +codecvt_base::result +__codecvt_utf8_base<char16_t>:: +do_in(state_type&, const extern_type* __from, const extern_type* __from_end, + const extern_type*& __from_next, + intern_type* __to, intern_type* __to_end, + intern_type*& __to_next) const +{ + range<const char> from{ __from, __from_end }; + range<char16_t> to{ __to, __to_end }; + auto res = ucs2_in(from, to, _M_maxcode, _M_mode); + __from_next = from.next; + __to_next = to.next; + return res; +} + +int +__codecvt_utf8_base<char16_t>::do_encoding() const throw() +{ return 0; } + +bool +__codecvt_utf8_base<char16_t>::do_always_noconv() const throw() +{ return false; } + +int +__codecvt_utf8_base<char16_t>:: +do_length(state_type&, const extern_type* __from, + const extern_type* __end, size_t __max) const +{ + __end = ucs2_span(__from, __end, __max, _M_maxcode, _M_mode); + return __end - __from; +} + +int +__codecvt_utf8_base<char16_t>::do_max_length() const throw() +{ return 3; } + +// Define members of codecvt_utf8<char32_t> base class implementation. +// Converts from UTF-8 to UTF-32 (aka UCS-4). + +__codecvt_utf8_base<char32_t>::~__codecvt_utf8_base() { } + +codecvt_base::result +__codecvt_utf8_base<char32_t>:: +do_out(state_type&, const intern_type* __from, const intern_type* __from_end, + const intern_type*& __from_next, + extern_type* __to, extern_type* __to_end, + extern_type*& __to_next) const +{ + range<const char32_t> from{ __from, __from_end }; + range<char> to{ __to, __to_end }; + auto res = ucs4_out(from, to, _M_maxcode, _M_mode); + __from_next = from.next; + __to_next = to.next; + return res; +} + +codecvt_base::result +__codecvt_utf8_base<char32_t>:: +do_unshift(state_type&, extern_type* __to, extern_type*, + extern_type*& __to_next) const +{ + __to_next = __to; + return noconv; +} + +codecvt_base::result +__codecvt_utf8_base<char32_t>:: +do_in(state_type&, const extern_type* __from, const extern_type* __from_end, + const extern_type*& __from_next, + intern_type* __to, intern_type* __to_end, + intern_type*& __to_next) const +{ + range<const char> from{ __from, __from_end }; + range<char32_t> to{ __to, __to_end }; + auto res = ucs4_in(from, to, _M_maxcode, _M_mode); + __from_next = from.next; + __to_next = to.next; + return res; +} + +int +__codecvt_utf8_base<char32_t>::do_encoding() const throw() +{ return 0; } + +bool +__codecvt_utf8_base<char32_t>::do_always_noconv() const throw() +{ return false; } + +int +__codecvt_utf8_base<char32_t>:: +do_length(state_type&, const extern_type* __from, + const extern_type* __end, size_t __max) const +{ + __end = ucs4_span(__from, __end, __max, _M_maxcode, _M_mode); + return __end - __from; +} + +int +__codecvt_utf8_base<char32_t>::do_max_length() const throw() +{ return 4; } + +#ifdef _GLIBCXX_USE_WCHAR_T +// Define members of codecvt_utf8<wchar_t> base class implementation. +// Converts from UTF-8 to UCS-2 or UCS-4 depending on sizeof(wchar_t). + +__codecvt_utf8_base<wchar_t>::~__codecvt_utf8_base() { } + +codecvt_base::result +__codecvt_utf8_base<wchar_t>:: +do_out(state_type&, const intern_type* __from, const intern_type* __from_end, + const intern_type*& __from_next, + extern_type* __to, extern_type* __to_end, + extern_type*& __to_next) const +{ + range<char> to{ __to, __to_end }; +#if __SIZEOF_WCHAR_T__ == 2 + range<const char16_t> from{ + reinterpret_cast<const char16_t*>(__from), + reinterpret_cast<const char16_t*>(__from_end) + }; + auto res = ucs2_out(from, to, _M_maxcode, _M_mode); +#elif __SIZEOF_WCHAR_T__ == 4 + range<const char32_t> from{ + reinterpret_cast<const char32_t*>(__from), + reinterpret_cast<const char32_t*>(__from_end) + }; + auto res = ucs4_out(from, to, _M_maxcode, _M_mode); +#else + return codecvt_base::error; +#endif + __from_next = reinterpret_cast<const wchar_t*>(from.next); + __to_next = to.next; + return res; +} + +codecvt_base::result +__codecvt_utf8_base<wchar_t>:: +do_unshift(state_type&, extern_type* __to, extern_type*, + extern_type*& __to_next) const +{ + __to_next = __to; + return noconv; +} + +codecvt_base::result +__codecvt_utf8_base<wchar_t>:: +do_in(state_type&, const extern_type* __from, const extern_type* __from_end, + const extern_type*& __from_next, + intern_type* __to, intern_type* __to_end, + intern_type*& __to_next) const +{ + range<const char> from{ __from, __from_end }; +#if __SIZEOF_WCHAR_T__ == 2 + range<char16_t> to{ + reinterpret_cast<char16_t*>(__to), + reinterpret_cast<char16_t*>(__to_end) + }; + auto res = ucs2_in(from, to, _M_maxcode, _M_mode); +#elif __SIZEOF_WCHAR_T__ == 4 + range<char32_t> to{ + reinterpret_cast<char32_t*>(__to), + reinterpret_cast<char32_t*>(__to_end) + }; + auto res = ucs4_in(from, to, _M_maxcode, _M_mode); +#else + return codecvt_base::error; +#endif + __from_next = from.next; + __to_next = reinterpret_cast<wchar_t*>(to.next); + return res; +} + +int +__codecvt_utf8_base<wchar_t>::do_encoding() const throw() +{ return 0; } + +bool +__codecvt_utf8_base<wchar_t>::do_always_noconv() const throw() +{ return false; } + +int +__codecvt_utf8_base<wchar_t>:: +do_length(state_type&, const extern_type* __from, + const extern_type* __end, size_t __max) const +{ +#if __SIZEOF_WCHAR_T__ == 2 + __end = ucs2_span(__from, __end, __max, _M_maxcode, _M_mode); +#elif __SIZEOF_WCHAR_T__ == 4 + __end = ucs4_span(__from, __end, __max, _M_maxcode, _M_mode); +#else + __end = __from; +#endif + return __end - __from; +} + +int +__codecvt_utf8_base<wchar_t>::do_max_length() const throw() +{ return 4; } +#endif + +// Define members of codecvt_utf16<char16_t> base class implementation. +// Converts from UTF-16 to UCS-2. + +__codecvt_utf16_base<char16_t>::~__codecvt_utf16_base() { } + +codecvt_base::result +__codecvt_utf16_base<char16_t>:: +do_out(state_type&, const intern_type* __from, const intern_type* __from_end, + const intern_type*& __from_next, + extern_type* __to, extern_type* __to_end, + extern_type*& __to_next) const +{ + range<const char16_t> from{ __from, __from_end }; + range<char16_t> to{ + reinterpret_cast<char16_t*>(__to), + reinterpret_cast<char16_t*>(__to_end) + }; + auto res = ucs2_out(from, to, _M_maxcode, _M_mode); + __from_next = from.next; + __to_next = reinterpret_cast<char*>(to.next); + return res; +} + +codecvt_base::result +__codecvt_utf16_base<char16_t>:: +do_unshift(state_type&, extern_type* __to, extern_type*, + extern_type*& __to_next) const +{ + __to_next = __to; + return noconv; +} + +codecvt_base::result +__codecvt_utf16_base<char16_t>:: +do_in(state_type&, const extern_type* __from, const extern_type* __from_end, + const extern_type*& __from_next, + intern_type* __to, intern_type* __to_end, + intern_type*& __to_next) const +{ + range<const char16_t> from{ + reinterpret_cast<const char16_t*>(__from), + reinterpret_cast<const char16_t*>(__from_end) + }; + range<char16_t> to{ __to, __to_end }; + auto res = ucs2_in(from, to, _M_maxcode, _M_mode); + __from_next = reinterpret_cast<const char*>(from.next); + __to_next = to.next; + return res; +} + +int +__codecvt_utf16_base<char16_t>::do_encoding() const throw() +{ return 1; } + +bool +__codecvt_utf16_base<char16_t>::do_always_noconv() const throw() +{ return false; } + +int +__codecvt_utf16_base<char16_t>:: +do_length(state_type&, const extern_type* __from, + const extern_type* __end, size_t __max) const +{ + auto next = reinterpret_cast<const char16_t*>(__from); + next = ucs2_span(next, reinterpret_cast<const char16_t*>(__end), __max, + _M_maxcode, _M_mode); + return reinterpret_cast<const char*>(next) - __from; +} + +int +__codecvt_utf16_base<char16_t>::do_max_length() const throw() +{ return 3; } + +// Define members of codecvt_utf16<char32_t> base class implementation. +// Converts from UTF-16 to UTF-32 (aka UCS-4). + +__codecvt_utf16_base<char32_t>::~__codecvt_utf16_base() { } + +codecvt_base::result +__codecvt_utf16_base<char32_t>:: +do_out(state_type&, const intern_type* __from, const intern_type* __from_end, + const intern_type*& __from_next, + extern_type* __to, extern_type* __to_end, + extern_type*& __to_next) const +{ + range<const char32_t> from{ __from, __from_end }; + range<char16_t> to{ + reinterpret_cast<char16_t*>(__to), + reinterpret_cast<char16_t*>(__to_end) + }; + auto res = ucs4_out(from, to, _M_maxcode, _M_mode); + __from_next = from.next; + __to_next = reinterpret_cast<char*>(to.next); + return res; +} + +codecvt_base::result +__codecvt_utf16_base<char32_t>:: +do_unshift(state_type&, extern_type* __to, extern_type*, + extern_type*& __to_next) const +{ + __to_next = __to; + return noconv; +} + +codecvt_base::result +__codecvt_utf16_base<char32_t>:: +do_in(state_type&, const extern_type* __from, const extern_type* __from_end, + const extern_type*& __from_next, + intern_type* __to, intern_type* __to_end, + intern_type*& __to_next) const +{ + range<const char16_t> from{ + reinterpret_cast<const char16_t*>(__from), + reinterpret_cast<const char16_t*>(__from_end) + }; + range<char32_t> to{ __to, __to_end }; + auto res = ucs4_in(from, to, _M_maxcode, _M_mode); + __from_next = reinterpret_cast<const char*>(from.next); + __to_next = to.next; + return res; +} + +int +__codecvt_utf16_base<char32_t>::do_encoding() const throw() +{ return 0; } + +bool +__codecvt_utf16_base<char32_t>::do_always_noconv() const throw() +{ return false; } + +int +__codecvt_utf16_base<char32_t>:: +do_length(state_type&, const extern_type* __from, + const extern_type* __end, size_t __max) const +{ + auto next = reinterpret_cast<const char16_t*>(__from); + next = ucs4_span(next, reinterpret_cast<const char16_t*>(__end), __max, + _M_maxcode, _M_mode); + return reinterpret_cast<const char*>(next) - __from; +} + +int +__codecvt_utf16_base<char32_t>::do_max_length() const throw() +{ return 3; } + +#ifdef _GLIBCXX_USE_WCHAR_T +// Define members of codecvt_utf16<wchar_t> base class implementation. +// Converts from UTF-8 to UCS-2 or UCS-4 depending on sizeof(wchar_t). + +__codecvt_utf16_base<wchar_t>::~__codecvt_utf16_base() { } + +codecvt_base::result +__codecvt_utf16_base<wchar_t>:: +do_out(state_type&, const intern_type* __from, const intern_type* __from_end, + const intern_type*& __from_next, + extern_type* __to, extern_type* __to_end, + extern_type*& __to_next) const +{ + range<char> to{ __to, __to_end }; +#if __SIZEOF_WCHAR_T__ == 2 + range<const char16_t> from{ + reinterpret_cast<const char16_t*>(__from), + reinterpret_cast<const char16_t*>(__from_end) + }; + auto res = ucs2_out(from, to, _M_maxcode, _M_mode); +#elif __SIZEOF_WCHAR_T__ == 4 + range<const char32_t> from{ + reinterpret_cast<const char32_t*>(__from), + reinterpret_cast<const char32_t*>(__from_end) + }; + auto res = ucs4_out(from, to, _M_maxcode, _M_mode); +#else + return codecvt_base::error; +#endif + __from_next = reinterpret_cast<const wchar_t*>(from.next); + __to_next = to.next; + return res; +} + +codecvt_base::result +__codecvt_utf16_base<wchar_t>:: +do_unshift(state_type&, extern_type* __to, extern_type*, + extern_type*& __to_next) const +{ + __to_next = __to; + return noconv; +} + +codecvt_base::result +__codecvt_utf16_base<wchar_t>:: +do_in(state_type&, const extern_type* __from, const extern_type* __from_end, + const extern_type*& __from_next, + intern_type* __to, intern_type* __to_end, + intern_type*& __to_next) const +{ + range<const char> from{ __from, __from_end }; +#if __SIZEOF_WCHAR_T__ == 2 + range<char16_t> to{ + reinterpret_cast<char16_t*>(__to), + reinterpret_cast<char16_t*>(__to_end) + }; + auto res = ucs2_in(from, to, _M_maxcode, _M_mode); +#elif __SIZEOF_WCHAR_T__ == 4 + range<char32_t> to{ + reinterpret_cast<char32_t*>(__to), + reinterpret_cast<char32_t*>(__to_end) + }; + auto res = ucs4_in(from, to, _M_maxcode, _M_mode); +#else + return codecvt_base::error; +#endif + __from_next = from.next; + __to_next = reinterpret_cast<wchar_t*>(to.next); + return res; +} + +int +__codecvt_utf16_base<wchar_t>::do_encoding() const throw() +{ return 0; } + +bool +__codecvt_utf16_base<wchar_t>::do_always_noconv() const throw() +{ return false; } + +int +__codecvt_utf16_base<wchar_t>:: +do_length(state_type&, const extern_type* __from, + const extern_type* __end, size_t __max) const +{ + auto next = reinterpret_cast<const char16_t*>(__from); +#if __SIZEOF_WCHAR_T__ == 2 + next = ucs2_span(next, reinterpret_cast<const char16_t*>(__end), __max, + _M_maxcode, _M_mode); +#elif __SIZEOF_WCHAR_T__ == 4 + next = ucs4_span(next, reinterpret_cast<const char16_t*>(__end), __max, + _M_maxcode, _M_mode); +#endif + return reinterpret_cast<const char*>(next) - __from; +} + +int +__codecvt_utf16_base<wchar_t>::do_max_length() const throw() +{ return 4; } +#endif + +// Define members of codecvt_utf8_utf16<char16_t> base class implementation. +// Converts from UTF-8 to UTF-16. + +__codecvt_utf8_utf16_base<char16_t>::~__codecvt_utf8_utf16_base() { } + +codecvt_base::result +__codecvt_utf8_utf16_base<char16_t>:: +do_out(state_type&, const intern_type* __from, const intern_type* __from_end, + const intern_type*& __from_next, + extern_type* __to, extern_type* __to_end, + extern_type*& __to_next) const +{ + range<const char16_t> from{ __from, __from_end }; + range<char> to{ __to, __to_end }; + auto res = utf16_out(from, to, _M_maxcode, _M_mode); + __from_next = from.next; + __to_next = to.next; + return res; +} + +codecvt_base::result +__codecvt_utf8_utf16_base<char16_t>:: +do_unshift(state_type&, extern_type* __to, extern_type*, + extern_type*& __to_next) const +{ + __to_next = __to; + return noconv; +} + +codecvt_base::result +__codecvt_utf8_utf16_base<char16_t>:: +do_in(state_type&, const extern_type* __from, const extern_type* __from_end, + const extern_type*& __from_next, + intern_type* __to, intern_type* __to_end, + intern_type*& __to_next) const +{ + range<const char> from{ __from, __from_end }; + range<char16_t> to{ __to, __to_end }; + auto res = utf16_in(from, to, _M_maxcode, _M_mode); + __from_next = from.next; + __to_next = to.next; + return res; +} + +int +__codecvt_utf8_utf16_base<char16_t>::do_encoding() const throw() +{ return 0; } + +bool +__codecvt_utf8_utf16_base<char16_t>::do_always_noconv() const throw() +{ return false; } + +int +__codecvt_utf8_utf16_base<char16_t>:: +do_length(state_type&, const extern_type* __from, + const extern_type* __end, size_t __max) const +{ + __end = utf16_span(__from, __end, __max, _M_maxcode, _M_mode); + return __end - __from; +} + +int +__codecvt_utf8_utf16_base<char16_t>::do_max_length() const throw() +{ + // Any valid UTF-8 sequence of 3 bytes fits in a single 16-bit code unit, + // whereas 4 byte sequences require two 16-bit code units. + return 3; +} + +// Define members of codecvt_utf8_utf16<char32_t> base class implementation. +// Converts from UTF-8 to UTF-16. + +__codecvt_utf8_utf16_base<char32_t>::~__codecvt_utf8_utf16_base() { } + +codecvt_base::result +__codecvt_utf8_utf16_base<char32_t>:: +do_out(state_type&, const intern_type* __from, const intern_type* __from_end, + const intern_type*& __from_next, + extern_type* __to, extern_type* __to_end, + extern_type*& __to_next) const +{ + range<const char32_t> from{ __from, __from_end }; + range<char> to{ __to, __to_end }; + auto res = utf16_out(from, to, _M_maxcode, _M_mode); + __from_next = from.next; + __to_next = to.next; + return res; +} + +codecvt_base::result +__codecvt_utf8_utf16_base<char32_t>:: +do_unshift(state_type&, extern_type* __to, extern_type*, + extern_type*& __to_next) const +{ + __to_next = __to; + return noconv; +} + +codecvt_base::result +__codecvt_utf8_utf16_base<char32_t>:: +do_in(state_type&, const extern_type* __from, const extern_type* __from_end, + const extern_type*& __from_next, + intern_type* __to, intern_type* __to_end, + intern_type*& __to_next) const +{ + range<const char> from{ __from, __from_end }; + range<char32_t> to{ __to, __to_end }; + auto res = utf16_in(from, to, _M_maxcode, _M_mode); + __from_next = from.next; + __to_next = to.next; + return res; +} + +int +__codecvt_utf8_utf16_base<char32_t>::do_encoding() const throw() +{ return 0; } + +bool +__codecvt_utf8_utf16_base<char32_t>::do_always_noconv() const throw() +{ return false; } + +int +__codecvt_utf8_utf16_base<char32_t>:: +do_length(state_type&, const extern_type* __from, + const extern_type* __end, size_t __max) const +{ + __end = utf16_span(__from, __end, __max, _M_maxcode, _M_mode); + return __end - __from; +} + +int +__codecvt_utf8_utf16_base<char32_t>::do_max_length() const throw() +{ + // Any valid UTF-8 sequence of 3 bytes fits in a single 16-bit code unit, + // whereas 4 byte sequences require two 16-bit code units. + return 3; +} + +#ifdef _GLIBCXX_USE_WCHAR_T +// Define members of codecvt_utf8_utf16<wchar_t> base class implementation. +// Converts from UTF-8 to UTF-16. + +__codecvt_utf8_utf16_base<wchar_t>::~__codecvt_utf8_utf16_base() { } + +codecvt_base::result +__codecvt_utf8_utf16_base<wchar_t>:: +do_out(state_type&, const intern_type* __from, const intern_type* __from_end, + const intern_type*& __from_next, + extern_type* __to, extern_type* __to_end, + extern_type*& __to_next) const +{ + range<const wchar_t> from{ __from, __from_end }; + range<char> to{ __to, __to_end }; + auto res = utf16_out(from, to, _M_maxcode, _M_mode); + __from_next = from.next; + __to_next = to.next; + return res; +} + +codecvt_base::result +__codecvt_utf8_utf16_base<wchar_t>:: +do_unshift(state_type&, extern_type* __to, extern_type*, + extern_type*& __to_next) const +{ + __to_next = __to; + return noconv; +} + +codecvt_base::result +__codecvt_utf8_utf16_base<wchar_t>:: +do_in(state_type&, const extern_type* __from, const extern_type* __from_end, + const extern_type*& __from_next, + intern_type* __to, intern_type* __to_end, + intern_type*& __to_next) const +{ + range<const char> from{ __from, __from_end }; + range<wchar_t> to{ __to, __to_end }; + auto res = utf16_in(from, to, _M_maxcode, _M_mode); + __from_next = from.next; + __to_next = to.next; + return res; +} + +int +__codecvt_utf8_utf16_base<wchar_t>::do_encoding() const throw() +{ return 0; } + +bool +__codecvt_utf8_utf16_base<wchar_t>::do_always_noconv() const throw() +{ return false; } + +int +__codecvt_utf8_utf16_base<wchar_t>:: +do_length(state_type&, const extern_type* __from, + const extern_type* __end, size_t __max) const +{ + __end = utf16_span(__from, __end, __max, _M_maxcode, _M_mode); + return __end - __from; +} + +int +__codecvt_utf8_utf16_base<wchar_t>::do_max_length() const throw() +{ + // Any valid UTF-8 sequence of 3 bytes fits in a single 16-bit code unit, + // whereas 4 byte sequences require two 16-bit code units. + return 3; +} +#endif + inline template class __codecvt_abstract_base<char16_t, char, mbstate_t>; inline template class __codecvt_abstract_base<char32_t, char, mbstate_t>; diff --git a/libstdc++-v3/testsuite/22_locale/codecvt/codecvt_utf16/requirements/1.cc b/libstdc++-v3/testsuite/22_locale/codecvt/codecvt_utf16/requirements/1.cc new file mode 100644 index 0000000..38bb393 --- /dev/null +++ b/libstdc++-v3/testsuite/22_locale/codecvt/codecvt_utf16/requirements/1.cc @@ -0,0 +1,37 @@ +// Copyright (C) 2015 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// { dg-require-cstdint "" } +// { dg-options "-std=gnu++11" } +// { dg-do compile } + +#include <codecvt> +#include <type_traits> +#include <testsuite_hooks.h> + +template<typename C> + using codecvt = std::codecvt<C, char, std::mbstate_t>; + +using std::is_base_of; + +static_assert( + is_base_of<codecvt<char16_t>, std::codecvt_utf16<char16_t>>::value, + "codecvt_utf16<char16_t> has wrong base class"); + +static_assert( + is_base_of<codecvt<char32_t>, std::codecvt_utf16<char32_t>>::value, + "codecvt_utf16<char32_t> has wrong base class"); diff --git a/libstdc++-v3/testsuite/22_locale/codecvt/codecvt_utf8/requirements/1.cc b/libstdc++-v3/testsuite/22_locale/codecvt/codecvt_utf8/requirements/1.cc new file mode 100644 index 0000000..6bc2418 --- /dev/null +++ b/libstdc++-v3/testsuite/22_locale/codecvt/codecvt_utf8/requirements/1.cc @@ -0,0 +1,37 @@ +// Copyright (C) 2015 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// { dg-require-cstdint "" } +// { dg-options "-std=gnu++11" } +// { dg-do compile } + +#include <codecvt> +#include <type_traits> +#include <testsuite_hooks.h> + +template<typename C> + using codecvt = std::codecvt<C, char, std::mbstate_t>; + +using std::is_base_of; + +static_assert( + is_base_of<codecvt<char16_t>, std::codecvt_utf8<char16_t>>::value, + "codecvt_utf8<char16_t> has wrong base class"); + +static_assert( + is_base_of<codecvt<char32_t>, std::codecvt_utf8<char32_t>>::value, + "codecvt_utf8<char32_t> has wrong base class"); diff --git a/libstdc++-v3/testsuite/22_locale/codecvt/codecvt_utf8_utf16/requirements/1.cc b/libstdc++-v3/testsuite/22_locale/codecvt/codecvt_utf8_utf16/requirements/1.cc new file mode 100644 index 0000000..5e5f8dd --- /dev/null +++ b/libstdc++-v3/testsuite/22_locale/codecvt/codecvt_utf8_utf16/requirements/1.cc @@ -0,0 +1,37 @@ +// Copyright (C) 2015 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// { dg-require-cstdint "" } +// { dg-options "-std=gnu++11" } +// { dg-do compile } + +#include <codecvt> +#include <type_traits> +#include <testsuite_hooks.h> + +template<typename C> + using codecvt = std::codecvt<C, char, std::mbstate_t>; + +using std::is_base_of; + +static_assert( + is_base_of<codecvt<char16_t>, std::codecvt_utf8_utf16<char16_t>>::value, + "codecvt_utf8_utf16<char16_t> has wrong base class"); + +static_assert( + is_base_of<codecvt<char32_t>, std::codecvt_utf8_utf16<char32_t>>::value, + "codecvt_utf8_utf16<char32_t> has wrong base class");
commit 9304c8d768fcbf4265bc45cb8e057f6460e3a034 Author: Jonathan Wakely <jwakely....@gmail.com> Date: Fri Oct 26 03:20:07 2012 +0100 * include/bits/locale_conv.h (wstring_convert, wbuffer_convert): New. * include/std/locale: Include new header. * include/Makefile.am: Add it. * include/Makefile.in: Regenerate. * testsuite/22_locale/conversions/buffer/requirements/typedefs.cc: New. * testsuite/22_locale/conversions/string/1.cc: New. * testsuite/22_locale/conversions/string/2.cc: New. * testsuite/22_locale/conversions/string/requirements/typedefs.cc: New. * testsuite/22_locale/conversions/string/requirements/typedefs-2.cc: New. diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am index 285a504..2677132 100644 --- a/libstdc++-v3/include/Makefile.am +++ b/libstdc++-v3/include/Makefile.am @@ -113,6 +113,7 @@ bits_headers = \ ${bits_srcdir}/list.tcc \ ${bits_srcdir}/locale_classes.h \ ${bits_srcdir}/locale_classes.tcc \ + ${bits_srcdir}/locale_conv.h \ ${bits_srcdir}/locale_facets.h \ ${bits_srcdir}/locale_facets.tcc \ ${bits_srcdir}/locale_facets_nonio.h \ diff --git a/libstdc++-v3/include/bits/locale_conv.h b/libstdc++-v3/include/bits/locale_conv.h new file mode 100644 index 0000000..c8a44f4 --- /dev/null +++ b/libstdc++-v3/include/bits/locale_conv.h @@ -0,0 +1,464 @@ +// wstring_convert implementation -*- C++ -*- + +// Copyright (C) 2012 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// <http://www.gnu.org/licenses/>. + +/** @file bits/locale_conv.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{locale} + */ + +#ifndef _LOCALE_CONV_H +#define _LOCALE_CONV_H 1 + +#if __cplusplus < 201103L +# include <bits/c++0x_warning.h> +#else + +#include <streambuf> +#include "stringfwd.h" +#include "allocator.h" +#include "codecvt.h" +#include "unique_ptr.h" + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + +#ifdef _GLIBCXX_USE_WCHAR_T + + /** + * @addtogroup locales + * @{ + */ + + /// String conversions + template<typename _Codecvt, typename _Elem = wchar_t, + typename _Wide_alloc = allocator<_Elem>, + typename _Byte_alloc = allocator<char>> + class wstring_convert + { + public: + typedef basic_string<char, char_traits<char>, _Byte_alloc> byte_string; + typedef basic_string<_Elem, char_traits<_Elem>, _Wide_alloc> wide_string; + typedef typename _Codecvt::state_type state_type; + typedef typename wide_string::traits_type::int_type int_type; + + /** Default constructor. + * + * @param __pcvt The facet to use for conversions. + * + * Takes ownership of @p __pcvt and will delete it in the destructor. + */ + explicit + wstring_convert(_Codecvt* __pcvt = new _Codecvt()) : _M_cvt(__pcvt) + { + if (!_M_cvt) + __throw_logic_error("wstring_convert"); + } + + /** Construct with an initial converstion state. + * + * @param __pcvt The facet to use for conversions. + * @param __state Initial conversion state. + * + * Takes ownership of @p __pcvt and will delete it in the destructor. + * The object's conversion state will persist between conversions. + */ + wstring_convert(_Codecvt* __pcvt, state_type __state) + : _M_cvt(__pcvt), _M_state(__state), _M_with_cvtstate(true) + { + if (!_M_cvt) + __throw_logic_error("wstring_convert"); + } + + /** Construct with error strings. + * + * @param __byte_err A string to return on failed conversions. + * @param __wide_err A wide string to return on failed conversions. + */ + explicit + wstring_convert(const byte_string& __byte_err, + const wide_string& __wide_err = wide_string()) + : _M_cvt(new _Codecvt), + _M_byte_err_string(__byte_err), _M_wide_err_string(__wide_err), + _M_with_strings(true) + { + if (!_M_cvt) + __throw_logic_error("wstring_convert"); + } + + ~wstring_convert() = default; + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2176. Special members for wstring_convert and wbuffer_convert + wstring_convert(const wstring_convert&) = delete; + wstring_convert& operator=(const wstring_convert&) = delete; + + /// @{ Convert from bytes. + wide_string + from_bytes(char __byte) + { + char __bytes[2] = { __byte }; + return from_bytes(__bytes, __bytes+1); + } + + wide_string + from_bytes(const char* __ptr) + { return from_bytes(__ptr, __ptr+char_traits<char>::length(__ptr)); } + + wide_string + from_bytes(const byte_string& __str) + { + auto __ptr = __str.data(); + return from_bytes(__ptr, __ptr + __str.size()); + } + + wide_string + from_bytes(const char* __first, const char* __last) + { + auto __errstr = _M_with_strings ? &_M_wide_err_string : nullptr; + _ConvFn<char, _Elem> __fn = &_Codecvt::in; + return _M_conv(__first, __last, __errstr, __fn); + } + /// @} + + /// @{ Convert to bytes. + byte_string + to_bytes(_Elem __wchar) + { + _Elem __wchars[2] = { __wchar }; + return to_bytes(__wchars, __wchars+1); + } + + byte_string + to_bytes(const _Elem* __ptr) + { + return to_bytes(__ptr, __ptr+wide_string::traits_type::length(__ptr)); + } + + byte_string + to_bytes(const wide_string& __wstr) + { + auto __ptr = __wstr.data(); + return to_bytes(__ptr, __ptr + __wstr.size()); + } + + byte_string + to_bytes(const _Elem* __first, const _Elem* __last) + { + auto __errstr = _M_with_strings ? &_M_byte_err_string : nullptr; + _ConvFn<_Elem, char> __fn = &_Codecvt::out; + return _M_conv(__first, __last, __errstr, __fn); + } + /// @} + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2174. wstring_convert::converted() should be noexcept + /// The number of elements successfully converted in the last conversion. + size_t converted() const noexcept { return _M_count; } + + /// The final conversion state of the last conversion. + state_type state() const { return _M_state; } + + private: + template<typename _InC, typename _OutC> + using _ConvFn + = codecvt_base::result + (_Codecvt::*)(state_type&, const _InC*, const _InC*, const _InC*&, + _OutC*, _OutC*, _OutC*&) const; + + template<typename _InChar, typename _OutStr, typename _MemFn> + _OutStr + _M_conv(const _InChar* __first, const _InChar* __last, + const _OutStr* __err, _MemFn __memfn) + { + if (!_M_with_cvtstate) + _M_state = state_type(); + + auto __outstr = __err ? _OutStr(__err->get_allocator()) : _OutStr(); + size_t __outchars = 0; + auto __next = __first; + + codecvt_base::result __result; + do + { + __outstr.resize(__outstr.size() + (__last - __next)); + auto __outnext = &__outstr.front() + __outchars; + auto const __outlast = &__outstr.back() + 1; + __result = ((*_M_cvt).*__memfn)(_M_state, __next, __last, __next, + __outnext, __outlast, __outnext); + __outchars = __outnext - &__outstr.front(); + } + while (__result == codecvt_base::partial && __next != __last); + + __outstr.resize(__outchars); + _M_count = __next - __first; + + if (__result != codecvt_base::error) + return __outstr; + else if (__err) + return *__err; + else + __throw_range_error("wstring_convert"); + } + + unique_ptr<_Codecvt> _M_cvt; + byte_string _M_byte_err_string; + wide_string _M_wide_err_string; + state_type _M_state = state_type(); + size_t _M_count = 0; + bool _M_with_cvtstate = false; + bool _M_with_strings = false; + }; + + /// Buffer conversions + template<typename _Codecvt, typename _Elem = wchar_t, + typename _Tr = char_traits<_Elem>> + class wbuffer_convert : public basic_streambuf<_Elem, _Tr> + { + typedef basic_streambuf<_Elem, _Tr> _Wide_streambuf; + + public: + typedef typename _Codecvt::state_type state_type; + + /** Default constructor. + * + * @param __bytebuf The underlying byte stream buffer. + * @param __pcvt The facet to use for conversions. + * @param __state Initial conversion state. + * + * Takes ownership of @p __pcvt and will delete it in the destructor. + */ + explicit + wbuffer_convert(streambuf* __bytebuf = 0, _Codecvt* __pcvt = new _Codecvt, + state_type __state = state_type()) + : _M_buf(__bytebuf), _M_cvt(__pcvt), _M_state(__state) + { + if (!_M_cvt) + __throw_logic_error("wstring_convert"); + + _M_always_noconv = _M_cvt->always_noconv(); + + if (_M_buf) + { + this->setp(_M_put_area, _M_put_area + _S_buffer_length); + this->setg(_M_get_area + _S_putback_length, + _M_get_area + _S_putback_length, + _M_get_area + _S_putback_length); + } + } + + ~wbuffer_convert() = default; + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2176. Special members for wstring_convert and wbuffer_convert + wbuffer_convert(const wbuffer_convert&) = delete; + wbuffer_convert& operator=(const wbuffer_convert&) = delete; + + streambuf* rdbuf() const noexcept { return _M_buf; } + + streambuf* + rdbuf(streambuf *__bytebuf) noexcept + { + auto __prev = _M_buf; + _M_buf = __bytebuf; + return __prev; + } + + /// The conversion state following the last conversion. + state_type state() const noexcept { return _M_state; } + + protected: + int + sync() + { return _M_buf && _M_conv_put() && _M_buf->pubsync() ? 0 : -1; } + + typename _Wide_streambuf::int_type + overflow(typename _Wide_streambuf::int_type __out) + { + if (!_M_buf || !_M_conv_put()) + return _Tr::eof(); + else if (!_Tr::eq_int_type(__out, _Tr::eof())) + return this->sputc(__out); + return _Tr::not_eof(__out); + } + + typename _Wide_streambuf::int_type + underflow() + { + if (!_M_buf) + return _Tr::eof(); + + if (this->gptr() < this->egptr() || (_M_buf && _M_conv_get())) + return _Tr::to_int_type(*this->gptr()); + else + return _Tr::eof(); + } + + streamsize + xsputn(const typename _Wide_streambuf::char_type* __s, streamsize __n) + { + if (!_M_buf || __n == 0) + return 0; + streamsize __done = 0; + do + { + auto __nn = std::min<streamsize>(this->epptr() - this->pptr(), + __n - __done); + _Tr::copy(this->pptr(), __s + __done, __nn); + this->pbump(__nn); + __done += __nn; + } while (__done < __n && _M_conv_put()); + return __done; + } + + private: + // fill the get area from converted contents of the byte stream buffer + bool + _M_conv_get() + { + const streamsize __pb1 = this->gptr() - this->eback(); + const streamsize __pb2 = _S_putback_length; + const streamsize __npb = std::min(__pb1, __pb2); + + _Tr::move(_M_get_area + _S_putback_length - __npb, + this->gptr() - __npb, __npb); + + streamsize __nbytes = sizeof(_M_get_buf) - _M_unconv; + __nbytes = std::min(__nbytes, _M_buf->in_avail()); + if (__nbytes < 1) + __nbytes == 1; + __nbytes = _M_buf->sgetn(_M_get_buf + _M_unconv, __nbytes); + if (__nbytes < 1) + return false; + __nbytes += _M_unconv; + + // convert _M_get_buf into _M_get_area + + _Elem* __outbuf = _M_get_area + _S_putback_length; + _Elem* __outnext = __outbuf; + const char* __bnext = _M_get_buf; + + codecvt_base::result __result; + if (_M_always_noconv) + __result = codecvt_base::noconv; + else + { + _Elem* __outend = _M_get_area + _S_buffer_length; + + __result = _M_cvt->in(_M_state, + __bnext, __bnext + __nbytes, __bnext, + __outbuf, __outend, __outnext); + } + + if (__result == codecvt_base::noconv) + { + // cast is safe because noconv means _Elem is same type as char + auto __get_buf = reinterpret_cast<const _Elem*>(_M_get_buf); + _Tr::copy(__outbuf, __get_buf, __nbytes); + _M_unconv = 0; + return true; + } + + if ((_M_unconv = _M_get_buf + __nbytes - __bnext)) + char_traits<char>::move(_M_get_buf, __bnext, _M_unconv); + + this->setg(__outbuf, __outbuf, __outnext); + + return __result != codecvt_base::error; + } + + // unused + bool + _M_put(...) + { return false; } + + bool + _M_put(const char* __p, streamsize __n) + { + if (_M_buf->sputn(__p, __n) < __n) + return false; + } + + // convert the put area and write to the byte stream buffer + bool + _M_conv_put() + { + _Elem* const __first = this->pbase(); + const _Elem* const __last = this->pptr(); + const streamsize __pending = __last - __first; + + if (_M_always_noconv) + return _M_put(__first, __pending); + + char __outbuf[2 * _S_buffer_length]; + + const _Elem* __next = __first; + const _Elem* __start; + do + { + __start = __next; + char* __outnext = __outbuf; + char* const __outlast = __outbuf + sizeof(__outbuf); + auto __result = _M_cvt->out(_M_state, __next, __last, __next, + __outnext, __outlast, __outnext); + if (__result == codecvt_base::error) + return false; + else if (__result == codecvt_base::noconv) + return _M_put(__next, __pending); + + if (!_M_put(__outbuf, __outnext - __outbuf)) + return false; + } + while (__next != __last && __next != __start); + + if (__next != __last) + _Tr::move(__first, __next, __last - __next); + + this->pbump(__first - __next); + return __next != __first; + } + + streambuf* _M_buf; + unique_ptr<_Codecvt> _M_cvt; + state_type _M_state; + + static const streamsize _S_buffer_length = 32; + static const streamsize _S_putback_length = 3; + _Elem _M_put_area[_S_buffer_length]; + _Elem _M_get_area[_S_buffer_length]; + streamsize _M_unconv = 0; + char _M_get_buf[_S_buffer_length-_S_putback_length]; + bool _M_always_noconv; + }; + + /// @} group locales + +#endif // _GLIBCXX_USE_WCHAR_T + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#endif // __cplusplus + +#endif /* _LOCALE_CONV_H */ diff --git a/libstdc++-v3/include/std/locale b/libstdc++-v3/include/std/locale index fbc2770..102004f 100644 --- a/libstdc++-v3/include/std/locale +++ b/libstdc++-v3/include/std/locale @@ -39,5 +39,8 @@ #include <bits/locale_classes.h> #include <bits/locale_facets.h> #include <bits/locale_facets_nonio.h> +#if __cplusplus >= 201103L +# include <bits/locale_conv.h> +#endif #endif /* _GLIBCXX_LOCALE */ diff --git a/libstdc++-v3/testsuite/22_locale/conversions/buffer/requirements/typedefs.cc b/libstdc++-v3/testsuite/22_locale/conversions/buffer/requirements/typedefs.cc new file mode 100644 index 0000000..c59c6d6 --- /dev/null +++ b/libstdc++-v3/testsuite/22_locale/conversions/buffer/requirements/typedefs.cc @@ -0,0 +1,36 @@ +// { dg-do compile } +// { dg-options "-std=gnu++11" } + +// Copyright (C) 2012 Free Software Foundation +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// 22.3.3.2.3 Buffer conversions + +#include <locale> +#include <type_traits> + +void test01() +{ + // Check for required typedefs + struct cvt_type : std::codecvt<wchar_t, char, mbstate_t> { }; + typedef std::char_traits<wchar_t> traits_type; + typedef std::wbuffer_convert<cvt_type, wchar_t, traits_type> test_type; + typedef test_type::state_type state_type; + + static_assert( std::is_same<cvt_type::state_type, state_type>::value, + "state type" ); +} diff --git a/libstdc++-v3/testsuite/22_locale/conversions/string/1.cc b/libstdc++-v3/testsuite/22_locale/conversions/string/1.cc new file mode 100644 index 0000000..c2ab6e7 --- /dev/null +++ b/libstdc++-v3/testsuite/22_locale/conversions/string/1.cc @@ -0,0 +1,74 @@ +// { dg-do compile } +// { dg-options "-std=gnu++11" } + +// Copyright (C) 2012 Free Software Foundation +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// 22.3.3.2.2 String conversions + +#include <locale> +#include <string> +#include <testsuite_hooks.h> + +template<typename Elem> +struct cvt : std::codecvt<Elem, char, std::mbstate_t> { }; + +template<typename Elem> +using str_conv = std::wstring_convert<cvt<Elem>, Elem>; + +using std::string; +using std::wstring; + +void test01() +{ + typedef str_conv<char> sc; // noconv + sc c; + string input = "King for a day..."; + string output = c.from_bytes(input); + VERIFY( input == output ); + VERIFY( c.converted() == output.length() ); + string roundtrip = c.to_bytes(output); + VERIFY( input == roundtrip ); + VERIFY( c.converted() == roundtrip.length() ); +} + +void test02() +{ + typedef str_conv<wchar_t> wsc; + wsc c; + string input = "Fool for a lifetime"; + wstring output = c.from_bytes(input); + VERIFY( c.converted() == output.length() ); + VERIFY( L"Fool for a lifetime" == output ); + string roundtrip = c.to_bytes(output); + VERIFY( input == roundtrip ); + VERIFY( c.converted() == roundtrip.length() ); + + VERIFY( c.from_bytes(input[0]) == output.substr(0, 1) ); + VERIFY( c.from_bytes(input.c_str()) == output ); + VERIFY( c.from_bytes(input.data(), input.data()+input.size()) == output ); + + VERIFY( c.to_bytes(output[0]) == input.substr(0, 1) ); + VERIFY( c.to_bytes(output.c_str()) == input ); + VERIFY( c.to_bytes(output.data(), output.data()+output.size()) == input ); +} + +int main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/22_locale/conversions/string/2.cc b/libstdc++-v3/testsuite/22_locale/conversions/string/2.cc new file mode 100644 index 0000000..94eb75f --- /dev/null +++ b/libstdc++-v3/testsuite/22_locale/conversions/string/2.cc @@ -0,0 +1,60 @@ +// { dg-options "-std=gnu++11" } + +// Copyright (C) 2012 Free Software Foundation +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// 22.3.3.2.2 String conversions + +#include <locale> +#include <string> +#include <testsuite_hooks.h> + +template<typename Elem> +struct cvt : std::codecvt<Elem, char, std::mbstate_t> { }; + +template<typename Elem> +using str_conv = std::wstring_convert<cvt<Elem>, Elem>; + +using std::string; +using std::wstring; + +// test conversion errors, with and without error strings + +void test01() +{ + typedef str_conv<wchar_t> sc; + + const sc::byte_string berr = "invalid wide string"; + const sc::wide_string werr = L"invalid byte string"; + + sc c(berr, werr); + string input = "Stop"; + input += char(0xff); + input += char(0xff); + wstring woutput = c.from_bytes(input); + VERIFY( werr == woutput ); + wstring winput = L"Stop"; + winput += wchar_t(0xff); + winput += wchar_t(0xff); + string output = c.to_bytes(winput); + VERIFY( berr == output ); +} + +int main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/22_locale/conversions/string/requirements/typedefs-2.cc b/libstdc++-v3/testsuite/22_locale/conversions/string/requirements/typedefs-2.cc new file mode 100644 index 0000000..65a1458 --- /dev/null +++ b/libstdc++-v3/testsuite/22_locale/conversions/string/requirements/typedefs-2.cc @@ -0,0 +1,41 @@ +// { dg-do compile } +// { dg-options "-std=gnu++11" } + +// Copyright (C) 2012 Free Software Foundation +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// 22.3.3.2.2 String conversions + +#include <locale> +#include <string> +#include <type_traits> +#include <testsuite_allocator.h> + +template<typename T> + using alloc = __gnu_test::uneq_allocator<T>; + +template<typename C> + using Str = std::basic_string<C, std::char_traits<C>, alloc<C>>; + +struct cvt : std::codecvt<wchar_t, char, std::mbstate_t> { }; + +using wconv = std::wstring_convert<cvt, wchar_t, alloc<wchar_t>, alloc<char>>; + +static_assert( std::is_same<wconv::byte_string, Str<char>>::value, + "byte string is std::string" ); +static_assert( std::is_same<wconv::wide_string, Str<wchar_t>>::value, + "wide string is std::wstring" ); diff --git a/libstdc++-v3/testsuite/22_locale/conversions/string/requirements/typedefs.cc b/libstdc++-v3/testsuite/22_locale/conversions/string/requirements/typedefs.cc new file mode 100644 index 0000000..baed16e --- /dev/null +++ b/libstdc++-v3/testsuite/22_locale/conversions/string/requirements/typedefs.cc @@ -0,0 +1,34 @@ +// { dg-do compile } +// { dg-options "-std=gnu++11" } + +// Copyright (C) 2012 Free Software Foundation +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// 22.3.3.2.2 String conversions + +#include <locale> + +void test01() +{ + // Check for required typedefs + typedef std::codecvt<wchar_t, char, mbstate_t> codecvt_type; + typedef std::wstring_convert<codecvt_type> test_type; + typedef test_type::byte_string byte_string; + typedef test_type::wide_string wide_string; + typedef test_type::state_type state_type; + typedef test_type::int_type int_type; +}