fmt::ostream - aggregate buffer instead of inheriting it

Some MSVC-specific behavior:
When class fmt::ostream inherits detail::buffer - the last gets implicitly exported when fmt is built as a shared library.
Unless os.h is included, the compiler assumes detail::buffer is not externally exported and instantiets a local copy of it, which causes ODR violation.
With aggregation - there is no extra exporting of detail::buffer symbols.
This commit is contained in:
Ihor Dutchak 2022-10-13 22:42:27 +03:00
parent 9254cfa6f0
commit ef4074802a
2 changed files with 38 additions and 20 deletions

View File

@ -379,32 +379,23 @@ struct ostream_params {
# endif # endif
}; };
FMT_END_DETAIL_NAMESPACE class ostream_buffer final : public detail::buffer<char> {
// Added {} below to work around default constructor error known to
// occur in Xcode versions 7.2.1 and 8.2.1.
constexpr detail::buffer_size buffer_size{};
/** A fast output stream which is not thread-safe. */
class FMT_API ostream final : private detail::buffer<char> {
private:
file file_; file file_;
void grow(size_t) override; FMT_API void grow(size_t) override;
ostream(cstring_view path, const detail::ostream_params& params) public:
ostream_buffer(cstring_view path, const detail::ostream_params& params)
: file_(path, params.oflag) { : file_(path, params.oflag) {
set(new char[params.buffer_size], params.buffer_size); set(new char[params.buffer_size], params.buffer_size);
} }
ostream_buffer(ostream_buffer&& other)
public:
ostream(ostream&& other)
: detail::buffer<char>(other.data(), other.size(), other.capacity()), : detail::buffer<char>(other.data(), other.size(), other.capacity()),
file_(std::move(other.file_)) { file_(std::move(other.file_)) {
other.clear(); other.clear();
other.set(nullptr, 0); other.set(nullptr, 0);
} }
~ostream() { ~ostream_buffer() {
flush(); flush();
delete[] data(); delete[] data();
} }
@ -415,20 +406,45 @@ class FMT_API ostream final : private detail::buffer<char> {
clear(); clear();
} }
template <typename... T>
friend ostream output_file(cstring_view path, T... params);
void close() { void close() {
flush(); flush();
file_.close(); file_.close();
} }
};
FMT_END_DETAIL_NAMESPACE
// Added {} below to work around default constructor error known to
// occur in Xcode versions 7.2.1 and 8.2.1.
constexpr detail::buffer_size buffer_size{};
/** A fast output stream which is not thread-safe. */
class FMT_API ostream final {
private:
FMT_MSC_WARNING(suppress : 4251)
detail::ostream_buffer buffer_;
ostream(cstring_view path, const detail::ostream_params& params)
: buffer_(path, params) {}
public:
ostream(ostream&& other) : buffer_(std::move(other.buffer_)) {}
~ostream();
void flush() { buffer_.flush(); }
template <typename... T>
friend ostream output_file(cstring_view path, T... params);
void close() { buffer_.close(); }
/** /**
Formats ``args`` according to specifications in ``fmt`` and writes the Formats ``args`` according to specifications in ``fmt`` and writes the
output to the file. output to the file.
*/ */
template <typename... T> void print(format_string<T...> fmt, T&&... args) { template <typename... T> void print(format_string<T...> fmt, T&&... args) {
vformat_to(detail::buffer_appender<char>(*this), fmt, vformat_to(detail::buffer_appender<char>(buffer_), fmt,
fmt::make_format_args(args...)); fmt::make_format_args(args...));
} }
}; };

View File

@ -366,8 +366,10 @@ long getpagesize() {
# endif # endif
} }
FMT_API void ostream::grow(size_t) { FMT_API void detail::ostream_buffer::grow(size_t) {
if (this->size() == this->capacity()) flush(); if (this->size() == this->capacity()) flush();
} }
ostream::~ostream() = default;
#endif // FMT_USE_FCNTL #endif // FMT_USE_FCNTL
FMT_END_NAMESPACE FMT_END_NAMESPACE