summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Help/dev/source.rst3
-rw-r--r--Utilities/std/cm/iomanip183
2 files changed, 186 insertions, 0 deletions
diff --git a/Help/dev/source.rst b/Help/dev/source.rst
index 0ccb8f42d9..5fbc9fa70c 100644
--- a/Help/dev/source.rst
+++ b/Help/dev/source.rst
@@ -35,6 +35,9 @@ Available features are:
* From ``C++14``:
+ * ``<cm/iomanip>``:
+ ``cm::quoted``
+
* ``<cm/iterator>``:
``cm::make_reverse_iterator``, ``cm::cbegin``, ``cm::cend``,
``cm::rbegin``, ``cm::rend``, ``cm::crbegin``, ``cm::crend``
diff --git a/Utilities/std/cm/iomanip b/Utilities/std/cm/iomanip
new file mode 100644
index 0000000000..6f68530c00
--- /dev/null
+++ b/Utilities/std/cm/iomanip
@@ -0,0 +1,183 @@
+// -*-c++-*-
+// vim: set ft=cpp:
+
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cm_iomanip
+#define cm_iomanip
+
+#include <iomanip> // IWYU pragma: export
+#if __cplusplus < 201402L || defined(_MSVC_LANG) && _MSVC_LANG < 201402L
+# include <ios>
+# include <iostream>
+# include <sstream>
+# include <string>
+# include <type_traits>
+#endif
+#if __cplusplus < 201703L || defined(_MSVC_LANG) && _MSVC_LANG < 201703L
+# include <cm/string_view>
+#endif
+
+namespace cm {
+
+#if __cplusplus >= 201402L || defined(_MSVC_LANG) && _MSVC_LANG >= 201402L
+
+using std::quoted;
+
+# if __cplusplus < 201703L || defined(_MSVC_LANG) && _MSVC_LANG < 201703L
+
+inline auto quoted(cm::string_view str, char delim = '"', char escape = '\\')
+{
+ return std::quoted(static_cast<std::string>(str), delim, escape);
+}
+
+# endif
+
+#else
+
+namespace internals {
+
+// Struct for delimited strings.
+template <typename String, typename Char>
+struct quoted_string
+{
+ static_assert(std::is_reference<String>::value ||
+ std::is_pointer<String>::value,
+ "String type must be pointer or reference");
+
+ quoted_string(String str, Char del, Char esc)
+ : string_(str)
+ , delim_{ del }
+ , escape_{ esc }
+ {
+ }
+
+ quoted_string& operator=(quoted_string&) = delete;
+
+ String string_;
+ Char delim_;
+ Char escape_;
+};
+
+template <>
+struct quoted_string<cm::string_view, char>
+{
+ quoted_string(cm::string_view str, char del, char esc)
+ : string_(str)
+ , delim_{ del }
+ , escape_{ esc }
+ {
+ }
+
+ quoted_string& operator=(quoted_string&) = delete;
+
+ cm::string_view string_;
+ char delim_;
+ char escape_;
+};
+
+template <typename Char, typename Traits>
+std::basic_ostream<Char, Traits>& operator<<(
+ std::basic_ostream<Char, Traits>& os,
+ const quoted_string<const Char*, Char>& str)
+{
+ std::basic_ostringstream<Char, Traits> ostr;
+ ostr << str.delim_;
+ for (const Char* c = str.string_; *c; ++c) {
+ if (*c == str.delim_ || *c == str.escape_)
+ ostr << str.escape_;
+ ostr << *c;
+ }
+ ostr << str.delim_;
+
+ return os << ostr.str();
+}
+
+template <typename Char, typename Traits, typename String>
+std::basic_ostream<Char, Traits>& operator<<(
+ std::basic_ostream<Char, Traits>& os, const quoted_string<String, Char>& str)
+{
+ std::basic_ostringstream<Char, Traits> ostr;
+ ostr << str.delim_;
+ for (auto c : str.string_) {
+ if (c == str.delim_ || c == str.escape_)
+ ostr << str.escape_;
+ ostr << c;
+ }
+ ostr << str.delim_;
+
+ return os << ostr.str();
+}
+
+template <typename Char, typename Traits, typename Alloc>
+std::basic_istream<Char, Traits>& operator>>(
+ std::basic_istream<Char, Traits>& is,
+ const quoted_string<std::basic_string<Char, Traits, Alloc>&, Char>& str)
+{
+ Char c;
+ is >> c;
+ if (!is.good())
+ return is;
+ if (c != str.delim_) {
+ is.unget();
+ is >> str.string_;
+ return is;
+ }
+ str.string_.clear();
+ std::ios_base::fmtflags flags =
+ is.flags(is.flags() & ~std::ios_base::skipws);
+ do {
+ is >> c;
+ if (!is.good())
+ break;
+ if (c == str.escape_) {
+ is >> c;
+ if (!is.good())
+ break;
+ } else if (c == str.delim_)
+ break;
+ str.string_ += c;
+ } while (true);
+ is.setf(flags);
+
+ return is;
+}
+}
+
+template <typename Char>
+inline internals::quoted_string<const Char*, Char> quoted(
+ const Char* str, Char delim = Char('"'), Char escape = Char('\\'))
+{
+ return internals::quoted_string<const Char*, Char>(str, delim, escape);
+}
+
+template <typename Char, typename Traits, typename Alloc>
+inline internals::quoted_string<const std::basic_string<Char, Traits, Alloc>&,
+ Char>
+quoted(const std::basic_string<Char, Traits, Alloc>& str,
+ Char delim = Char('"'), Char escape = Char('\\'))
+{
+ return internals::quoted_string<
+ const std::basic_string<Char, Traits, Alloc>&, Char>(str, delim, escape);
+}
+
+template <typename Char, typename Traits, typename Alloc>
+inline internals::quoted_string<std::basic_string<Char, Traits, Alloc>&, Char>
+quoted(std::basic_string<Char, Traits, Alloc>& str, Char delim = Char('"'),
+ Char escape = Char('\\'))
+{
+ return internals::quoted_string<std::basic_string<Char, Traits, Alloc>&,
+ Char>(str, delim, escape);
+}
+
+inline internals::quoted_string<cm::string_view, char> quoted(
+ cm::string_view str, char delim = '"', char escape = '\\')
+{
+ return internals::quoted_string<cm::string_view, char>(str, delim, escape);
+}
+
+#endif
+
+} // namespace cm
+
+#endif