20#ifndef PLYWOOT_BUFFERED_ISTREAM_HPP
21#define PLYWOOT_BUFFERED_ISTREAM_HPP
34constexpr std::size_t IStreamBufferSize{1024 * 1024};
38namespace plywoot::detail {
49 explicit BufferedIStream(std::istream &is) : is_{is} { buffer(); }
52 BufferedIStream(
const BufferedIStream &) =
delete;
53 BufferedIStream &operator=(
const BufferedIStream &) =
delete;
56 bool eof()
const {
return *c_ == EOF; }
61 const char *data()
const {
return c_; }
62 const char *&data() {
return c_; }
71 if (c_ +
sizeof(T) > eob_) buffer(
sizeof(T));
74 return *
reinterpret_cast<const T *
>(t);
80 template<
typename From,
typename To, std::
size_t N>
81 std::uint8_t *read(std::uint8_t *dest)
83 if constexpr (std::is_same_v<From, To>)
85 return this->memcpy(dest, N *
sizeof(From));
90 N *
sizeof(From) <= IStreamBufferSize,
91 "input stream buffer size is too small; increase IStreamBufferSize");
93 constexpr std::size_t bytesToRead = N *
sizeof(From);
94 if (c_ + bytesToRead > eob_) buffer(bytesToRead);
96 const From *from =
reinterpret_cast<const From *
>(c_);
97 To *to =
reinterpret_cast<To *
>(dest);
98 for (std::size_t i = 0; i < N; ++i) { *to++ = *from++; }
102 return reinterpret_cast<std::uint8_t *
>(to);
109 inline std::uint8_t *memcpy(std::uint8_t *dest, std::size_t n)
111 if (n > IStreamBufferSize)
113 const std::size_t remaining = eob_ - c_;
114 std::memcpy(dest, c_, remaining);
115 is_.read(
reinterpret_cast<char *
>(dest) + remaining, n - remaining);
120 if (c_ + n > eob_) buffer(n);
122 std::memcpy(dest, c_, n);
130 void skip(std::size_t n)
132 const std::size_t remaining = eob_ - c_;
133 if (remaining > n) { c_ += n; }
136 is_.seekg(n - remaining, std::ios_base::cur);
144 void skipLines(std::size_t n)
146 while (*c_ != EOF && n > 0)
148 c_ =
static_cast<const char *
>(std::memchr(c_,
'\n', eob_ - c_));
161 inline void skipWhitespace()
163 while (0 <= *c_ && *c_ <= 0x20) { readCharacter(); }
169 inline void skipNonWhitespace()
171 while (*c_ > 0x20) readCharacter();
178 void buffer(std::size_t minimum)
180 std::size_t remaining = eob_ - c_;
181 if (remaining < minimum)
183 std::memcpy(buffer_.get(), c_, remaining);
184 if (!is_.read(buffer_.get() + remaining, IStreamBufferSize - remaining))
188 remaining += is_.gcount();
189 std::fill_n(buffer_.get() + remaining, IStreamBufferSize - remaining, EOF);
200 if (!is_.read(buffer_.get(), IStreamBufferSize))
204 auto remaining = is_.gcount();
205 std::fill_n(buffer_.get() + remaining, IStreamBufferSize - remaining, EOF);
213 inline void readCharacter()
215 if (c_++ == eob_) { buffer(); }
219 std::unique_ptr<char[]> buffer_{
new char[IStreamBufferSize]};
227 const char *c_{buffer_.get() + IStreamBufferSize};
229 const char *eob_{buffer_.get() + IStreamBufferSize};