#define FMT_OSTREAM_H_
#include <ostream>
+
#include "format.h"
FMT_BEGIN_NAMESPACE
-namespace internal {
+
+template <typename Char> class basic_printf_parse_context;
+template <typename OutputIt, typename Char> class basic_printf_context;
+
+namespace detail {
template <class Char> class formatbuf : public std::basic_streambuf<Char> {
private:
- typedef typename std::basic_streambuf<Char>::int_type int_type;
- typedef typename std::basic_streambuf<Char>::traits_type traits_type;
+ using int_type = typename std::basic_streambuf<Char>::int_type;
+ using traits_type = typename std::basic_streambuf<Char>::traits_type;
- basic_buffer<Char>& buffer_;
+ buffer<Char>& buffer_;
public:
- formatbuf(basic_buffer<Char>& buffer) : buffer_(buffer) {}
+ formatbuf(buffer<Char>& buf) : buffer_(buf) {}
protected:
// The put-area is actually always empty. This makes the implementation
template <typename Char> struct test_stream : std::basic_ostream<Char> {
private:
- struct null;
// Hide all operator<< from std::basic_ostream<Char>.
- void operator<<(null);
+ void_t<> operator<<(null<>);
+ void_t<> operator<<(const Char*);
+
+ template <typename T, FMT_ENABLE_IF(std::is_convertible<T, int>::value &&
+ !std::is_enum<T>::value)>
+ void_t<> operator<<(T);
};
// Checks if T has a user-defined operator<< (e.g. not a member of
template <typename T, typename Char> class is_streamable {
private:
template <typename U>
- static decltype((void)(internal::declval<test_stream<Char>&>()
- << internal::declval<U>()),
- std::true_type())
+ static bool_constant<!std::is_same<decltype(std::declval<test_stream<Char>&>()
+ << std::declval<U>()),
+ void_t<>>::value>
test(int);
template <typename> static std::false_type test(...);
- typedef decltype(test<T>(0)) result;
+ using result = decltype(test<T>(0));
public:
static const bool value = result::value;
// Write the content of buf to os.
template <typename Char>
-void write(std::basic_ostream<Char>& os, basic_buffer<Char>& buf) {
- const Char* data = buf.data();
- typedef std::make_unsigned<std::streamsize>::type UnsignedStreamSize;
- UnsignedStreamSize size = buf.size();
- UnsignedStreamSize max_size =
- internal::to_unsigned((std::numeric_limits<std::streamsize>::max)());
+void write(std::basic_ostream<Char>& os, buffer<Char>& buf) {
+ const Char* buf_data = buf.data();
+ using unsigned_streamsize = std::make_unsigned<std::streamsize>::type;
+ unsigned_streamsize size = buf.size();
+ unsigned_streamsize max_size = to_unsigned(max_value<std::streamsize>());
do {
- UnsignedStreamSize n = size <= max_size ? size : max_size;
- os.write(data, static_cast<std::streamsize>(n));
- data += n;
+ unsigned_streamsize n = size <= max_size ? size : max_size;
+ os.write(buf_data, static_cast<std::streamsize>(n));
+ buf_data += n;
size -= n;
} while (size != 0);
}
template <typename Char, typename T>
-void format_value(basic_buffer<Char>& buffer, const T& value) {
- internal::formatbuf<Char> format_buf(buffer);
+void format_value(buffer<Char>& buf, const T& value,
+ locale_ref loc = locale_ref()) {
+ formatbuf<Char> format_buf(buf);
std::basic_ostream<Char> output(&format_buf);
- output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
+#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
+ if (loc) output.imbue(loc.get<std::locale>());
+#endif
output << value;
- buffer.resize(buffer.size());
+ output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
+ buf.resize(buf.size());
}
// Formats an object of type T that has an overloaded ostream operator<<.
template <typename T, typename Char>
-struct fallback_formatter<
- T, Char,
- typename std::enable_if<internal::is_streamable<T, Char>::value>::type>
- : formatter<basic_string_view<Char>, Char> {
- template <typename Context>
- auto format(const T& value, Context& ctx) -> decltype(ctx.out()) {
+struct fallback_formatter<T, Char, enable_if_t<is_streamable<T, Char>::value>>
+ : private formatter<basic_string_view<Char>, Char> {
+ FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
+ -> decltype(ctx.begin()) {
+ return formatter<basic_string_view<Char>, Char>::parse(ctx);
+ }
+ template <typename ParseCtx,
+ FMT_ENABLE_IF(std::is_same<
+ ParseCtx, basic_printf_parse_context<Char>>::value)>
+ auto parse(ParseCtx& ctx) -> decltype(ctx.begin()) {
+ return ctx.begin();
+ }
+
+ template <typename OutputIt>
+ auto format(const T& value, basic_format_context<OutputIt, Char>& ctx)
+ -> OutputIt {
basic_memory_buffer<Char> buffer;
- internal::format_value(buffer, value);
+ format_value(buffer, value, ctx.locale());
basic_string_view<Char> str(buffer.data(), buffer.size());
return formatter<basic_string_view<Char>, Char>::format(str, ctx);
}
+ template <typename OutputIt>
+ auto format(const T& value, basic_printf_context<OutputIt, Char>& ctx)
+ -> OutputIt {
+ basic_memory_buffer<Char> buffer;
+ format_value(buffer, value, ctx.locale());
+ return std::copy(buffer.begin(), buffer.end(), ctx.out());
+ }
};
-} // namespace internal
-
-// Disable conversion to int if T has an overloaded operator<< which is a free
-// function (not a member of std::ostream).
-template <typename T, typename Char> struct convert_to_int<T, Char, void> {
- static const bool value = convert_to_int<T, Char, int>::value &&
- !internal::is_streamable<T, Char>::value;
-};
+} // namespace detail
template <typename Char>
-inline void vprint(
- std::basic_ostream<Char>& os, basic_string_view<Char> format_str,
- basic_format_args<typename buffer_context<Char>::type> args) {
+void vprint(std::basic_ostream<Char>& os, basic_string_view<Char> format_str,
+ basic_format_args<buffer_context<type_identity_t<Char>>> args) {
basic_memory_buffer<Char> buffer;
- internal::vformat_to(buffer, format_str, args);
- internal::write(os, buffer);
+ detail::vformat_to(buffer, format_str, args);
+ detail::write(os, buffer);
}
+
/**
\rst
Prints formatted data to the stream *os*.
\endrst
*/
template <typename S, typename... Args,
- FMT_ENABLE_IF(internal::is_string<S>::value)>
-inline void print(std::basic_ostream<FMT_CHAR(S)>& os, const S& format_str,
- const Args&... args) {
+ typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>>
+void print(std::basic_ostream<Char>& os, const S& format_str, Args&&... args) {
vprint(os, to_string_view(format_str),
- {internal::make_args_checked(format_str, args...)});
+ detail::make_args_checked<Args...>(format_str, args...));
}
FMT_END_NAMESPACE