libzypp 17.37.17
iobuffer.cc
Go to the documentation of this file.
2#include <cstring>
3#include <cassert>
4
5namespace zyppng {
6
7 enum {
9 };
10
11 IOBuffer::IOBuffer( int64_t chunkSize ) : _defaultChunkSize ( chunkSize == 0 ? DefChunkSize : chunkSize )
12 { }
13
14 char *IOBuffer::reserve( int64_t bytes )
15 {
16 assert( bytes > 0 && size_t(bytes) < ByteArray::maxSize() );
17 // do we need a new chunk?
18 if ( _chunks.size() ) {
19 auto &back = _chunks.back();
20 if ( back.available() >= bytes ) {
21 char * ptr = back._buffer.data() + back.tail;
22 back.tail += bytes;
23 return ptr;
24 }
25 }
26
27 // not enough space ready allocate a new one
28 _chunks.push_back( Chunk{} );
29 auto &back = _chunks.back();
30 back._buffer.insert( back._buffer.end(), std::max<int64_t>( _defaultChunkSize, bytes ), '\0' );
31 back.tail += bytes;
32 return back.data();
33 }
34
36 {
37 if ( frontSize() == 0 )
38 return nullptr;
39
40 return _chunks.front().data();
41 }
42
43 int64_t IOBuffer::frontSize() const
44 {
45 if ( _chunks.empty() )
46 return 0;
47 return _chunks.front().len();
48 }
49
51 {
52 _chunks.clear();
53 }
54
55 int64_t IOBuffer::discard( int64_t bytes )
56 {
57 const int64_t bytesToDiscard = std::min(bytes, size());
58 if ( bytesToDiscard == size() ) {
59 clear();
60 return bytesToDiscard;
61 }
62
63 int64_t discardedSoFar = 0;
64
65 // since the chunks might not be used completely we need to iterate over them
66 // counting how much used bytes we actually discard until we hit the requested amount
67 while ( discardedSoFar < bytesToDiscard ) {
68 auto &chunk = _chunks.front();
69 const auto bytesInChunk = chunk.len();
70
71 if ( discardedSoFar + bytesInChunk > bytesToDiscard ) {
72 chunk.head += ( bytesToDiscard - discardedSoFar );
73 discardedSoFar = bytesToDiscard;
74 } else {
75 _chunks.erase( _chunks.begin() );
76 discardedSoFar += bytesInChunk;
77 }
78 }
79
80
81 return bytesToDiscard;
82 }
83
87 void IOBuffer::chop( int64_t bytes )
88 {
89 if ( bytes == 0 )
90 return;
91
92 bytes = std::min( bytes, size() );
93 if ( bytes == size() ) {
94 clear();
95 return;
96 }
97
98 int64_t choppedSoFar = 0;
99 while ( choppedSoFar < bytes && _chunks.size() ) {
100 auto bytesStillToChop = bytes - choppedSoFar;
101 auto &chunk = _chunks.back();
102
103 if ( chunk.len() > bytesStillToChop ) {
104 chunk.tail -= bytesStillToChop;
105 break;
106 } else {
107 choppedSoFar += chunk.len();
108 _chunks.pop_back();
109 }
110 }
111 }
112
113 void IOBuffer::append(const char *data, int64_t count)
114 {
115 if ( count <= 0 )
116 return;
117
118 assert( count > 0 && size_t(count) < ByteArray::maxSize() );
119
120 char *buf = reserve( count );
121 if ( count == 1 )
122 *buf = *data;
123 else {
124 ::memcpy( buf, data, count );
125 }
126 }
127
128 void IOBuffer::append(const ByteArray &data)
129 {
130 append( data.data(), data.size() );
131 }
132
133 int64_t IOBuffer::read( char *buffer, int64_t max )
134 {
135 const size_t bytesToRead = std::min( size(), max );
136 size_t readSoFar = 0;
137
138 while ( readSoFar < bytesToRead && _chunks.size() ) {
139
140 auto &chunk = _chunks.front();
141 const auto toRead = std::min<size_t>( bytesToRead - readSoFar, chunk.len() );
142 ::memcpy( buffer+readSoFar, chunk.data(), toRead );
143 readSoFar += toRead;
144
145 // if we consumed all data in the chunk discard it
146 chunk.head += toRead;
147 if( chunk.head >= chunk.tail )
148 _chunks.erase( _chunks.begin() );
149 }
150
151 return readSoFar;
152 }
153
154 int64_t IOBuffer::size() const
155 {
156 int64_t s = 0;
157 for ( const auto &c : _chunks )
158 s+= c.len();
159 return s;
160 }
161
162 std::vector<IOBuffer::Chunk>::size_type IOBuffer::chunks() const
163 {
164 return _chunks.size();
165 }
166
167 int64_t IOBuffer::indexOf(const char c, int64_t maxCount, int64_t pos ) const
168 {
169 if ( maxCount == 0 )
170 return -1;
171
172 maxCount = std::min<size_t>( maxCount, size() );
173
174 int64_t scannedSoFar = 0;
175 for ( const auto &chunk : _chunks ) {
176
177 //as long as pos is still after the current chunk just increase the count
178 if ( scannedSoFar+chunk.len() - 1 < pos ) {
179 scannedSoFar += chunk.len();
180 continue;
181 }
182
183 const char * const chunkBegin = chunk.data();
184 const char *s = chunkBegin;
185
186 size_t lengthToScan = std::min<size_t>( chunk.len() , maxCount - scannedSoFar );
187 if ( pos > 0 && scannedSoFar < pos ) {
188 const auto adjust = (pos-scannedSoFar);
189 s += adjust;
190 lengthToScan -= adjust;
191 }
192
193 const char *ptr = reinterpret_cast<const char*>(::memchr( s, c, lengthToScan ));
194 if ( ptr ) {
195 return ( ( ptr - chunkBegin ) + scannedSoFar );
196 }
197
198 scannedSoFar += chunk.len();
199 if ( scannedSoFar >= maxCount )
200 break;
201 }
202 return -1;
203 }
204
205 ByteArray IOBuffer::readUntil(const char delim, const int64_t max)
206 {
207 assert( ( max >= 2 || max == 0 ) && size_t(max) <= ByteArray::maxSize() );
208
209 const auto idx = indexOf( delim, max == 0 ? size() : max );
210 if ( idx == -1 )
211 return {};
212
213 zyppng::ByteArray b( idx+1, '\0' );
214 read( b.data(), idx+1 );
215 return b;
216 }
217
218 int64_t IOBuffer::readUntil(char *buffer, const char delim, int64_t max)
219 {
220 assert( buffer != nullptr && max > 1 );
221 const auto maxRead = max - 1;
222 const auto idx = indexOf( delim, maxRead );
223 const auto bytesRead = read( buffer, idx == -1 ? maxRead : idx + 1 );
224 buffer[bytesRead] = '\0';
225 return bytesRead;
226 }
227
228 ByteArray IOBuffer::readLine( const int64_t max )
229 {
230 return readUntil( '\n', max );
231 }
232
233 int64_t IOBuffer::readLine( char *buffer, int64_t max )
234 {
235 return readUntil( buffer, '\n', max );
236 }
237
238 bool IOBuffer::canReadUntil(const char delim) const
239 {
240 return indexOf(delim) >= 0;
241 }
242
244 {
245 return canReadUntil('\n');
246 }
247
248}
static std::size_t maxSize()
Definition ByteArray.h:38
std::vector< Chunk > _chunks
Definition iobuffer_p.h:59
ByteArray readUntil(const char delim, const int64_t max=0)
Definition iobuffer.cc:205
bool canReadUntil(const char delim) const
Definition iobuffer.cc:238
bool canReadLine() const
Definition iobuffer.cc:243
int64_t _defaultChunkSize
Definition iobuffer_p.h:58
ByteArray readLine(const int64_t max=0)
Definition iobuffer.cc:228
void chop(int64_t bytes)
Definition iobuffer.cc:87
int64_t size() const
Definition iobuffer.cc:154
char * front()
Definition iobuffer.cc:35
std::vector< Chunk >::size_type chunks() const
Definition iobuffer.cc:162
int64_t read(char *buffer, int64_t max)
Definition iobuffer.cc:133
void append(const char *data, int64_t count)
Definition iobuffer.cc:113
int64_t indexOf(const char c) const
Definition iobuffer_p.h:48
char * reserve(int64_t bytes)
Definition iobuffer.cc:14
IOBuffer(int64_t chunkSize=0)
Definition iobuffer.cc:11
int64_t discard(int64_t bytes)
Definition iobuffer.cc:55
int64_t frontSize() const
Definition iobuffer.cc:43
unsigned short b
@ DefChunkSize
Definition iobuffer.cc:8