#pragma once #include #include #include #include #include #include namespace DB { namespace ErrorCodes { extern const int CANNOT_WRITE_AFTER_END_OF_BUFFER; } /** A simple abstract class for buffered data writing (char sequences) somewhere. * Unlike std::ostream, it provides access to the internal buffer, * and also allows you to manually manage the position inside the buffer. * * The successors must implement the nextImpl() method. */ class WriteBuffer : public BufferBase { public: WriteBuffer(Position ptr, size_t size) : BufferBase(ptr, size, 0) {} void set(Position ptr, size_t size) { BufferBase::set(ptr, size, 0); } /** write the data in the buffer (from the beginning of the buffer to the current position); * set the position to the beginning; throw an exception, if something is wrong */ inline void next() { if (!offset()) return; bytes += offset(); try { nextImpl(); } catch (...) { /** If the nextImpl() call was unsuccessful, move the cursor to the beginning, * so that later (for example, when the stack was expanded) there was no second attempt to write data. */ pos = working_buffer.begin(); throw; } pos = working_buffer.begin(); } /** it is desirable in the successors to place the next() call in the destructor, * so that the last data is written */ virtual ~WriteBuffer() {} inline void nextIfAtEnd() { if (!hasPendingData()) next(); } void write(const char * from, size_t n) { size_t bytes_copied = 0; while (bytes_copied < n) { nextIfAtEnd(); size_t bytes_to_copy = std::min(static_cast(working_buffer.end() - pos), n - bytes_copied); std::memcpy(pos, from + bytes_copied, bytes_to_copy); pos += bytes_to_copy; bytes_copied += bytes_to_copy; } } inline void write(char x) { nextIfAtEnd(); *pos = x; ++pos; } private: /** Write the data in the buffer (from the beginning of the buffer to the current position). * Throw an exception if something is wrong. */ virtual void nextImpl() { throw Exception("Cannot write after end of buffer.", ErrorCodes::CANNOT_WRITE_AFTER_END_OF_BUFFER); } }; using WriteBufferPtr = std::shared_ptr; }