diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /util/stream/input.cpp | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'util/stream/input.cpp')
-rw-r--r-- | util/stream/input.cpp | 344 |
1 files changed, 344 insertions, 0 deletions
diff --git a/util/stream/input.cpp b/util/stream/input.cpp new file mode 100644 index 0000000000..6e8170f2f9 --- /dev/null +++ b/util/stream/input.cpp @@ -0,0 +1,344 @@ +#include "input.h" +#include "output.h" +#include "str.h" + +#include <util/charset/wide.h> +#include <util/memory/tempbuf.h> +#include <util/generic/string.h> +#include <util/generic/yexception.h> +#include <util/generic/singleton.h> +#include <util/string/cast.h> +#include <util/system/compat.h> +#include <util/system/spinlock.h> + +#include <cstdlib> + +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<size_t>(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 +} + +IInputStream& NPrivate::StdInStream() noexcept { + return *SingletonWithPriority<TGetLine, 4>(); +} + +// 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<TString>(IInputStream& i, TString& s) { + s.resize(0); + ReadUpToDelimiter(i, s); +} + +template <> +void In<TUtf16String>(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<T>(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<T>(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<T, char>(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 |