00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "stdmisc.h"
00027
00028 #include "nel/misc/time_nl.h"
00029
00030 #include "nel/misc/buf_fifo.h"
00031
00032 using namespace std;
00033
00034 #define DEBUG_FIFO 0
00035
00036 namespace NLMISC {
00037
00038
00039 CBufFIFO::CBufFIFO() : _Buffer(NULL), _BufferSize(0), _Empty(true), _Head(NULL), _Tail(NULL), _Rewinder(NULL)
00040 {
00041
00042 _BiggestBlock = 0;
00043 _SmallestBlock = 999999999;
00044 _BiggestBuffer = 0;
00045 _SmallestBuffer = 999999999;
00046 _Pushed = 0;
00047 _Fronted = 0;
00048 _Resized = 0;
00049 _PushedTime = 0;
00050 _FrontedTime = 0;
00051 _ResizedTime = 0;
00052 }
00053
00054 CBufFIFO::~CBufFIFO()
00055 {
00056 if (_Buffer != NULL)
00057 {
00058 delete _Buffer;
00059 #if DEBUG_FIFO
00060 nldebug("%p delete", this);
00061 #endif
00062 }
00063 }
00064
00065 void CBufFIFO::push (const uint8 *buffer, uint32 size)
00066 {
00067
00068
00069
00070 TTicks before = CTime::getPerformanceTime();
00071
00072 #if DEBUG_FIFO
00073 nldebug("%p push(%d)", this, size);
00074 #endif
00075
00076 nlassert(size > 0 && size < pow(2, sizeof(TFifoSize)*8));
00077
00078
00079 if (size > _BiggestBlock) _BiggestBlock = size;
00080 if (size < _SmallestBlock) _SmallestBlock = size;
00081 _Pushed++;
00082
00083 while (!canFit (size + sizeof (TFifoSize)))
00084 {
00085 resize(_BufferSize * 2);
00086 }
00087
00088 *(TFifoSize *)_Head = size;
00089 _Head += sizeof(TFifoSize);
00090
00091 CFastMem::memcpy(_Head, buffer, size);
00092
00093 _Head += size;
00094
00095 _Empty = false;
00096
00097
00098 TTicks after = CTime::getPerformanceTime();
00099 _PushedTime += after - before;
00100
00101 #if DEBUG_FIFO
00102 display ();
00103 #endif
00104 }
00105
00106 void CBufFIFO::push(const std::vector<uint8> &buffer1, const std::vector<uint8> &buffer2)
00107 {
00108 TTicks before = CTime::getPerformanceTime();
00109
00110 TFifoSize size = buffer1.size() + buffer2.size ();
00111
00112 #if DEBUG_FIFO
00113 nldebug("%p push2(%d)", this, size);
00114 #endif
00115
00116 nlassert((buffer1.size() + buffer2.size ()) > 0 && (buffer1.size() + buffer2.size ()) < pow(2, sizeof(TFifoSize)*8));
00117
00118
00119 if (this->size() > 10000000)
00120 {
00121 throw Exception ("CBufFIFO::push(): stack full (more than 10mb)");
00122 }
00123
00124
00125
00126 if (size > _BiggestBlock) _BiggestBlock = size;
00127 if (size < _SmallestBlock) _SmallestBlock = size;
00128
00129 _Pushed++;
00130
00131
00132 while (!canFit (size + sizeof (TFifoSize)))
00133 {
00134 resize(_BufferSize * 2);
00135 }
00136
00137
00138 *(TFifoSize *)_Head = size;
00139 _Head += sizeof(TFifoSize);
00140
00141
00142 CFastMem::memcpy(_Head, &(buffer1[0]), buffer1.size ());
00143 CFastMem::memcpy(_Head + buffer1.size(), &(buffer2[0]), buffer2.size ());
00144 _Head += size;
00145
00146 _Empty = false;
00147
00148
00149 TTicks after = CTime::getPerformanceTime();
00150 _PushedTime += after - before;
00151
00152 #if DEBUG_FIFO
00153 display ();
00154 #endif
00155 }
00156
00157 void CBufFIFO::pop ()
00158 {
00159 if (empty ())
00160 {
00161 nlwarning("Try to pop an empty fifo!");
00162 return;
00163 }
00164
00165 if (_Rewinder != NULL && _Tail == _Rewinder)
00166 {
00167 #if DEBUG_FIFO
00168 nldebug("%p pop rewind!", this);
00169 #endif
00170
00171
00172 _Tail = _Buffer;
00173 _Rewinder = NULL;
00174 }
00175
00176 TFifoSize size = *(TFifoSize *)_Tail;
00177
00178 #if DEBUG_FIFO
00179 nldebug("%p pop(%d)", this, size);
00180 #endif
00181
00182 #ifdef NL_DEBUG
00183
00184 memset (_Tail, '-', size + sizeof (TFifoSize));
00185 #endif
00186
00187 _Tail += size + sizeof (TFifoSize);
00188
00189 if (_Tail == _Head) _Empty = true;
00190
00191 #if DEBUG_FIFO
00192 display ();
00193 #endif
00194 }
00195
00196 uint8 CBufFIFO::frontLast ()
00197 {
00198 uint8 *tail = _Tail;
00199
00200 if (empty ())
00201 {
00202 nlwarning("Try to get the front of an empty fifo!");
00203 return 0;
00204 }
00205
00206 if (_Rewinder != NULL && tail == _Rewinder)
00207 {
00208 #if DEBUG_FIFO
00209 nldebug("%p front rewind!", this);
00210 #endif
00211
00212
00213 tail = _Buffer;
00214 }
00215
00216 TFifoSize size = *(TFifoSize *)tail;
00217
00218 #if DEBUG_FIFO
00219 nldebug("%p frontLast() returns %d ", this, size, *(tail+sizeof(TFifoSize)+size-1));
00220 #endif
00221
00222 return *(tail+sizeof(TFifoSize)+size-1);
00223 }
00224
00225
00226 void CBufFIFO::front (vector<uint8> &buffer)
00227 {
00228 uint8 *tmpbuffer;
00229 uint32 size;
00230
00231 buffer.clear ();
00232
00233 front (tmpbuffer, size);
00234
00235 buffer.resize (size);
00236
00237 CFastMem::memcpy (&(buffer[0]), tmpbuffer, size);
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282 }
00283
00284
00285 void CBufFIFO::front (NLMISC::CMemStream &buffer)
00286 {
00287 uint8 *tmpbuffer;
00288 uint32 size;
00289
00290 buffer.clear ();
00291
00292 front (tmpbuffer, size);
00293
00294 buffer.fill (tmpbuffer, size);
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341 }
00342
00343 void CBufFIFO::front (uint8 *&buffer, uint32 &size)
00344 {
00345 TTicks before = CTime::getPerformanceTime ();
00346
00347 uint8 *tail = _Tail;
00348
00349 if (empty ())
00350 {
00351 nlwarning("Try to get the front of an empty fifo!");
00352 return;
00353 }
00354
00355 _Fronted++;
00356
00357 if (_Rewinder != NULL && tail == _Rewinder)
00358 {
00359 #if DEBUG_FIFO
00360 nldebug("%p front rewind!", this);
00361 #endif
00362
00363
00364 tail = _Buffer;
00365 }
00366
00367 size = *(TFifoSize *)tail;
00368
00369 #if DEBUG_FIFO
00370 nldebug("%p front(%d)", this, size);
00371 #endif
00372
00373 tail += sizeof (TFifoSize);
00374
00375
00376 TTicks after = CTime::getPerformanceTime ();
00377 _FrontedTime += after - before;
00378
00379 #if DEBUG_FIFO
00380 display ();
00381 #endif
00382
00383 buffer = tail;
00384 }
00385
00386
00387
00388 void CBufFIFO::clear ()
00389 {
00390 _Tail = _Head = _Buffer;
00391 _Rewinder = NULL;
00392 _Empty = true;
00393 }
00394
00395 uint32 CBufFIFO::size ()
00396 {
00397 if (empty ())
00398 {
00399 return 0;
00400 }
00401 else if (_Head == _Tail)
00402 {
00403
00404 if (_Rewinder == NULL)
00405 return _BufferSize;
00406 else
00407 return _Rewinder - _Buffer;
00408 }
00409 else if (_Head > _Tail)
00410 {
00411 return _Head - _Tail;
00412 }
00413 else if (_Head < _Tail)
00414 {
00415 nlassert (_Rewinder != NULL);
00416 return (_Rewinder - _Tail) + (_Head - _Buffer);
00417 }
00418 nlstop;
00419 return 0;
00420 }
00421
00422 void CBufFIFO::resize (uint32 size)
00423 {
00424 TTicks before = CTime::getPerformanceTime();
00425
00426 if (size == 0) size = 100;
00427
00428 #if DEBUG_FIFO
00429 nldebug("%p resize(%d)", this, size);
00430 #endif
00431
00432 if (size > _BiggestBuffer) _BiggestBuffer = size;
00433 if (size < _SmallestBuffer) _SmallestBuffer = size;
00434
00435 _Resized++;
00436
00437 uint32 UsedSize = CBufFIFO::size();
00438
00439
00440 if (size < _BufferSize && UsedSize > size)
00441 {
00442
00443 nlwarning("Can't resize the FIFO because there's not enough room in the new wanted buffer (%d bytes needed at least)", UsedSize);
00444 return;
00445 }
00446
00447 uint8 *NewBuffer = new uint8[size];
00448 if (NewBuffer == NULL)
00449 {
00450 nlerror("Not enough memory to resize the FIFO to %u bytes", size);
00451 }
00452 #ifdef NL_DEBUG
00453
00454 memset (NewBuffer, '-', size);
00455 #endif
00456
00457 #if DEBUG_FIFO
00458 nldebug("%p new %d bytes", this, size);
00459 #endif
00460
00461
00462
00463 if (!empty())
00464 {
00465 if (_Tail < _Head)
00466 {
00467 CFastMem::memcpy (NewBuffer, _Tail, UsedSize);
00468 }
00469 else if (_Tail >= _Head)
00470 {
00471 nlassert (_Rewinder != NULL);
00472
00473 uint size1 = _Rewinder - _Tail;
00474 CFastMem::memcpy (NewBuffer, _Tail, size1);
00475 uint size2 = _Head - _Buffer;
00476 CFastMem::memcpy (NewBuffer + size1, _Buffer, size2);
00477
00478 nlassert (size1+size2==UsedSize);
00479 }
00480 }
00481
00482
00483
00484 _Tail = NewBuffer;
00485 _Head = NewBuffer + UsedSize;
00486 _Rewinder = NULL;
00487
00488
00489 if (_Buffer != NULL)
00490 {
00491 delete _Buffer;
00492 #if DEBUG_FIFO
00493 nldebug ("delete", this);
00494 #endif
00495 }
00496
00497
00498 _Buffer = NewBuffer;
00499 _BufferSize = size;
00500
00501 TTicks after = CTime::getPerformanceTime();
00502
00503 _ResizedTime += after - before;
00504
00505 #if DEBUG_FIFO
00506 display ();
00507 #endif
00508 }
00509
00510 void CBufFIFO::displayStats ()
00511 {
00512 nlinfo ("%p _BiggestBlock: %d", this, _BiggestBlock);
00513 nlinfo ("%p _SmallestBlock: %d", this, _SmallestBlock);
00514 nlinfo ("%p _BiggestBuffer: %d", this, _BiggestBuffer);
00515 nlinfo ("%p _SmallestBuffer: %d", this, _SmallestBuffer);
00516 nlinfo ("%p _Pushed : %d", this, _Pushed);
00517 nlinfo ("%p _Fronted: %d", this, _Fronted);
00518 nlinfo ("%p _Resized: %d", this, _Resized);
00519 nlinfo ("%p _PushedTime: %"NL_I64"d %f", this, _PushedTime, (double)(sint64)_PushedTime / (double)_Pushed);
00520 nlinfo ("%p _FrontedTime: %"NL_I64"d %f", this, _FrontedTime, (double)(sint64)_FrontedTime / (double)_Fronted);
00521 nlinfo ("%p _ResizedTime: %"NL_I64"d %f", this, _ResizedTime, (double)(sint64)_ResizedTime / (double)_Resized);
00522 }
00523
00524 void CBufFIFO::display ()
00525 {
00526 int size = 64;
00527 int gran = size/30;
00528
00529 char str[1024];
00530
00531 smprintf(str, 1024, "%p %p (%5d %5d) %p %p %p ", this, _Buffer, _BufferSize, CBufFIFO::size(), _Rewinder, _Tail, _Head);
00532
00533 int i;
00534 for (i = 0; i < (sint32) _BufferSize; i+= gran)
00535 {
00536 uint8 *pos = _Buffer + i;
00537 if (_Tail >= pos && _Tail < pos + gran)
00538 {
00539 if (_Head >= pos && _Head < pos + gran)
00540 {
00541 if (_Rewinder != NULL && _Rewinder >= pos && _Rewinder < pos + gran)
00542 {
00543 strncat (str, "*", 1024);
00544 }
00545 else
00546 {
00547 strncat (str, "@", 1024);
00548 }
00549 }
00550 else
00551 {
00552 strncat (str, "T", 1024);
00553 }
00554 }
00555 else if (_Head >= pos && _Head < pos + gran)
00556 {
00557 strncat (str, "H", 1024);
00558 }
00559 else if (_Rewinder != NULL && _Rewinder >= pos && _Rewinder < pos + gran)
00560 {
00561 strncat (str, "R", 1024);
00562 }
00563 else
00564 {
00565 if (strlen(str) < 1023)
00566 {
00567 uint32 p = strlen(str);
00568 if (isprint(*pos))
00569 str[p] = *pos;
00570 else
00571 str[p] = '$';
00572
00573 str[p+1] = '\0';
00574 }
00575 }
00576 }
00577
00578 for (; i < size; i+= gran)
00579 {
00580 strncat (str, " ", 1024);
00581 }
00582 #ifdef NL_DEBUG
00583 strncat (str, "\n", 1024);
00584 #else
00585 strncat (str, "\r", 1024);
00586 #endif
00587 DebugLog->display (str);
00588 }
00589
00590 bool CBufFIFO::canFit (uint32 size)
00591 {
00592 if (_Tail == _Head)
00593 {
00594 if (empty())
00595 {
00596
00597 if (_BufferSize >= size)
00598 {
00599
00600 #if DEBUG_FIFO
00601 nldebug("%p reset tail and head", this);
00602 #endif
00603 _Head = _Tail = _Buffer;
00604 return true;
00605 }
00606 else
00607 {
00608
00609 #if DEBUG_FIFO
00610 nldebug("%p buffer full buffersize<size", this);
00611 #endif
00612 return false;
00613 }
00614 }
00615 else
00616 {
00617
00618 #if DEBUG_FIFO
00619 nldebug("%p buffer full h=t", this);
00620 #endif
00621 return false;
00622 }
00623 }
00624 else if (_Tail < _Head)
00625 {
00626 if (_Buffer + _BufferSize - _Head >= (sint32) size)
00627 {
00628
00629 #if DEBUG_FIFO
00630 nldebug("%p fit after", this);
00631 #endif
00632 return true;
00633 }
00634 else if (_Tail - _Buffer >= (sint32) size)
00635 {
00636
00637 #if DEBUG_FIFO
00638 nldebug("%p fit at beginning", this);
00639 #endif
00640 _Rewinder = _Head;
00641 #if DEBUG_FIFO
00642 nldebug("%p set the rewinder", this);
00643 #endif
00644 _Head = _Buffer;
00645 return true;
00646 }
00647 else
00648 {
00649
00650 #if DEBUG_FIFO
00651 nldebug("%p no room t<h", this);
00652 #endif
00653 return false;
00654 }
00655 }
00656 else
00657 {
00658 if (_Tail - _Head >= (sint32) size)
00659 {
00660 #if DEBUG_FIFO
00661 nldebug("%p fit t>h", this);
00662 #endif
00663 return true;
00664 }
00665 else
00666 {
00667 #if DEBUG_FIFO
00668 nldebug("%p no room t>h", this);
00669 #endif
00670 return false;
00671 }
00672 }
00673 nlstop;
00674 }
00675
00676
00677 }