You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

171 lines
4.8 KiB

  1. // Formatting library for C++ - formatters for standard library types
  2. //
  3. // Copyright (c) 2012 - present, Victor Zverovich
  4. // All rights reserved.
  5. //
  6. // For the license information refer to format.h.
  7. #ifndef FMT_STD_H_
  8. #define FMT_STD_H_
  9. #include <thread>
  10. #include <type_traits>
  11. #include <utility>
  12. #include "ostream.h"
  13. #if FMT_HAS_INCLUDE(<version>)
  14. # include <version>
  15. #endif
  16. // Checking FMT_CPLUSPLUS for warning suppression in MSVC.
  17. #if FMT_CPLUSPLUS >= 201703L
  18. # if FMT_HAS_INCLUDE(<filesystem>)
  19. # include <filesystem>
  20. # endif
  21. # if FMT_HAS_INCLUDE(<variant>)
  22. # include <variant>
  23. # endif
  24. #endif
  25. #ifdef __cpp_lib_filesystem
  26. FMT_BEGIN_NAMESPACE
  27. namespace detail {
  28. template <typename Char>
  29. void write_escaped_path(basic_memory_buffer<Char>& quoted,
  30. const std::filesystem::path& p) {
  31. write_escaped_string<Char>(std::back_inserter(quoted), p.string<Char>());
  32. }
  33. # ifdef _WIN32
  34. template <>
  35. inline void write_escaped_path<char>(basic_memory_buffer<char>& quoted,
  36. const std::filesystem::path& p) {
  37. auto s = p.u8string();
  38. write_escaped_string<char>(
  39. std::back_inserter(quoted),
  40. string_view(reinterpret_cast<const char*>(s.c_str()), s.size()));
  41. }
  42. # endif
  43. template <>
  44. inline void write_escaped_path<std::filesystem::path::value_type>(
  45. basic_memory_buffer<std::filesystem::path::value_type>& quoted,
  46. const std::filesystem::path& p) {
  47. write_escaped_string<std::filesystem::path::value_type>(
  48. std::back_inserter(quoted), p.native());
  49. }
  50. } // namespace detail
  51. template <typename Char>
  52. struct formatter<std::filesystem::path, Char>
  53. : formatter<basic_string_view<Char>> {
  54. template <typename FormatContext>
  55. auto format(const std::filesystem::path& p, FormatContext& ctx) const ->
  56. typename FormatContext::iterator {
  57. basic_memory_buffer<Char> quoted;
  58. detail::write_escaped_path(quoted, p);
  59. return formatter<basic_string_view<Char>>::format(
  60. basic_string_view<Char>(quoted.data(), quoted.size()), ctx);
  61. }
  62. };
  63. FMT_END_NAMESPACE
  64. #endif
  65. FMT_BEGIN_NAMESPACE
  66. template <typename Char>
  67. struct formatter<std::thread::id, Char> : basic_ostream_formatter<Char> {};
  68. FMT_END_NAMESPACE
  69. #ifdef __cpp_lib_variant
  70. FMT_BEGIN_NAMESPACE
  71. template <typename Char> struct formatter<std::monostate, Char> {
  72. template <typename ParseContext>
  73. FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
  74. return ctx.begin();
  75. }
  76. template <typename FormatContext>
  77. auto format(const std::monostate&, FormatContext& ctx) const
  78. -> decltype(ctx.out()) {
  79. auto out = ctx.out();
  80. out = detail::write<Char>(out, "monostate");
  81. return out;
  82. }
  83. };
  84. namespace detail {
  85. template <typename T>
  86. using variant_index_sequence =
  87. std::make_index_sequence<std::variant_size<T>::value>;
  88. // variant_size and variant_alternative check.
  89. template <typename T, typename U = void>
  90. struct is_variant_like_ : std::false_type {};
  91. template <typename T>
  92. struct is_variant_like_<T, std::void_t<decltype(std::variant_size<T>::value)>>
  93. : std::true_type {};
  94. // formattable element check
  95. template <typename T, typename C> class is_variant_formattable_ {
  96. template <std::size_t... I>
  97. static std::conjunction<
  98. is_formattable<std::variant_alternative_t<I, T>, C>...>
  99. check(std::index_sequence<I...>);
  100. public:
  101. static constexpr const bool value =
  102. decltype(check(variant_index_sequence<T>{}))::value;
  103. };
  104. template <typename Char, typename OutputIt, typename T>
  105. auto write_variant_alternative(OutputIt out, const T& v) -> OutputIt {
  106. if constexpr (is_string<T>::value)
  107. return write_escaped_string<Char>(out, detail::to_string_view(v));
  108. else if constexpr (std::is_same_v<T, Char>)
  109. return write_escaped_char(out, v);
  110. else
  111. return write<Char>(out, v);
  112. }
  113. } // namespace detail
  114. template <typename T> struct is_variant_like {
  115. static constexpr const bool value = detail::is_variant_like_<T>::value;
  116. };
  117. template <typename T, typename C> struct is_variant_formattable {
  118. static constexpr const bool value =
  119. detail::is_variant_formattable_<T, C>::value;
  120. };
  121. template <typename Variant, typename Char>
  122. struct formatter<
  123. Variant, Char,
  124. std::enable_if_t<std::conjunction_v<
  125. is_variant_like<Variant>, is_variant_formattable<Variant, Char>>>> {
  126. template <typename ParseContext>
  127. FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
  128. return ctx.begin();
  129. }
  130. template <typename FormatContext>
  131. auto format(const Variant& value, FormatContext& ctx) const
  132. -> decltype(ctx.out()) {
  133. auto out = ctx.out();
  134. out = detail::write<Char>(out, "variant(");
  135. std::visit(
  136. [&](const auto& v) {
  137. out = detail::write_variant_alternative<Char>(out, v);
  138. },
  139. value);
  140. *out++ = ')';
  141. return out;
  142. }
  143. };
  144. FMT_END_NAMESPACE
  145. #endif
  146. #endif // FMT_STD_H_