libzypp  17.35.15
iobuffer.cc
Go to the documentation of this file.
1 #include "private/iobuffer_p.h"
2 #include <cstring>
3 #include <cassert>
4 
5 namespace zyppng {
6 
7  enum {
8  DefChunkSize = 4096
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 
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 }
IOBuffer(int64_t chunkSize=0)
Definition: iobuffer.cc:11
int64_t indexOf(const char c) const
Definition: iobuffer_p.h:48
unsigned short b
ByteArray readLine(const int64_t max=0)
Definition: iobuffer.cc:228
char * front()
Definition: iobuffer.cc:35
int64_t size() const
Definition: iobuffer.cc:154
void append(const char *data, int64_t count)
Definition: iobuffer.cc:113
static std::size_t maxSize()
Definition: ByteArray.h:38
int64_t discard(int64_t bytes)
Definition: iobuffer.cc:55
int64_t frontSize() const
Definition: iobuffer.cc:43
int64_t _defaultChunkSize
Definition: iobuffer_p.h:58
bool canReadLine() const
Definition: iobuffer.cc:243
bool canReadUntil(const char delim) const
Definition: iobuffer.cc:238
std::vector< Chunk > _chunks
Definition: iobuffer_p.h:59
void chop(int64_t bytes)
Definition: iobuffer.cc:87
int64_t read(char *buffer, int64_t max)
Definition: iobuffer.cc:133
ByteArray readUntil(const char delim, const int64_t max=0)
Definition: iobuffer.cc:205
SolvableIdType size_type
Definition: PoolMember.h:126
char * reserve(int64_t bytes)
Definition: iobuffer.cc:14
std::vector< Chunk >::size_type chunks() const
Definition: iobuffer.cc:162