#include "input.h" #include "output.h" #include "str.h" #include #include #include #include #include #include #include #include #include IInputStream::IInputStream() noexcept = default; IInputStream::~IInputStream() = default; size_t IInputStream::DoReadTo(TString& st, char to) { char ch; if (!Read(&ch, 1)) { return 0; } st.clear(); size_t result = 0; do { ++result; if (ch == to) { break; } st += ch; } while (Read(&ch, 1)); return result; } ui64 IInputStream::DoReadAll(IOutputStream& out) { TTempBuf buffer; void* ptr = buffer.Data(); size_t size = buffer.Size(); ui64 result = 0; while (size_t read = Read(ptr, size)) { out.Write(ptr, read); result += read; } return result; } size_t IInputStream::Load(void* buf_in, size_t len) { char* buf = (char*)buf_in; while (len) { const size_t ret = Read(buf, len); buf += ret; len -= ret; if (ret == 0) { break; } } return buf - (char*)buf_in; } void IInputStream::LoadOrFail(void* buf, size_t len) { const size_t realLen = Load(buf, len); if (Y_UNLIKELY(realLen != len)) { ythrow yexception() << "Failed to read required number of bytes from stream! Expected: " << len << ", gained: " << realLen << "!"; } } size_t IInputStream::ReadLine(TString& st) { const size_t ret = ReadTo(st, '\n'); if (ret && !st.empty() && st.back() == '\r') { st.pop_back(); } return ret; } size_t IInputStream::ReadLine(TUtf16String& w) { TString s; size_t result = ReadLine(s); if (result) { UTF8ToWide(s, w); } return result; } TString IInputStream::ReadLine() { TString ret; if (!ReadLine(ret)) { ythrow yexception() << "can not read line from stream"; } return ret; } TString IInputStream::ReadTo(char ch) { TString ret; if (!ReadTo(ret, ch)) { ythrow yexception() << "can not read from stream"; } return ret; } size_t IInputStream::Skip(size_t sz) { return DoSkip(sz); } size_t IInputStream::DoSkip(size_t sz) { if (sz < 128) { return Load(alloca(sz), sz); } TTempBuf buf; size_t total = 0; while (sz) { const size_t lresult = Read(buf.Data(), Min(sz, buf.Size())); if (lresult == 0) { return total; } total += lresult; sz -= lresult; } return total; } TString IInputStream::ReadAll() { TString result; TStringOutput stream(result); DoReadAll(stream); return result; } ui64 IInputStream::ReadAll(IOutputStream& out) { return DoReadAll(out); } ui64 TransferData(IInputStream* in, IOutputStream* out) { return in->ReadAll(*out); } namespace { struct TStdIn: public IInputStream { ~TStdIn() override = default; size_t DoRead(void* buf, size_t len) override { const size_t ret = fread(buf, 1, len, F_); if (ret < len && ferror(F_)) { ythrow TSystemError() << "can not read from stdin"; } return ret; } FILE* F_ = stdin; }; #if defined(_win_) using TGetLine = TStdIn; #else #if defined(_bionic_) using TGetLineBase = TStdIn; #else struct TGetLineBase: public TStdIn { ~TGetLineBase() override { free(B_); } size_t DoReadTo(TString& st, char ch) override { auto&& guard = Guard(M_); (void)guard; const auto r = getdelim(&B_, &L_, ch, F_); if (r < 0) { if (ferror(F_)) { ythrow TSystemError() << "can not read from stdin"; } st.clear(); return 0; } st.AssignNoAlias(B_, r); if (st && st.back() == ch) { st.pop_back(); } return r; } TAdaptiveLock M_; char* B_ = nullptr; size_t L_ = 0; }; #endif #if defined(_glibc_) || defined(_cygwin_) // glibc does not have fgetln using TGetLine = TGetLineBase; #else struct TGetLine: public TGetLineBase { size_t DoReadTo(TString& st, char ch) override { if (ch == '\n') { size_t len = 0; auto r = fgetln(F_, &len); if (r) { st.AssignNoAlias(r, len); if (st && st.back() == '\n') { st.pop_back(); } return len; } } return TGetLineBase::DoReadTo(st, ch); } }; #endif #endif } // namespace IInputStream& NPrivate::StdInStream() noexcept { return *SingletonWithPriority(); } // implementation of >> operator // helper functions static inline bool IsStdDelimiter(char c) { return (c == '\0') || (c == ' ') || (c == '\r') || (c == '\n') || (c == '\t'); } static void ReadUpToDelimiter(IInputStream& i, TString& s) { char c; while (i.ReadChar(c)) { // skip delimiters if (!IsStdDelimiter(c)) { s += c; break; } } while (i.ReadChar(c) && !IsStdDelimiter(c)) { // read data (with trailing delimiter) s += c; } } // specialization for string-related stuff template <> void In(IInputStream& i, TString& s) { s.resize(0); ReadUpToDelimiter(i, s); } template <> void In(IInputStream& i, TUtf16String& w) { TString s; ReadUpToDelimiter(i, s); if (s.empty()) { w.erase(); } else { w = UTF8ToWide(s); } } // specialization for char types #define SPEC_FOR_CHAR(T) \ template <> \ void In(IInputStream & i, T & t) { \ i.ReadChar((char&)t); \ } SPEC_FOR_CHAR(char) SPEC_FOR_CHAR(unsigned char) SPEC_FOR_CHAR(signed char) #undef SPEC_FOR_CHAR // specialization for number types #define SPEC_FOR_NUMBER(T) \ template <> \ void In(IInputStream & i, T & t) { \ char buf[128]; \ size_t pos = 0; \ while (i.ReadChar(buf[0])) { \ if (!IsStdDelimiter(buf[0])) { \ ++pos; \ break; \ } \ } \ while (i.ReadChar(buf[pos]) && !IsStdDelimiter(buf[pos]) && pos < 127) { \ ++pos; \ } \ t = FromString(buf, pos); \ } SPEC_FOR_NUMBER(signed short) SPEC_FOR_NUMBER(signed int) SPEC_FOR_NUMBER(signed long int) SPEC_FOR_NUMBER(signed long long int) SPEC_FOR_NUMBER(unsigned short) SPEC_FOR_NUMBER(unsigned int) SPEC_FOR_NUMBER(unsigned long int) SPEC_FOR_NUMBER(unsigned long long int) SPEC_FOR_NUMBER(float) SPEC_FOR_NUMBER(double) SPEC_FOR_NUMBER(long double) #undef SPEC_FOR_NUMBER