12class file_istreambuf :
public std::streambuf
15 file_istreambuf() =
default;
23 ~file_istreambuf()
override
28 file_istreambuf(
const file_istreambuf&) =
delete;
29 auto operator=(
const file_istreambuf&) -> file_istreambuf& =
delete;
31 file_istreambuf(file_istreambuf&& other) noexcept
33 , owns_file_(other.owns_file_)
34 , cached_size_(other.cached_size_)
35 , underflow_char_(other.underflow_char_)
37 other.file_ =
nullptr;
38 other.owns_file_ =
false;
39 other.cached_size_ = -1;
40 other.invalidate_get_area();
41 invalidate_get_area();
44 auto operator=(file_istreambuf&& other)
noexcept -> file_istreambuf&
50 owns_file_ = other.owns_file_;
51 cached_size_ = other.cached_size_;
52 underflow_char_ = other.underflow_char_;
53 other.file_ =
nullptr;
54 other.owns_file_ =
false;
55 other.cached_size_ = -1;
56 other.invalidate_get_area();
57 invalidate_get_area();
62 auto open(
const std::string& absolute_path, std::ios_base::openmode mode) ->
bool
65 mode |= std::ios_base::in;
71 file_ = std::fopen(absolute_path.c_str(), stdio_mode);
72 owns_file_ = file_ !=
nullptr;
74 invalidate_get_area();
75 return file_ !=
nullptr;
88 invalidate_get_area();
92 auto is_open() const ->
bool
94 return file_ !=
nullptr;
97 auto native_handle() const -> FILE*
106 invalidate_get_area();
109 auto tell_file() const ->
long long
115 if(gptr() !=
nullptr && egptr() >= gptr())
118 static_cast<long long>(egptr() - gptr());
123 auto seek_file(
long long offset,
int whence) ->
bool
129 if(whence == SEEK_END)
131 const long long size = cached_file_size();
136 offset =
size + offset;
139 if(whence == SEEK_CUR && gptr() !=
nullptr && egptr() >= gptr())
141 offset -=
static_cast<long long>(egptr() - gptr());
143 invalidate_get_area();
147 auto query_file_size() ->
long long
149 return cached_file_size();
153 auto underflow() -> int_type
override
155 if(gptr() !=
nullptr && gptr() < egptr())
157 return traits_type::to_int_type(*gptr());
161 return traits_type::eof();
163 if(std::fread(&underflow_char_, 1, 1, file_) != 1)
165 invalidate_get_area();
166 return traits_type::eof();
168 setg(&underflow_char_, &underflow_char_, &underflow_char_ + 1);
169 return traits_type::to_int_type(underflow_char_);
172 auto xsgetn(
char* dest, std::streamsize
count) -> std::streamsize
override
174 if(
count <= 0 || dest ==
nullptr || file_ ==
nullptr)
178 std::streamsize copied = 0;
179 if(gptr() != egptr())
181 const std::streamsize available =
static_cast<std::streamsize
>(egptr() - gptr());
182 const std::streamsize chunk = std::min(
count, available);
183 traits_type::copy(dest, gptr(),
static_cast<std::size_t
>(chunk));
184 gbump(
static_cast<int>(chunk));
187 while(copied <
count)
189 const std::size_t bytes_read =
190 std::fread(dest + copied, 1,
static_cast<std::size_t
>(
count - copied), file_);
195 copied +=
static_cast<std::streamsize
>(bytes_read);
200 auto seekoff(std::streamoff off, std::ios_base::seekdir way, std::ios_base::openmode which)
201 -> std::streampos
override
203 if((which & std::ios_base::in) == 0 || file_ ==
nullptr)
205 return std::streampos(std::streamoff(-1));
207 const long long file_size = cached_file_size();
210 return std::streampos(std::streamoff(-1));
212 long long next_pos = 0;
215 case std::ios_base::beg:
216 next_pos =
static_cast<long long>(off);
218 case std::ios_base::cur:
219 next_pos = tell_file() +
static_cast<long long>(off);
221 case std::ios_base::end:
222 next_pos = file_size +
static_cast<long long>(off);
225 return std::streampos(std::streamoff(-1));
227 if(next_pos < 0 || next_pos > file_size)
229 return std::streampos(std::streamoff(-1));
231 if(!seek_file(next_pos, SEEK_SET))
233 return std::streampos(std::streamoff(-1));
235 return std::streampos(
static_cast<std::streamoff
>(next_pos));
238 auto seekpos(std::streampos sp, std::ios_base::openmode which) -> std::streampos
override
240 return seekoff(
static_cast<std::streamoff
>(sp), std::ios_base::beg, which);
244 auto cached_file_size() ->
long long
246 if(cached_size_ >= 0)
254 void invalidate_get_area()
256 setg(
nullptr,
nullptr,
nullptr);
261 if(file_ !=
nullptr && owns_file_)
269 FILE* file_ =
nullptr;
270 bool owns_file_ =
false;
271 long long cached_size_ = -1;
272 char underflow_char_ =
'\0';
275auto open_read_buffer(
const std::string& absolute_path, std::ios_base::openmode mode)
276 -> std::unique_ptr<file_istreambuf>
278 auto buffer = std::make_unique<file_istreambuf>();
279 if(!buffer->open(absolute_path, mode))
299 :
std::istream(nullptr)
300 , impl_(
std::make_unique<
impl>(
std::make_unique<file_istreambuf>()))
302 rdbuf(impl_->buffer.get());
311 :
std::istream(nullptr)
313 auto buffer = open_read_buffer(absolute_path, mode);
316 buffer = std::make_unique<file_istreambuf>();
318 impl_ = std::make_unique<impl>(std::move(buffer));
319 rdbuf(impl_->buffer.get());
322 setstate(std::ios::failbit);
328 open(file_path.string(), mode);
335 impl_ = std::make_unique<impl>(std::make_unique<file_istreambuf>());
336 rdbuf(impl_->buffer.get());
338 if(!impl_->buffer->open(absolute_path, mode))
340 setstate(std::ios::failbit);
347 :
std::istream(nullptr)
348 , impl_(
std::make_unique<
impl>(
std::make_unique<file_istreambuf>()))
350 impl_->buffer->attach(file, ownership);
351 rdbuf(impl_->buffer.get());
355 : std::istream(
nullptr)
356 , impl_(std::move(other.impl_))
358 rdbuf(impl_ ? impl_->buffer.get() :
nullptr);
359 other.rdbuf(
nullptr);
366 impl_ = std::move(other.impl_);
367 rdbuf(impl_ ? impl_->buffer.get() :
nullptr);
368 other.rdbuf(
nullptr);
377 return impl_ && impl_->buffer && impl_->buffer->is_open();
382 return impl_ && impl_->buffer ? impl_->buffer->native_handle() :
nullptr;
387 return impl_ && impl_->buffer ? impl_->buffer->tell_file() : -1;
392 return impl_ && impl_->buffer ? impl_->buffer->query_file_size() : -1;
397 return impl_ && impl_->buffer && impl_->buffer->seek_file(offset, whence);
402 if(impl_ && impl_->buffer)
404 impl_->buffer->close();
stdio-backed input stream. Accepts std::ios open flags (e.g. std::ios::binary) when opening a
auto seek(long long offset, int whence=SEEK_SET) -> bool
void open(const path &file_path, std::ios_base::openmode mode=default_file_read_mode)
auto file_size() const -> long long
auto is_open() const -> bool
auto tell() const -> long long
auto native_handle() const -> FILE *
auto operator=(const file_istream &) -> file_istream &=delete
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.
impl(std::unique_ptr< file_istreambuf > stream_buffer)
std::unique_ptr< file_istreambuf > buffer