diff --git a/include/iomanip b/include/iomanip index 0c58e1980..cdb0d5f0d 100644 --- a/include/iomanip +++ b/include/iomanip @@ -26,6 +26,17 @@ template T8 put_money(const moneyT& mon, bool intl = template T9 get_time(struct tm* tmb, const charT* fmt); template T10 put_time(const struct tm* tmb, const charT* fmt); +template + T11 quoted(const charT* s, charT delim=charT('"'), charT escape=charT('\\')); // C++14 + +template + T12 quoted(const basic_string& s, + charT delim=charT('"'), charT escape=charT('\\')); // C++14 + +template + T13 quoted(basic_string& s, + charT delim=charT('"'), charT escape=charT('\\')); // C++14 + } // std */ @@ -499,6 +510,142 @@ put_time(const tm* __tm, const _CharT* __fmt) return __iom_t10<_CharT>(__tm, __fmt); } +#if _LIBCPP_STD_VER > 11 + +template +std::basic_ostream<_CharT, _Traits> & +__quoted_output ( basic_ostream<_CharT, _Traits> &__os, + _ForwardIterator __first, _ForwardIterator __last, _CharT __delim, _CharT __escape ) +{ + __os << __delim; + for ( ; __first != __last; ++ __first ) + { + if (_Traits::eq (*__first, __escape) || _Traits::eq (*__first, __delim)) + __os << __escape; + __os << *__first; + } + __os << __delim; + return __os; +} + +template +basic_istream<_CharT, _Traits> & +__quoted_input ( basic_istream<_CharT, _Traits> &__is, _String & __string, _CharT __delim, _CharT __escape ) +{ + __string.clear (); + _CharT __c; + __is >> __c; + if ( __is.fail ()) + return __is; + + if (!_Traits::eq (__c, __delim)) // no delimiter, read the whole string + { + __is.unget (); + __is >> __string; + return __is; + } + + __save_flags<_CharT, _Traits> sf(__is); + noskipws (__is); + while (true) + { + __is >> __c; + if ( __is.fail ()) + break; + if (_Traits::eq (__c, __escape)) + { + __is >> __c; + if ( __is.fail ()) + break; + } + else if (_Traits::eq (__c, __delim)) + break; + __string.push_back ( __c ); + } + return __is; +} + + +template > +struct __quoted_output_proxy +{ + _Iter __first; + _Iter __last; + _CharT __delim; + _CharT __escape; + + __quoted_output_proxy(_Iter __f, _Iter __l, _CharT __d, _CharT __e) + : __first(__f), __last(__l), __delim(__d), __escape(__e) {} + // This would be a nice place for a string_ref +}; + +template +basic_ostream<_CharT, _Traits>& operator<<( + basic_ostream<_CharT, _Traits>& __os, + const __quoted_output_proxy<_CharT, _Iter, _Traits> & __proxy) +{ + return __quoted_output (__os, __proxy.__first, __proxy.__last, __proxy.__delim, __proxy.__escape); +} + +template +struct __quoted_proxy +{ + basic_string<_CharT, _Traits, _Allocator> &__string; + _CharT __delim; + _CharT __escape; + + __quoted_proxy(basic_string<_CharT, _Traits, _Allocator> &__s, _CharT __d, _CharT __e) + : __string(__s), __delim(__d), __escape(__e) {} +}; + +template +_LIBCPP_INLINE_VISIBILITY +basic_ostream<_CharT, _Traits>& operator<<( + basic_ostream<_CharT, _Traits>& __os, + const __quoted_proxy<_CharT, _Traits, _Allocator> & __proxy) +{ + return __quoted_output (__os, __proxy.string.cbegin (), __proxy.string.cend (), __proxy.__delim, __proxy.__escape); +} + +// extractor for non-const basic_string& proxies +template +_LIBCPP_INLINE_VISIBILITY +basic_istream<_CharT, _Traits>& operator>>( + basic_istream<_CharT, _Traits>& __is, + const __quoted_proxy<_CharT, _Traits, _Allocator> & __proxy) +{ + return __quoted_input ( __is, __proxy.__string, __proxy.__delim, __proxy.__escape ); +} + + +template +_LIBCPP_INLINE_VISIBILITY +__quoted_output_proxy<_CharT, const _CharT *> +quoted ( const _CharT *__s, _CharT __delim = _CharT('"'), _CharT __escape =_CharT('\\')) +{ + const _CharT *__end = __s; + while ( *__end ) ++__end; + return __quoted_output_proxy<_CharT, const _CharT *> ( __s, __end, __delim, __escape ); +} + +template +_LIBCPP_INLINE_VISIBILITY +__quoted_output_proxy<_CharT, typename basic_string <_CharT, _Traits, _Allocator>::const_iterator> +quoted ( const basic_string <_CharT, _Traits, _Allocator> &__s, _CharT __delim = _CharT('"'), _CharT __escape=_CharT('\\')) +{ + return __quoted_output_proxy<_CharT, + typename basic_string <_CharT, _Traits, _Allocator>::const_iterator> + ( __s.cbegin(), __s.cend (), __delim, __escape ); +} + +template +__quoted_proxy<_CharT, _Traits, _Allocator> +quoted ( basic_string <_CharT, _Traits, _Allocator> &__s, _CharT __delim = _CharT('"'), _CharT __escape=_CharT('\\')) +{ + return __quoted_proxy<_CharT, _Traits, _Allocator>( __s, __delim, __escape ); +} +#endif + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP_IOMANIP diff --git a/test/input.output/iostream.format/quoted.manip/quoted.pass.cpp b/test/input.output/iostream.format/quoted.manip/quoted.pass.cpp new file mode 100644 index 000000000..9f2d7c8ec --- /dev/null +++ b/test/input.output/iostream.format/quoted.manip/quoted.pass.cpp @@ -0,0 +1,192 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// quoted + +#include +#include +#include +#include + +#if _LIBCPP_STD_VER > 11 + +bool is_skipws ( const std::istream *is ) { + return ( is->flags() & std::ios_base::skipws ) != 0; + } + + +bool is_skipws ( const std::wistream *is ) { + return ( is->flags() & std::ios_base::skipws ) != 0; + } + +void round_trip ( const char *p ) { + std::stringstream ss; + bool skippingws = is_skipws ( &ss ); + ss << std::quoted(p); + std::string s; + ss >> std::quoted(s); + assert ( s == p ); + assert ( skippingws == is_skipws ( &ss )); + } + +void round_trip_ws ( const char *p ) { + std::stringstream ss; + std::noskipws ( ss ); + bool skippingws = is_skipws ( &ss ); + ss << std::quoted(p); + std::string s; + ss >> std::quoted(s); + assert ( s == p ); + assert ( skippingws == is_skipws ( &ss )); + } + +void round_trip_d ( const char *p, char delim ) { + std::stringstream ss; + ss << std::quoted(p, delim); + std::string s; + ss >> std::quoted(s, delim); + assert ( s == p ); + } + +void round_trip_e ( const char *p, char escape ) { + std::stringstream ss; + ss << std::quoted(p, '"', escape ); + std::string s; + ss >> std::quoted(s, '"', escape ); + assert ( s == p ); + } + + + +std::string quote ( const char *p, char delim='"', char escape='\\' ) { + std::stringstream ss; + ss << std::quoted(p, delim, escape); + std::string s; + ss >> s; // no quote + return s; +} + +std::string unquote ( const char *p, char delim='"', char escape='\\' ) { + std::stringstream ss; + ss << p; + std::string s; + ss >> std::quoted(s, delim, escape); + return s; +} + + +void round_trip ( const wchar_t *p ) { + std::wstringstream ss; + bool skippingws = is_skipws ( &ss ); + ss << std::quoted(p); + std::wstring s; + ss >> std::quoted(s); + assert ( s == p ); + assert ( skippingws == is_skipws ( &ss )); + } + + +void round_trip_ws ( const wchar_t *p ) { + std::wstringstream ss; + std::noskipws ( ss ); + bool skippingws = is_skipws ( &ss ); + ss << std::quoted(p); + std::wstring s; + ss >> std::quoted(s); + assert ( s == p ); + assert ( skippingws == is_skipws ( &ss )); + } + +void round_trip_d ( const wchar_t *p, wchar_t delim ) { + std::wstringstream ss; + ss << std::quoted(p, delim); + std::wstring s; + ss >> std::quoted(s, delim); + assert ( s == p ); + } + +void round_trip_e ( const wchar_t *p, wchar_t escape ) { + std::wstringstream ss; + ss << std::quoted(p, wchar_t('"'), escape ); + std::wstring s; + ss >> std::quoted(s, wchar_t('"'), escape ); + assert ( s == p ); + } + + +std::wstring quote ( const wchar_t *p, wchar_t delim='"', wchar_t escape='\\' ) { + std::wstringstream ss; + ss << std::quoted(p, delim, escape); + std::wstring s; + ss >> s; // no quote + return s; +} + +std::wstring unquote ( const wchar_t *p, wchar_t delim='"', wchar_t escape='\\' ) { + std::wstringstream ss; + ss << p; + std::wstring s; + ss >> std::quoted(s, delim, escape); + return s; +} + +int main() +{ + round_trip ( "" ); + round_trip_ws ( "" ); + round_trip_d ( "", 'q' ); + round_trip_e ( "", 'q' ); + + round_trip ( L"" ); + round_trip_ws ( L"" ); + round_trip_d ( L"", 'q' ); + round_trip_e ( L"", 'q' ); + + round_trip ( "Hi" ); + round_trip_ws ( "Hi" ); + round_trip_d ( "Hi", '!' ); + round_trip_e ( "Hi", '!' ); + assert ( quote ( "Hi", '!' ) == "!Hi!" ); + assert ( quote ( "Hi!", '!' ) == R"(!Hi\!!)" ); + + round_trip ( L"Hi" ); + round_trip_ws ( L"Hi" ); + round_trip_d ( L"Hi", '!' ); + round_trip_e ( L"Hi", '!' ); + assert ( quote ( L"Hi", '!' ) == L"!Hi!" ); + assert ( quote ( L"Hi!", '!' ) == LR"(!Hi\!!)" ); + + round_trip ( "Hi Mom" ); + round_trip_ws ( "Hi Mom" ); + round_trip ( L"Hi Mom" ); + round_trip_ws ( L"Hi Mom" ); + + assert ( quote ( "" ) == "\"\"" ); + assert ( quote ( L"" ) == L"\"\"" ); + assert ( quote ( "a" ) == "\"a\"" ); + assert ( quote ( L"a" ) == L"\"a\"" ); + +// missing end quote - must not hang + assert ( unquote ( "\"abc" ) == "abc" ); + assert ( unquote ( L"\"abc" ) == L"abc" ); + + assert ( unquote ( "abc" ) == "abc" ); // no delimiter + assert ( unquote ( L"abc" ) == L"abc" ); // no delimiter + assert ( unquote ( "abc def" ) == "abc" ); // no delimiter + assert ( unquote ( L"abc def" ) == L"abc" ); // no delimiter + + assert ( unquote ( "" ) == "" ); // nothing there + assert ( unquote ( L"" ) == L"" ); // nothing there + } + +#else +int main() {} +#endif diff --git a/test/input.output/iostream.format/quoted.manip/quoted_char.fail.cpp b/test/input.output/iostream.format/quoted.manip/quoted_char.fail.cpp new file mode 100644 index 000000000..2f516f8fb --- /dev/null +++ b/test/input.output/iostream.format/quoted.manip/quoted_char.fail.cpp @@ -0,0 +1,36 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// quoted + +#include +#include +#include +#include + +#if _LIBCPP_STD_VER > 11 + +void round_trip ( const char *p ) { + std::wstringstream ss; + ss << std::quoted(p); + std::string s; + ss >> std::quoted(s); + } + + + +int main() +{ + round_trip ( "Hi Mom" ); +} +#else +#error +#endif diff --git a/test/input.output/iostream.format/quoted.manip/quoted_traits.fail.cpp b/test/input.output/iostream.format/quoted.manip/quoted_traits.fail.cpp new file mode 100644 index 000000000..bdd362df1 --- /dev/null +++ b/test/input.output/iostream.format/quoted.manip/quoted_traits.fail.cpp @@ -0,0 +1,42 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// quoted + +#include +#include +#include +#include + +#if _LIBCPP_STD_VER > 11 + +template +struct test_traits +{ + typedef charT char_type; +}; + +void round_trip ( const char *p ) { + std::stringstream ss; + ss << std::quoted(p); + std::basic_string> s; + ss >> std::quoted(s); + } + + + +int main() +{ + round_trip ( "Hi Mom" ); +} +#else +#error +#endif diff --git a/www/cxx1y_status.html b/www/cxx1y_status.html index 0d489cb14..4fe5bb3c8 100644 --- a/www/cxx1y_status.html +++ b/www/cxx1y_status.html @@ -83,7 +83,7 @@ 3670LWGAddressing Tuples by TypeBristolComplete3.4 3671LWGMaking non-modifying sequence operations more robustBristolComplete3.4 3656LWGmake_uniqueBristolComplete3.4 - 3654LWGQuoted StringsBristolImplemented, but not checked in + 3654LWGQuoted StringsBristolComplete3.4 3642LWGUser-defined LiteralsBristolComplete3.4 3655LWGTransformationTraits Redux (excluding part 4)BristolComplete3.4 3657LWGAdding heterogeneous comparison lookup to associative containersBristolComplete3.4