00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #ifndef LIBTORRENT_BUFFER_HPP
00033 #define LIBTORRENT_BUFFER_HPP
00034
00035
00036
00037 #include "libtorrent/invariant_check.hpp"
00038 #include <memory>
00039
00040 namespace libtorrent {
00041
00042 class buffer
00043 {
00044 public:
00045 struct interval
00046 {
00047 interval(char* begin, char* end)
00048 : begin(begin)
00049 , end(end)
00050 {}
00051
00052 char operator[](int index) const
00053 {
00054 assert(begin + index < end);
00055 return begin[index];
00056 }
00057
00058 int left() const { assert(end >= begin); return end - begin; }
00059
00060 char* begin;
00061 char* end;
00062 };
00063
00064 struct const_interval
00065 {
00066 const_interval(char const* begin, char const* end)
00067 : begin(begin)
00068 , end(end)
00069 {}
00070
00071 char operator[](int index) const
00072 {
00073 assert(begin + index < end);
00074 return begin[index];
00075 }
00076
00077 int left() const { assert(end >= begin); return end - begin; }
00078
00079 char const* begin;
00080 char const* end;
00081 };
00082
00083 typedef std::pair<const_interval, const_interval> interval_type;
00084
00085 buffer(std::size_t n = 0);
00086 ~buffer();
00087
00088 interval allocate(std::size_t n);
00089 void insert(char const* first, char const* last);
00090 void erase(std::size_t n);
00091 std::size_t size() const;
00092 std::size_t capacity() const;
00093 void reserve(std::size_t n);
00094 interval_type data() const;
00095 bool empty() const;
00096
00097 std::size_t space_left() const;
00098
00099 char const* raw_data() const
00100 {
00101 return m_first;
00102 }
00103
00104 #ifndef NDEBUG
00105 void check_invariant() const;
00106 #endif
00107
00108 private:
00109 char* m_first;
00110 char* m_last;
00111 char* m_write_cursor;
00112 char* m_read_cursor;
00113 char* m_read_end;
00114 bool m_empty;
00115 #ifdef TORRENT_BUFFER_DEBUG
00116 mutable std::vector<char> m_debug;
00117 mutable int m_pending_copy;
00118 #endif
00119 };
00120
00121 inline buffer::buffer(std::size_t n)
00122 : m_first((char*)::operator new(n))
00123 , m_last(m_first + n)
00124 , m_write_cursor(m_first)
00125 , m_read_cursor(m_first)
00126 , m_read_end(m_last)
00127 , m_empty(true)
00128 {
00129 #ifdef TORRENT_BUFFER_DEBUG
00130 m_pending_copy = 0;
00131 #endif
00132 }
00133
00134 inline buffer::~buffer()
00135 {
00136 ::operator delete (m_first);
00137 }
00138
00139 inline buffer::interval buffer::allocate(std::size_t n)
00140 {
00141 assert(m_read_cursor <= m_read_end || m_empty);
00142
00143 INVARIANT_CHECK;
00144
00145 #ifdef TORRENT_BUFFER_DEBUG
00146 if (m_pending_copy)
00147 {
00148 std::copy(m_write_cursor - m_pending_copy, m_write_cursor
00149 , m_debug.end() - m_pending_copy);
00150 m_pending_copy = 0;
00151 }
00152 m_debug.resize(m_debug.size() + n);
00153 m_pending_copy = n;
00154 #endif
00155 if (m_read_cursor < m_write_cursor || m_empty)
00156 {
00157
00158 if (m_last - m_write_cursor >= (std::ptrdiff_t)n)
00159 {
00160 interval ret(m_write_cursor, m_write_cursor + n);
00161 m_write_cursor += n;
00162 m_read_end = m_write_cursor;
00163 assert(m_read_cursor <= m_read_end);
00164 if (n) m_empty = false;
00165 return ret;
00166 }
00167
00168 if (m_read_cursor - m_first >= (std::ptrdiff_t)n)
00169 {
00170 m_read_end = m_write_cursor;
00171 interval ret(m_first, m_first + n);
00172 m_write_cursor = m_first + n;
00173 assert(m_read_cursor <= m_read_end);
00174 if (n) m_empty = false;
00175 return ret;
00176 }
00177
00178 reserve(capacity() + n - (m_last - m_write_cursor));
00179 assert(m_last - m_write_cursor >= (std::ptrdiff_t)n);
00180 interval ret(m_write_cursor, m_write_cursor + n);
00181 m_write_cursor += n;
00182 m_read_end = m_write_cursor;
00183 if (n) m_empty = false;
00184 assert(m_read_cursor <= m_read_end);
00185 return ret;
00186
00187 }
00188
00189 if (m_read_cursor - m_write_cursor >= (std::ptrdiff_t)n)
00190 {
00191 interval ret(m_write_cursor, m_write_cursor + n);
00192 m_write_cursor += n;
00193 if (n) m_empty = false;
00194 return ret;
00195 }
00196 reserve(capacity() + n - (m_read_cursor - m_write_cursor));
00197 assert(m_read_cursor - m_write_cursor >= (std::ptrdiff_t)n);
00198 interval ret(m_write_cursor, m_write_cursor + n);
00199 m_write_cursor += n;
00200 if (n) m_empty = false;
00201 return ret;
00202 }
00203
00204 inline void buffer::insert(char const* first, char const* last)
00205 {
00206 INVARIANT_CHECK;
00207
00208 std::size_t n = last - first;
00209
00210 #ifdef TORRENT_BUFFER_DEBUG
00211 if (m_pending_copy)
00212 {
00213 std::copy(m_write_cursor - m_pending_copy, m_write_cursor
00214 , m_debug.end() - m_pending_copy);
00215 m_pending_copy = 0;
00216 }
00217 m_debug.insert(m_debug.end(), first, last);
00218 #endif
00219
00220 if (space_left() < n)
00221 {
00222 reserve(capacity() + n);
00223 }
00224
00225 m_empty = false;
00226
00227 char const* end = (m_last - m_write_cursor) < (std::ptrdiff_t)n ?
00228 m_last : m_write_cursor + n;
00229
00230 std::size_t copied = end - m_write_cursor;
00231 std::memcpy(m_write_cursor, first, copied);
00232
00233 m_write_cursor += copied;
00234 if (m_write_cursor > m_read_end) m_read_end = m_write_cursor;
00235 first += copied;
00236 n -= copied;
00237
00238 if (n == 0) return;
00239
00240 assert(m_write_cursor == m_last);
00241 m_write_cursor = m_first;
00242
00243 memcpy(m_write_cursor, first, n);
00244 m_write_cursor += n;
00245 }
00246
00247 inline void buffer::erase(std::size_t n)
00248 {
00249 INVARIANT_CHECK;
00250
00251 if (n == 0) return;
00252 assert(!m_empty);
00253
00254 #ifndef NDEBUG
00255 int prev_size = size();
00256 #endif
00257 assert(m_read_cursor <= m_read_end);
00258 m_read_cursor += n;
00259 if (m_read_cursor > m_read_end)
00260 {
00261 m_read_cursor = m_first + (m_read_cursor - m_read_end);
00262 assert(m_read_cursor <= m_write_cursor);
00263 }
00264
00265 m_empty = m_read_cursor == m_write_cursor;
00266
00267 assert(prev_size - n == size());
00268
00269 #ifdef TORRENT_BUFFER_DEBUG
00270 m_debug.erase(m_debug.begin(), m_debug.begin() + n);
00271 #endif
00272 }
00273
00274 inline std::size_t buffer::size() const
00275 {
00276
00277 if (m_read_cursor < m_write_cursor)
00278 {
00279 return m_write_cursor - m_read_cursor;
00280 }
00281
00282 else
00283 {
00284 if (m_empty) return 0;
00285 return (m_write_cursor - m_first) + (m_read_end - m_read_cursor);
00286 }
00287 }
00288
00289 inline std::size_t buffer::capacity() const
00290 {
00291 return m_last - m_first;
00292 }
00293
00294 inline void buffer::reserve(std::size_t size)
00295 {
00296 std::size_t n = (std::size_t)(capacity() * 1.f);
00297 if (n < size) n = size;
00298
00299 char* buf = (char*)::operator new(n);
00300 char* old = m_first;
00301
00302 if (m_read_cursor < m_write_cursor)
00303 {
00304
00305 std::memcpy(
00306 buf + (m_read_cursor - m_first)
00307 , m_read_cursor
00308 , m_write_cursor - m_read_cursor
00309 );
00310
00311 m_write_cursor = buf + (m_write_cursor - m_first);
00312 m_read_cursor = buf + (m_read_cursor - m_first);
00313 m_read_end = m_write_cursor;
00314 m_first = buf;
00315 m_last = buf + n;
00316 }
00317 else
00318 {
00319
00320 std::size_t skip = n - (m_last - m_first);
00321
00322 std::memcpy(buf, m_first, m_write_cursor - m_first);
00323 std::memcpy(
00324 buf + (m_read_cursor - m_first) + skip
00325 , m_read_cursor
00326 , m_last - m_read_cursor
00327 );
00328
00329 m_write_cursor = buf + (m_write_cursor - m_first);
00330
00331 if (!m_empty)
00332 {
00333 m_read_cursor = buf + (m_read_cursor - m_first) + skip;
00334 m_read_end = buf + (m_read_end - m_first) + skip;
00335 }
00336 else
00337 {
00338 m_read_cursor = m_write_cursor;
00339 m_read_end = m_write_cursor;
00340 }
00341
00342 m_first = buf;
00343 m_last = buf + n;
00344 }
00345
00346 ::operator delete (old);
00347 }
00348
00349 #ifndef NDEBUG
00350 inline void buffer::check_invariant() const
00351 {
00352 assert(m_read_end >= m_read_cursor);
00353 assert(m_last >= m_read_cursor);
00354 assert(m_last >= m_write_cursor);
00355 assert(m_last >= m_first);
00356 assert(m_first <= m_read_cursor);
00357 assert(m_first <= m_write_cursor);
00358 #ifdef TORRENT_BUFFER_DEBUG
00359 int a = m_debug.size();
00360 int b = size();
00361 (void)a;
00362 (void)b;
00363 assert(m_debug.size() == size());
00364 #endif
00365 }
00366 #endif
00367
00368 inline buffer::interval_type buffer::data() const
00369 {
00370 INVARIANT_CHECK;
00371
00372 #ifdef TORRENT_BUFFER_DEBUG
00373 if (m_pending_copy)
00374 {
00375 std::copy(m_write_cursor - m_pending_copy, m_write_cursor
00376 , m_debug.end() - m_pending_copy);
00377 m_pending_copy = 0;
00378 }
00379 #endif
00380
00381
00382 if (m_read_cursor < m_write_cursor)
00383 {
00384 #ifdef TORRENT_BUFFER_DEBUG
00385 assert(m_debug.size() == size());
00386 assert(std::equal(m_debug.begin(), m_debug.end(), m_read_cursor));
00387 #endif
00388 return interval_type(
00389 const_interval(m_read_cursor, m_write_cursor)
00390 , const_interval(m_last, m_last)
00391 );
00392 }
00393
00394 else
00395 {
00396 if (m_read_cursor == m_read_end)
00397 {
00398 #ifdef TORRENT_BUFFER_DEBUG
00399 assert(m_debug.size() == size());
00400 assert(std::equal(m_debug.begin(), m_debug.end(), m_first));
00401 #endif
00402
00403 return interval_type(
00404 const_interval(m_first, m_write_cursor)
00405 , const_interval(m_last, m_last));
00406 }
00407 #ifdef TORRENT_BUFFER_DEBUG
00408 assert(m_debug.size() == size());
00409 assert(std::equal(m_debug.begin(), m_debug.begin() + (m_read_end
00410 - m_read_cursor), m_read_cursor));
00411 assert(std::equal(m_debug.begin() + (m_read_end - m_read_cursor), m_debug.end()
00412 , m_first));
00413 #endif
00414
00415 assert(m_read_cursor <= m_read_end || m_empty);
00416 return interval_type(
00417 const_interval(m_read_cursor, m_read_end)
00418 , const_interval(m_first, m_write_cursor)
00419 );
00420 }
00421 }
00422
00423 inline bool buffer::empty() const
00424 {
00425 return m_empty;
00426 }
00427
00428 inline std::size_t buffer::space_left() const
00429 {
00430 if (m_empty) return m_last - m_first;
00431
00432
00433 if (m_read_cursor < m_write_cursor)
00434 {
00435 return (m_last - m_write_cursor) + (m_read_cursor - m_first);
00436 }
00437
00438 else
00439 {
00440 return m_read_cursor - m_write_cursor;
00441 }
00442 }
00443
00444 }
00445
00446 #endif // LIBTORRENT_BUFFER_HPP
00447