13class file_ostreambuf :
public std::streambuf
16 file_ostreambuf() =
default;
25 ~file_ostreambuf()
override
30 file_ostreambuf(
const file_ostreambuf&) =
delete;
31 auto operator=(
const file_ostreambuf&) -> file_ostreambuf& =
delete;
33 file_ostreambuf(file_ostreambuf&& other) noexcept
35 , owns_file_(other.owns_file_)
36 , buffer_(other.buffer_)
38 other.file_ =
nullptr;
39 other.owns_file_ =
false;
40 other.setp(
nullptr,
nullptr);
44 auto open(
const std::string& absolute_path, std::ios_base::openmode mode) ->
bool
47 mode |= std::ios_base::out;
53 file_ = std::fopen(absolute_path.c_str(), stdio_mode);
54 owns_file_ = file_ !=
nullptr;
56 return file_ !=
nullptr;
72 auto is_open() const ->
bool
74 return file_ !=
nullptr;
77 auto native_handle() const -> FILE*
86 setp(
nullptr,
nullptr);
89 auto tell_file() const ->
long long
100 if(pptr() !=
nullptr && pbase() !=
nullptr && pptr() >= pbase())
102 return file_pos +
static_cast<long long>(pptr() - pbase());
107 auto seek_file(
long long offset,
int whence) ->
bool
117 if(whence == SEEK_END)
124 offset =
size + offset;
135 auto query_file_size() ->
long long
148 auto flush_file() ->
bool
150 return sync_put_area() && file_ !=
nullptr && std::fflush(file_) == 0;
154 auto overflow(int_type ch) -> int_type
override
158 return traits_type::eof();
160 if(ch != traits_type::eof())
162 const char value = traits_type::to_char_type(ch);
163 if(std::fwrite(&value, 1, 1, file_) != 1)
165 return traits_type::eof();
172 auto xsputn(
const char* src, std::streamsize
count) -> std::streamsize
override
174 if(
count <= 0 || src ==
nullptr)
178 std::streamsize written = 0;
179 while(written <
count)
181 if(pptr() == epptr() && overflow(traits_type::to_int_type(src[written])) == traits_type::eof())
185 const std::streamsize available = epptr() - pptr();
186 const std::streamsize chunk = std::min(
count - written, available);
187 traits_type::copy(pptr(), src + written,
static_cast<std::size_t
>(chunk));
188 pbump(
static_cast<int>(chunk));
194 auto sync() ->
int override
196 return sync_put_area() ? 0 : -1;
199 auto seekoff(std::streamoff off, std::ios_base::seekdir way, std::ios_base::openmode which)
200 -> std::streampos
override
202 if((which & std::ios_base::out) == 0 || file_ ==
nullptr)
204 return std::streampos(std::streamoff(-1));
206 long long next_pos = 0;
209 case std::ios_base::beg:
210 next_pos =
static_cast<long long>(off);
212 case std::ios_base::cur:
213 next_pos = tell_file() +
static_cast<long long>(off);
215 case std::ios_base::end:
217 const long long size = query_file_size();
220 return std::streampos(std::streamoff(-1));
222 next_pos =
size +
static_cast<long long>(off);
226 return std::streampos(std::streamoff(-1));
230 return std::streampos(std::streamoff(-1));
232 if(!seek_file(next_pos, SEEK_SET))
234 return std::streampos(std::streamoff(-1));
236 return std::streampos(
static_cast<std::streamoff
>(next_pos));
239 auto seekpos(std::streampos sp, std::ios_base::openmode which) -> std::streampos
override
241 return seekoff(
static_cast<std::streamoff
>(sp), std::ios_base::beg, which);
245 void reset_put_area()
247 setp(buffer_.data(), buffer_.data() +
static_cast<std::ptrdiff_t
>(buffer_.size()));
250 auto sync_put_area() ->
bool
256 if(pptr() ==
nullptr || pbase() ==
nullptr)
260 const std::size_t pending =
static_cast<std::size_t
>(pptr() - pbase());
265 const std::size_t written = std::fwrite(pbase(), 1, pending, file_);
267 return written == pending;
272 if(file_ !=
nullptr && owns_file_)
280 FILE* file_ =
nullptr;
281 bool owns_file_ =
false;
282 std::array<char, file_stream_detail::default_buffer_size> buffer_{};
285auto open_write_buffer(
const std::string& absolute_path, std::ios_base::openmode mode)
286 -> std::unique_ptr<file_ostreambuf>
288 auto buffer = std::make_unique<file_ostreambuf>();
289 if(!buffer->open(absolute_path, mode))
309 :
std::ostream(nullptr)
310 , impl_(
std::make_unique<
impl>(
std::make_unique<file_ostreambuf>()))
312 rdbuf(impl_->buffer.get());
321 :
std::ostream(nullptr)
323 auto buffer = open_write_buffer(absolute_path, mode);
326 buffer = std::make_unique<file_ostreambuf>();
328 impl_ = std::make_unique<impl>(std::move(buffer));
329 rdbuf(impl_->buffer.get());
332 setstate(std::ios::failbit);
338 open(file_path.string(), mode);
345 impl_ = std::make_unique<impl>(std::make_unique<file_ostreambuf>());
346 rdbuf(impl_->buffer.get());
348 if(!impl_->buffer->open(absolute_path, mode))
350 setstate(std::ios::failbit);
357 :
std::ostream(nullptr)
358 , impl_(
std::make_unique<
impl>(
std::make_unique<file_ostreambuf>()))
360 impl_->buffer->attach(file, ownership);
361 rdbuf(impl_->buffer.get());
365 : std::ostream(
nullptr)
366 , impl_(std::move(other.impl_))
368 rdbuf(impl_ ? impl_->buffer.get() :
nullptr);
369 other.rdbuf(
nullptr);
376 impl_ = std::move(other.impl_);
377 rdbuf(impl_ ? impl_->buffer.get() :
nullptr);
378 other.rdbuf(
nullptr);
387 return impl_ && impl_->buffer && impl_->buffer->is_open();
392 return impl_ && impl_->buffer ? impl_->buffer->native_handle() :
nullptr;
397 return impl_ && impl_->buffer ? impl_->buffer->tell_file() : -1;
402 return impl_ && impl_->buffer ? impl_->buffer->query_file_size() : -1;
407 return impl_ && impl_->buffer && impl_->buffer->seek_file(offset, whence);
413 return impl_ && impl_->buffer && impl_->buffer->flush_file();
418 if(impl_ && impl_->buffer)
420 impl_->buffer->close();
stdio-backed output stream. Accepts std::ios open flags (e.g. std::ios::binary | std::ios::app)
auto file_size() const -> long long
auto operator=(const file_ostream &) -> file_ostream &=delete
void open(const path &file_path, std::ios_base::openmode mode=default_file_write_mode)
auto is_open() const -> bool
auto seek(long long offset, int whence=SEEK_SET) -> bool
auto flush_file() -> bool
auto tell() const -> long long
auto native_handle() const -> FILE *
auto stdio_file_size(FILE *file) -> long long
auto stdio_tell64(FILE *file) -> long long
auto openmode_to_stdio_mode(std::ios_base::openmode mode, char(&out)[4]) -> bool
auto stdio_seek64(FILE *file, long long offset, int origin) -> int
file_stream_ownership
Whether a file stream wrapper should fclose its FILE* on destruction.
void close(const std::string &scope)
Closes the specified scope.
Hash specialization for batch_key to enable use in std::unordered_map.
std::unique_ptr< file_ostreambuf > buffer
impl(std::unique_ptr< file_ostreambuf > stream_buffer)