1#pragma once
2
3#include <Core/Defines.h>
4#include <algorithm>
5
6
7namespace DB
8{
9
10
11/** Base class for ReadBuffer and WriteBuffer.
12 * Contains common types, variables, and functions.
13 *
14 * ReadBuffer and WriteBuffer are similar to istream and ostream, respectively.
15 * They have to be used, because using iostreams it is impossible to effectively implement some operations.
16 * For example, using istream, you can not quickly read string values from a tab-separated file,
17 * so that after reading, the position remains immediately after the read value.
18 * (The only option is to call the std::istream::get() function on each byte, but this slows down due to several virtual calls.)
19 *
20 * Read/WriteBuffers provide direct access to the internal buffer, so the necessary operations are implemented more efficiently.
21 * Only one virtual function nextImpl() is used, which is rarely called:
22 * - in the case of ReadBuffer - fill in the buffer with new data from the source;
23 * - in the case of WriteBuffer - write data from the buffer into the receiver.
24 *
25 * Read/WriteBuffer can own or not own an own piece of memory.
26 * In the second case, you can effectively read from an already existing piece of memory / std::string without copying it.
27 */
28class BufferBase
29{
30public:
31 /** Cursor in the buffer. The position of write or read. */
32 using Position = char *;
33
34 /** A reference to the range of memory. */
35 struct Buffer
36 {
37 Buffer(Position begin_pos_, Position end_pos_) : begin_pos(begin_pos_), end_pos(end_pos_) {}
38
39 inline Position begin() const { return begin_pos; }
40 inline Position end() const { return end_pos; }
41 inline size_t size() const { return size_t(end_pos - begin_pos); }
42 inline void resize(size_t size) { end_pos = begin_pos + size; }
43
44 inline void swap(Buffer & other)
45 {
46 std::swap(begin_pos, other.begin_pos);
47 std::swap(end_pos, other.end_pos);
48 }
49
50 private:
51 Position begin_pos;
52 Position end_pos; /// 1 byte after the end of the buffer
53 };
54
55 /** The constructor takes a range of memory to use for the buffer.
56 * offset - the starting point of the cursor. ReadBuffer must set it to the end of the range, and WriteBuffer - to the beginning.
57 */
58 BufferBase(Position ptr, size_t size, size_t offset)
59 : pos(ptr + offset), working_buffer(ptr, ptr + size), internal_buffer(ptr, ptr + size) {}
60
61 void set(Position ptr, size_t size, size_t offset)
62 {
63 internal_buffer = Buffer(ptr, ptr + size);
64 working_buffer = Buffer(ptr, ptr + size);
65 pos = ptr + offset;
66 }
67
68 /// get buffer
69 inline Buffer & internalBuffer() { return internal_buffer; }
70
71 /// get the part of the buffer from which you can read / write data
72 inline Buffer & buffer() { return working_buffer; }
73
74 /// get (for reading and modifying) the position in the buffer
75 inline Position & position() { return pos; }
76
77 /// offset in bytes of the cursor from the beginning of the buffer
78 inline size_t offset() const { return size_t(pos - working_buffer.begin()); }
79
80 /// How many bytes are available for read/write
81 inline size_t available() const { return size_t(working_buffer.end() - pos); }
82
83 inline void swap(BufferBase & other)
84 {
85 internal_buffer.swap(other.internal_buffer);
86 working_buffer.swap(other.working_buffer);
87 std::swap(pos, other.pos);
88 }
89
90 /** How many bytes have been read/written, counting those that are still in the buffer. */
91 size_t count() const { return bytes + offset(); }
92
93 /** Check that there is more bytes in buffer after cursor. */
94 bool ALWAYS_INLINE hasPendingData() const { return available() > 0; }
95
96 bool isPadded() const { return padded; }
97
98protected:
99 /// Read/write position.
100 Position pos;
101
102 /** How many bytes have been read/written, not counting those that are now in the buffer.
103 * (counting those that were already used and "removed" from the buffer)
104 */
105 size_t bytes = 0;
106
107 /** A piece of memory that you can use.
108 * For example, if internal_buffer is 1MB, and from a file for reading it was loaded into the buffer
109 * only 10 bytes, then working_buffer will be 10 bytes in size
110 * (working_buffer.end() will point to the position immediately after the 10 bytes that can be read).
111 */
112 Buffer working_buffer;
113
114 /// A reference to a piece of memory for the buffer.
115 Buffer internal_buffer;
116
117 /// Indicator of 15 bytes pad_right
118 bool padded{false};
119};
120
121
122}
123