# Home    # nevrax.com   
Nevrax
Nevrax.org
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
Docs
 
Documentation  
Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  

buf_fifo.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2001 Nevrax Ltd.
00008  *
00009  * This file is part of NEVRAX NEL.
00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2, or (at your option)
00013  * any later version.
00014 
00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00018  * General Public License for more details.
00019 
00020  * You should have received a copy of the GNU General Public License
00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00023  * MA 02111-1307, USA.
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         // reset statistic
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         // if the buffer is more than 1 meg, there s surely a problem, no?
00068 //      nlassert( buffer.size() < 1000000 ); // size check in debug mode
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         // stat code
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         // stat code
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         // avoid too big fifo
00119         if (this->size() > 10000000)
00120         {
00121                 throw Exception ("CBufFIFO::push(): stack full (more than 10mb)");
00122         }
00123 
00124 
00125         // stat code
00126         if (size > _BiggestBlock) _BiggestBlock = size;
00127         if (size < _SmallestBlock) _SmallestBlock = size;
00128 
00129         _Pushed++;
00130 
00131         // resize while the buffer is enough big to accept the block
00132         while (!canFit (size + sizeof (TFifoSize)))
00133         {
00134                 resize(_BufferSize * 2);
00135         }
00136 
00137         // store the size of the block
00138         *(TFifoSize *)_Head = size;
00139         _Head += sizeof(TFifoSize);
00140 
00141         // store the block itself
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         // stat code
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                 // need to rewind
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         // clear the message to be sure user doesn't use it anymore
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                 // need to rewind
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 /*      TTicks before = CTime::getPerformanceTime ();
00240 
00241         uint8   *tail = _Tail;
00242         
00243         buffer.clear ();
00244 
00245         if (empty ())
00246         {
00247                 nlwarning("Try to get the front of an empty fifo!");
00248                 return;
00249         }
00250 
00251         _Fronted++;
00252         
00253         if (_Rewinder != NULL && tail == _Rewinder)
00254         {
00255 #if DEBUG_FIFO
00256                 nldebug("%p front rewind!", this);
00257 #endif
00258 
00259                 // need to rewind
00260                 tail = _Buffer;
00261         }
00262 
00263         TFifoSize size = *(TFifoSize *)tail;
00264 
00265 #if DEBUG_FIFO
00266         nldebug("%p front(%d)", this, size);
00267 #endif
00268 
00269         tail += sizeof (TFifoSize);
00270 
00271         buffer.resize (size);
00272 
00273         CFastMem::memcpy (&(buffer[0]), tail, size);
00274 
00275         // stat code
00276         TTicks after = CTime::getPerformanceTime ();
00277         _FrontedTime += after - before;
00278 
00279 #if DEBUG_FIFO
00280         display ();
00281 #endif
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         TTicks before = CTime::getPerformanceTime ();
00298 
00299         uint8   *tail = _Tail;
00300         
00301         buffer.clear ();
00302 
00303         if (empty ())
00304         {
00305                 nlwarning("Try to get the front of an empty fifo!");
00306                 return;
00307         }
00308 
00309         _Fronted++;
00310         
00311         if (_Rewinder != NULL && tail == _Rewinder)
00312         {
00313 #if DEBUG_FIFO
00314                 nldebug("%p front rewind!", this);
00315 #endif
00316 
00317                 // need to rewind
00318                 tail = _Buffer;
00319         }
00320 
00321         TFifoSize size = *(TFifoSize *)tail;
00322 
00323 #if DEBUG_FIFO
00324         nldebug("%p front(%d)", this, size);
00325 #endif
00326 
00327         tail += sizeof (TFifoSize);
00328 
00329         //buffer.resize (size);
00330         //CFastMem::memcpy (&(buffer[0]), tail, size);
00331 
00332         buffer.fill (tail, size);
00333 
00334         // stat code
00335         TTicks after = CTime::getPerformanceTime ();
00336         _FrontedTime += after - before;
00337 
00338 #if DEBUG_FIFO
00339         display ();
00340 #endif*/
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                 // need to rewind
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         // stat code
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                 // buffer is full
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         // creer un nouveau tableau et copie l ancien dans le nouveau.
00440         if (size < _BufferSize && UsedSize > size)
00441         {
00442                 // probleme, on a pas assez de place pour caser les datas => on fait pas
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         // clear the message to be sure user doesn't use it anymore
00454         memset (NewBuffer, '-', size);
00455 #endif
00456 
00457 #if DEBUG_FIFO
00458         nldebug("%p new %d bytes", this, size);
00459 #endif
00460 
00461         // copy the old buffer to the new one
00462         // if _Tail == _Head => empty fifo, don't copy anything
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         // resync the circular pointer
00483         // Warning: don't invert these 2 lines position or it ll not work
00484         _Tail = NewBuffer;
00485         _Head = NewBuffer + UsedSize;
00486         _Rewinder = NULL;
00487 
00488         // delete old buffer if needed
00489         if (_Buffer != NULL)
00490         {
00491                 delete _Buffer;
00492 #if DEBUG_FIFO
00493                 nldebug ("delete", this);
00494 #endif
00495         }
00496 
00497         // affect new buffer
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                         // is the buffer large enough?
00597                         if (_BufferSize >= size)
00598                         {
00599                                 // reset the pointer
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                                 // buffer not big enough
00609 #if DEBUG_FIFO
00610                                 nldebug("%p buffer full buffersize<size", this);
00611 #endif
00612                                 return false;
00613                         }
00614                 }
00615                 else
00616                 {
00617                         // buffer full
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                         // can fit after _Head
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                         // can fit at the beginning
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                         // can't fit
00650 #if DEBUG_FIFO
00651                         nldebug("%p no room t<h", this);
00652 #endif
00653                         return false;
00654                 }
00655         }
00656         else // the last case is : if (_Tail > _Head)
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 } // NLMISC