#pragma once #include #include #include #include struct IBinaryStream { virtual ~IBinaryStream() = default; inline i64 Write(const void* userBuffer, i64 size) { if (size <= Max()) { return WriteImpl(userBuffer, static_cast(size)); } else { return LongWrite(userBuffer, size); } } inline i64 Read(void* userBuffer, i64 size) { if (size <= Max()) { return ReadImpl(userBuffer, static_cast(size)); } else { return LongRead(userBuffer, size); } } virtual bool IsValid() const = 0; virtual bool IsFailed() const = 0; private: virtual int WriteImpl(const void* userBuffer, int size) = 0; virtual int ReadImpl(void* userBuffer, int size) = 0; i64 LongRead(void* userBuffer, i64 size); i64 LongWrite(const void* userBuffer, i64 size); }; template class TBufferedStream { char Buf[N_SIZE]; i64 Pos, BufSize; IBinaryStream& Stream; bool bIsReading, bIsEof, bFailed; void ReadComplex(void* userBuffer, i64 size) { if (bIsEof) { memset(userBuffer, 0, size); return; } char* dst = (char*)userBuffer; i64 leftBytes = BufSize - Pos; memcpy(dst, Buf + Pos, leftBytes); dst += leftBytes; size -= leftBytes; Pos = BufSize = 0; if (size > N_SIZE) { i64 n = Stream.Read(dst, size); bFailed = Stream.IsFailed(); if (n != size) { bIsEof = true; memset(dst + n, 0, size - n); } } else { BufSize = Stream.Read(Buf, N_SIZE); bFailed = Stream.IsFailed(); if (BufSize == 0) bIsEof = true; Read(dst, size); } } void WriteComplex(const void* userBuffer, i64 size) { Flush(); if (size >= N_SIZE) { Stream.Write(userBuffer, size); bFailed = Stream.IsFailed(); } else Write(userBuffer, size); } void operator=(const TBufferedStream&) { } public: TBufferedStream(bool bRead, IBinaryStream& stream) : Pos(0) , BufSize(0) , Stream(stream) , bIsReading(bRead) , bIsEof(false) , bFailed(false) { } ~TBufferedStream() { if (!bIsReading) Flush(); } void Flush() { Y_ASSERT(!bIsReading); if (bIsReading) return; Stream.Write(Buf, Pos); bFailed = Stream.IsFailed(); Pos = 0; } bool IsEof() const { return bIsEof; } inline void Read(void* userBuffer, i64 size) { Y_ASSERT(bIsReading); if (!bIsEof && size + Pos <= BufSize) { memcpy(userBuffer, Buf + Pos, size); Pos += size; return; } ReadComplex(userBuffer, size); } inline void Write(const void* userBuffer, i64 size) { Y_ASSERT(!bIsReading); if (Pos + size < N_SIZE) { memcpy(Buf + Pos, userBuffer, size); Pos += size; return; } WriteComplex(userBuffer, size); } bool IsValid() const { return Stream.IsValid(); } bool IsFailed() const { return bFailed; } };