quoted.hpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. //
  2. // Copyright (c) 2023 Alexander Grund
  3. //
  4. // Distributed under the Boost Software License, Version 1.0.
  5. // https://www.boost.org/LICENSE_1_0.txt
  6. #ifndef BOOST_NOWIDE_QUOTED_HPP_INCLUDED
  7. #define BOOST_NOWIDE_QUOTED_HPP_INCLUDED
  8. #include <boost/nowide/config.hpp>
  9. #include <boost/nowide/detail/is_path.hpp>
  10. #include <boost/nowide/utf/convert.hpp>
  11. #include <iomanip>
  12. #include <istream>
  13. #include <ostream>
  14. #include <type_traits>
  15. #if defined(__cpp_lib_quoted_string_io) && __cpp_lib_quoted_string_io >= 201304
  16. namespace boost {
  17. namespace nowide {
  18. /// \cond INTERNAL
  19. namespace detail {
  20. template<class Path>
  21. struct quoted;
  22. template<typename T>
  23. using remove_cvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
  24. } // namespace detail
  25. /// \endcond
  26. /// \brief Allows insertion and extraction of `filesystem::path` into/from streams.
  27. ///
  28. /// When used in an expression such as `out << quoted(path)`, where `out` is an output stream,
  29. /// has the effect as-if `out << std::quoted(path.native())` was used.
  30. ///
  31. /// When used in an expression like `in >> quoted(path)`, where `in` is an input stream,
  32. /// has the effect as-if `in >> std::quoted(path.native())` was used if that would be valid.
  33. /// To that effect a temporary string is used, which on success is assigned to `path`.
  34. ///
  35. /// Will automatically convert between the streams `char_type` and `path::value_type` if neccessary.
  36. template<class Path>
  37. #ifdef BOOST_NOWIDE_DOXYGEN
  38. unspecified_type
  39. #else
  40. detail::enable_if_path_t<detail::remove_cvref_t<Path>, detail::quoted<Path&>>
  41. #endif
  42. quoted(Path& path)
  43. {
  44. return {path};
  45. }
  46. /// \cond INTERNAL
  47. // Same but for const-refs and r-values
  48. template<class Path>
  49. detail::enable_if_path_t<detail::remove_cvref_t<Path>, detail::quoted<const Path&>> quoted(const Path& path)
  50. {
  51. return {path};
  52. }
  53. namespace detail {
  54. template<typename CharOut,
  55. typename CharIn,
  56. typename = typename std::enable_if<!std::is_same<CharOut, CharIn>::value>::type>
  57. std::basic_string<CharOut> maybe_convert_string(const std::basic_string<CharIn>& s)
  58. {
  59. return utf::convert_string<CharOut>(s);
  60. }
  61. template<typename Char>
  62. const std::basic_string<Char>& maybe_convert_string(const std::basic_string<Char>& s)
  63. {
  64. return s;
  65. }
  66. template<typename T>
  67. using requires_non_const =
  68. typename std::enable_if<!std::is_const<typename std::remove_reference<T>::type>::value>::type;
  69. template<class Path>
  70. struct quoted
  71. {
  72. Path value;
  73. template<typename CharType>
  74. friend std::basic_ostream<CharType>& operator<<(std::basic_ostream<CharType>& out, const quoted& path)
  75. {
  76. return out << std::quoted(maybe_convert_string<CharType>(path.value.native()));
  77. }
  78. template<typename CharType, class Path2 = Path, typename = requires_non_const<Path2>>
  79. friend std::basic_istream<CharType>& operator>>(std::basic_istream<CharType>& in, const quoted& path)
  80. {
  81. std::basic_string<CharType> value;
  82. using PlainPath = remove_cvref_t<Path>;
  83. if(in >> std::quoted(value))
  84. path.value = PlainPath(maybe_convert_string<typename PlainPath::value_type>(value));
  85. return in;
  86. }
  87. };
  88. } // namespace detail
  89. /// \endcond
  90. } // namespace nowide
  91. } // namespace boost
  92. #elif defined(BOOST_PRAGMA_MESSAGE)
  93. BOOST_PRAGMA_MESSAGE("To use boost::nowide::quoted at least C++14 is required.")
  94. #endif
  95. #endif