iomanip 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. // -*-c++-*-
  2. // vim: set ft=cpp:
  3. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  4. file Copyright.txt or https://cmake.org/licensing for details. */
  5. #pragma once
  6. #include <iomanip> // IWYU pragma: export
  7. #if __cplusplus < 201402L || defined(_MSVC_LANG) && _MSVC_LANG < 201402L
  8. # include <ios>
  9. # include <iostream>
  10. # include <sstream>
  11. # include <string>
  12. # include <type_traits>
  13. #endif
  14. #if __cplusplus < 201703L || defined(_MSVC_LANG) && _MSVC_LANG < 201703L
  15. # include <cm/string_view>
  16. #endif
  17. namespace cm {
  18. #if __cplusplus >= 201402L || defined(_MSVC_LANG) && _MSVC_LANG >= 201402L
  19. using std::quoted;
  20. # if __cplusplus < 201703L || defined(_MSVC_LANG) && _MSVC_LANG < 201703L
  21. inline auto quoted(cm::string_view str, char delim = '"', char escape = '\\')
  22. {
  23. return std::quoted(static_cast<std::string>(str), delim, escape);
  24. }
  25. # endif
  26. #else
  27. namespace internals {
  28. // Struct for delimited strings.
  29. template <typename String, typename Char>
  30. struct quoted_string
  31. {
  32. static_assert(std::is_reference<String>::value ||
  33. std::is_pointer<String>::value,
  34. "String type must be pointer or reference");
  35. quoted_string(String str, Char del, Char esc)
  36. : string_(str)
  37. , delim_{ del }
  38. , escape_{ esc }
  39. {
  40. }
  41. quoted_string& operator=(quoted_string&) = delete;
  42. String string_;
  43. Char delim_;
  44. Char escape_;
  45. };
  46. template <>
  47. struct quoted_string<cm::string_view, char>
  48. {
  49. quoted_string(cm::string_view str, char del, char esc)
  50. : string_(str)
  51. , delim_{ del }
  52. , escape_{ esc }
  53. {
  54. }
  55. quoted_string& operator=(quoted_string&) = delete;
  56. cm::string_view string_;
  57. char delim_;
  58. char escape_;
  59. };
  60. template <typename Char, typename Traits>
  61. std::basic_ostream<Char, Traits>& operator<<(
  62. std::basic_ostream<Char, Traits>& os,
  63. const quoted_string<const Char*, Char>& str)
  64. {
  65. std::basic_ostringstream<Char, Traits> ostr;
  66. ostr << str.delim_;
  67. for (const Char* c = str.string_; *c; ++c) {
  68. if (*c == str.delim_ || *c == str.escape_)
  69. ostr << str.escape_;
  70. ostr << *c;
  71. }
  72. ostr << str.delim_;
  73. return os << ostr.str();
  74. }
  75. template <typename Char, typename Traits, typename String>
  76. std::basic_ostream<Char, Traits>& operator<<(
  77. std::basic_ostream<Char, Traits>& os, const quoted_string<String, Char>& str)
  78. {
  79. std::basic_ostringstream<Char, Traits> ostr;
  80. ostr << str.delim_;
  81. for (auto c : str.string_) {
  82. if (c == str.delim_ || c == str.escape_)
  83. ostr << str.escape_;
  84. ostr << c;
  85. }
  86. ostr << str.delim_;
  87. return os << ostr.str();
  88. }
  89. template <typename Char, typename Traits, typename Alloc>
  90. std::basic_istream<Char, Traits>& operator>>(
  91. std::basic_istream<Char, Traits>& is,
  92. const quoted_string<std::basic_string<Char, Traits, Alloc>&, Char>& str)
  93. {
  94. Char c;
  95. is >> c;
  96. if (!is.good())
  97. return is;
  98. if (c != str.delim_) {
  99. is.unget();
  100. is >> str.string_;
  101. return is;
  102. }
  103. str.string_.clear();
  104. std::ios_base::fmtflags flags =
  105. is.flags(is.flags() & ~std::ios_base::skipws);
  106. do {
  107. is >> c;
  108. if (!is.good())
  109. break;
  110. if (c == str.escape_) {
  111. is >> c;
  112. if (!is.good())
  113. break;
  114. } else if (c == str.delim_)
  115. break;
  116. str.string_ += c;
  117. } while (true);
  118. is.setf(flags);
  119. return is;
  120. }
  121. }
  122. template <typename Char>
  123. inline internals::quoted_string<const Char*, Char> quoted(
  124. const Char* str, Char delim = Char('"'), Char escape = Char('\\'))
  125. {
  126. return internals::quoted_string<const Char*, Char>(str, delim, escape);
  127. }
  128. template <typename Char, typename Traits, typename Alloc>
  129. inline internals::quoted_string<const std::basic_string<Char, Traits, Alloc>&,
  130. Char>
  131. quoted(const std::basic_string<Char, Traits, Alloc>& str,
  132. Char delim = Char('"'), Char escape = Char('\\'))
  133. {
  134. return internals::quoted_string<
  135. const std::basic_string<Char, Traits, Alloc>&, Char>(str, delim, escape);
  136. }
  137. template <typename Char, typename Traits, typename Alloc>
  138. inline internals::quoted_string<std::basic_string<Char, Traits, Alloc>&, Char>
  139. quoted(std::basic_string<Char, Traits, Alloc>& str, Char delim = Char('"'),
  140. Char escape = Char('\\'))
  141. {
  142. return internals::quoted_string<std::basic_string<Char, Traits, Alloc>&,
  143. Char>(str, delim, escape);
  144. }
  145. inline internals::quoted_string<cm::string_view, char> quoted(
  146. cm::string_view str, char delim = '"', char escape = '\\')
  147. {
  148. return internals::quoted_string<cm::string_view, char>(str, delim, escape);
  149. }
  150. #endif
  151. } // namespace cm