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.

177 lines
5.8 KiB

1 year ago
  1. // Formatting library for C++ - std::ostream support
  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_OSTREAM_H_
  8. #define FMT_OSTREAM_H_
  9. #include <ostream>
  10. #include "format.h"
  11. FMT_BEGIN_NAMESPACE
  12. template <typename Char> class basic_printf_parse_context;
  13. template <typename OutputIt, typename Char> class basic_printf_context;
  14. namespace detail {
  15. template <class Char> class formatbuf : public std::basic_streambuf<Char> {
  16. private:
  17. using int_type = typename std::basic_streambuf<Char>::int_type;
  18. using traits_type = typename std::basic_streambuf<Char>::traits_type;
  19. buffer<Char>& buffer_;
  20. public:
  21. formatbuf(buffer<Char>& buf) : buffer_(buf) {}
  22. protected:
  23. // The put-area is actually always empty. This makes the implementation
  24. // simpler and has the advantage that the streambuf and the buffer are always
  25. // in sync and sputc never writes into uninitialized memory. The obvious
  26. // disadvantage is that each call to sputc always results in a (virtual) call
  27. // to overflow. There is no disadvantage here for sputn since this always
  28. // results in a call to xsputn.
  29. int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE {
  30. if (!traits_type::eq_int_type(ch, traits_type::eof()))
  31. buffer_.push_back(static_cast<Char>(ch));
  32. return ch;
  33. }
  34. std::streamsize xsputn(const Char* s, std::streamsize count) FMT_OVERRIDE {
  35. buffer_.append(s, s + count);
  36. return count;
  37. }
  38. };
  39. struct converter {
  40. template <typename T, FMT_ENABLE_IF(is_integral<T>::value)> converter(T);
  41. };
  42. template <typename Char> struct test_stream : std::basic_ostream<Char> {
  43. private:
  44. void_t<> operator<<(converter);
  45. };
  46. // Hide insertion operators for built-in types.
  47. template <typename Char, typename Traits>
  48. void_t<> operator<<(std::basic_ostream<Char, Traits>&, Char);
  49. template <typename Char, typename Traits>
  50. void_t<> operator<<(std::basic_ostream<Char, Traits>&, char);
  51. template <typename Traits>
  52. void_t<> operator<<(std::basic_ostream<char, Traits>&, char);
  53. template <typename Traits>
  54. void_t<> operator<<(std::basic_ostream<char, Traits>&, signed char);
  55. template <typename Traits>
  56. void_t<> operator<<(std::basic_ostream<char, Traits>&, unsigned char);
  57. // Checks if T has a user-defined operator<< (e.g. not a member of
  58. // std::ostream).
  59. template <typename T, typename Char> class is_streamable {
  60. private:
  61. template <typename U>
  62. static bool_constant<!std::is_same<decltype(std::declval<test_stream<Char>&>()
  63. << std::declval<U>()),
  64. void_t<>>::value>
  65. test(int);
  66. template <typename> static std::false_type test(...);
  67. using result = decltype(test<T>(0));
  68. public:
  69. static const bool value = result::value;
  70. };
  71. // Write the content of buf to os.
  72. template <typename Char>
  73. void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) {
  74. const Char* buf_data = buf.data();
  75. using unsigned_streamsize = std::make_unsigned<std::streamsize>::type;
  76. unsigned_streamsize size = buf.size();
  77. unsigned_streamsize max_size = to_unsigned(max_value<std::streamsize>());
  78. do {
  79. unsigned_streamsize n = size <= max_size ? size : max_size;
  80. os.write(buf_data, static_cast<std::streamsize>(n));
  81. buf_data += n;
  82. size -= n;
  83. } while (size != 0);
  84. }
  85. template <typename Char, typename T>
  86. void format_value(buffer<Char>& buf, const T& value,
  87. locale_ref loc = locale_ref()) {
  88. formatbuf<Char> format_buf(buf);
  89. std::basic_ostream<Char> output(&format_buf);
  90. #if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
  91. if (loc) output.imbue(loc.get<std::locale>());
  92. #endif
  93. output << value;
  94. output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
  95. buf.try_resize(buf.size());
  96. }
  97. // Formats an object of type T that has an overloaded ostream operator<<.
  98. template <typename T, typename Char>
  99. struct fallback_formatter<T, Char, enable_if_t<is_streamable<T, Char>::value>>
  100. : private formatter<basic_string_view<Char>, Char> {
  101. FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
  102. -> decltype(ctx.begin()) {
  103. return formatter<basic_string_view<Char>, Char>::parse(ctx);
  104. }
  105. template <typename ParseCtx,
  106. FMT_ENABLE_IF(std::is_same<
  107. ParseCtx, basic_printf_parse_context<Char>>::value)>
  108. auto parse(ParseCtx& ctx) -> decltype(ctx.begin()) {
  109. return ctx.begin();
  110. }
  111. template <typename OutputIt>
  112. auto format(const T& value, basic_format_context<OutputIt, Char>& ctx)
  113. -> OutputIt {
  114. basic_memory_buffer<Char> buffer;
  115. format_value(buffer, value, ctx.locale());
  116. basic_string_view<Char> str(buffer.data(), buffer.size());
  117. return formatter<basic_string_view<Char>, Char>::format(str, ctx);
  118. }
  119. template <typename OutputIt>
  120. auto format(const T& value, basic_printf_context<OutputIt, Char>& ctx)
  121. -> OutputIt {
  122. basic_memory_buffer<Char> buffer;
  123. format_value(buffer, value, ctx.locale());
  124. return std::copy(buffer.begin(), buffer.end(), ctx.out());
  125. }
  126. };
  127. } // namespace detail
  128. template <typename Char>
  129. void vprint(std::basic_ostream<Char>& os, basic_string_view<Char> format_str,
  130. basic_format_args<buffer_context<type_identity_t<Char>>> args) {
  131. basic_memory_buffer<Char> buffer;
  132. detail::vformat_to(buffer, format_str, args);
  133. detail::write_buffer(os, buffer);
  134. }
  135. /**
  136. \rst
  137. Prints formatted data to the stream *os*.
  138. **Example**::
  139. fmt::print(cerr, "Don't {}!", "panic");
  140. \endrst
  141. */
  142. template <typename S, typename... Args,
  143. typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>>
  144. void print(std::basic_ostream<Char>& os, const S& format_str, Args&&... args) {
  145. vprint(os, to_string_view(format_str),
  146. fmt::make_args_checked<Args...>(format_str, args...));
  147. }
  148. FMT_END_NAMESPACE
  149. #endif // FMT_OSTREAM_H_