Changeset 2544 for branches/blt4/src/core/RpSimpleBuffer.h
- Timestamp:
- Sep 21, 2011 2:28:26 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/blt4/src/core/RpSimpleBuffer.h
r1897 r2544 1 1 2 /* 2 3 * ====================================================================== … … 69 70 #include <cstdarg> 70 71 72 /* 73 * Note: I think I would redo this class to deal only with unsigned byte 74 * arrays, instead of arrays of <T>. I would create other classes 75 * that arrays of <T> that used the lower level byte array. 76 * 77 * It would make it cleaner if the class only dealt with bytes 78 * instead of elements (of various sizes). 79 * 80 * Specific implementations of <T> could perform data alignment on 81 * word/double word/quad word boundaries. This is an optimization 82 * that should could done for double arrays. 83 * 84 * Note: The signed int argument on append() should be replaced with a 85 * size_t. This limits the length of strings to appended. It 86 * silently truncates bigger sizes to the lower 32-bits. 87 */ 71 88 namespace Rappture { 72 89 … … 74 91 class SimpleBuffer { 75 92 public: 76 SimpleBuffer(); 93 /** 94 * Construct an empty SimpleBuffer. 95 */ 96 SimpleBuffer() { 97 Initialize(); 98 } 99 /** 100 * Construct a SimpleBuffer loaded with initial data. 101 * 102 * @param bytes pointer to bytes being stored. 103 * @param nbytes number of bytes being stored. 104 */ 105 SimpleBuffer(const T* bytes, int numElems=-1) { 106 Initialize(); 107 append(bytes, numElems); 108 } 77 109 SimpleBuffer(size_t nmemb); 78 SimpleBuffer(const T* bytes, int nmemb=-1); 110 111 /** 112 * Copy constructor 113 * @param SimpleBuffer object to copy 114 */ 79 115 SimpleBuffer(const SimpleBuffer& b); 116 80 117 SimpleBuffer<T>& operator=(const SimpleBuffer<T>& b); 81 118 SimpleBuffer operator+(const SimpleBuffer& b) const; 82 119 SimpleBuffer<T>& operator+=(const SimpleBuffer<T>& b); 83 120 T operator[](size_t offset); 84 virtual ~SimpleBuffer(); 85 86 const T* bytes() const; 87 size_t size() const; 88 size_t nmemb() const; 89 90 SimpleBuffer<T>& clear(); 121 122 /** 123 * Destructor 124 */ 125 virtual ~SimpleBuffer() { 126 Release(); 127 } 128 129 /** 130 * Get the bytes currently stored in the buffer. These bytes can 131 * be stored, and used later to construct another Buffer to 132 * decode the information. 133 * 134 * @return Pointer to the bytes in the buffer. 135 */ 136 const T* bytes() const { 137 return _buf; 138 } 139 /** 140 * Get the number of bytes currently stored in the buffer. 141 * @return Number of the bytes used in the buffer. 142 */ 143 size_t size() const { 144 return _numElemsUsed * sizeof(T); 145 } 146 /** 147 * Get the number of members currently stored in the buffer. 148 * @return Number of the members used in the buffer. 149 */ 150 size_t nmemb() const { 151 return _numElemsUsed; 152 } 153 /** 154 * Get the number of members currently stored in the buffer. 155 * @return Number of the members used in the buffer. 156 */ 157 size_t count() const { 158 return _numElemsUsed; 159 } 160 /** 161 * Set the number of members currently stored in the buffer. 162 * @return Number of the members used in the buffer. 163 */ 164 size_t count(size_t newCount) { 165 _numElemsUsed = newCount; 166 return _numElemsUsed; 167 } 168 /** 169 * Clear the buffer, making it empty. 170 * @return Reference to this buffer. 171 */ 172 SimpleBuffer<T>& clear() { 173 Release(); 174 return *this; 175 } 176 size_t extend(size_t extraElems); 91 177 int append(const T* bytes, int nmemb=-1); 92 178 int appendf(const char *format, ...); … … 98 184 SimpleBuffer<T>& rewind(); 99 185 SimpleBuffer<T>& show(); 100 186 101 187 bool good() const; 102 188 bool bad() const; 103 189 bool eof() const; 104 190 105 191 SimpleBuffer<T>& move(SimpleBuffer<T>& b); 106 192 107 193 protected: 108 109 void bufferInit();110 void bufferFree();111 194 195 void Initialize(); 196 void Release(); 197 112 198 private: 113 199 114 200 /// Pointer to the memory that holds our buffer's data 115 201 T* _buf; 116 202 117 203 /// Position offset within the buffer's memory 118 204 size_t _pos; 119 205 120 206 /// Number of members stored in the buffer 121 size_t _n MembStored;122 207 size_t _numElemsUsed; 208 123 209 /// Total number of members available in the buffer 124 size_t _n MembAvl;125 210 size_t _numElemsAllocated; 211 126 212 /// State of the last file like operation. 127 213 bool _fileState; 128 214 129 215 /// Minimum number of members is set to the number you can fit in 256 bytes 130 const static int _minMembCnt=(256/sizeof(T));131 216 const static size_t _minNumElems = (256/sizeof(T)); 217 132 218 size_t __guesslen(const T* bytes); 133 219 134 220 }; 135 221 136 222 typedef SimpleBuffer<char> SimpleCharBuffer; 137 223 typedef SimpleBuffer<float> SimpleFloatBuffer; … … 139 225 140 226 /** 141 * Construct an empty SimpleBuffer.142 */143 template<class T>144 SimpleBuffer<T>::SimpleBuffer()145 {146 bufferInit();147 }148 149 150 /**151 227 * Construct an empty SimpleBuffer of specified size. 152 228 */ 153 229 template<class T> 154 SimpleBuffer<T>::SimpleBuffer(size_t n memb)155 { 156 bufferInit();157 158 if (n memb== 0) {230 SimpleBuffer<T>::SimpleBuffer(size_t numElems) 231 { 232 Initialize(); 233 234 if (numElems == 0) { 159 235 // ignore requests for sizes equal to zero 160 236 return; … … 162 238 163 239 // buffer sizes less than min_size are set to min_size 164 if (n memb < (size_t) _minMembCnt) {165 n memb = _minMembCnt;166 } 167 168 if (set(n memb) != nmemb) {240 if (numElems < (size_t) _minNumElems) { 241 numElems = _minNumElems; 242 } 243 244 if (set(numElems) != numElems) { 169 245 return; 170 246 } 171 _nMembStored = nmemb; 172 } 173 174 175 /** 176 * Construct a SimpleBuffer loaded with initial data. 177 * 178 * @param bytes pointer to bytes being stored. 179 * @param nbytes number of bytes being stored. 180 */ 181 template<class T> 182 SimpleBuffer<T>::SimpleBuffer(const T* bytes, int nmemb) 183 { 184 bufferInit(); 185 append(bytes,nmemb); 247 _numElemsUsed = numElems; 186 248 } 187 249 … … 194 256 SimpleBuffer<T>::SimpleBuffer(const SimpleBuffer<T>& b) 195 257 { 196 bufferInit();197 append(b.bytes(), b.nmemb());258 Initialize(); 259 append(b.bytes(), b.nmemb()); 198 260 } 199 261 … … 207 269 SimpleBuffer<T>::operator=(const SimpleBuffer<T>& b) 208 270 { 209 bufferFree(); 210 bufferInit(); 271 Release(); 211 272 append(b.bytes(),b.nmemb()); 212 273 return *this; … … 247 308 template<class T> 248 309 T 249 SimpleBuffer<T>::operator[](size_t idx) 250 { 251 return (_buf+idx); 252 } 253 254 255 /** 256 * Destructor 257 */ 258 template<class T> 259 SimpleBuffer<T>::~SimpleBuffer() 260 { 261 bufferFree(); 262 } 263 264 265 /** 266 * Get the bytes currently stored in the buffer. These bytes can 267 * be stored, and used later to construct another Buffer to 268 * decode the information. 269 * 270 * @return Pointer to the bytes in the buffer. 271 */ 272 template<class T> 273 const T* 274 SimpleBuffer<T>::bytes() const 275 { 276 return _buf; 277 } 278 279 280 /** 281 * Get the number of bytes currently stored in the buffer. 282 * @return Number of the bytes used in the buffer. 283 */ 284 template<class T> 285 size_t 286 SimpleBuffer<T>::size() const 287 { 288 return _nMembStored*sizeof(T); 289 } 290 291 292 /** 293 * Get the number of members currently stored in the buffer. 294 * @return Number of the members used in the buffer. 295 */ 296 template<class T> 297 size_t 298 SimpleBuffer<T>::nmemb() const 299 { 300 return _nMembStored; 301 } 302 303 304 /** 305 * Clear the buffer, making it empty. 306 * @return Reference to this buffer. 307 */ 308 template<class T> 309 SimpleBuffer<T>& 310 SimpleBuffer<T>::clear() 311 { 312 bufferFree(); 313 bufferInit(); 314 315 return *this; 316 } 310 SimpleBuffer<T>::operator[](size_t index) 311 { 312 return (_buf + index); // Rely on pointer arithmetic 313 } 314 315 317 316 318 317 /** … … 327 326 return strlen(bytes); 328 327 } 328 329 /* FIXME: Change the signed int to size_t. Move the -1 copy string 330 * up to the SimpleCharBuffer class. There needs to be both 331 * a heavy duty class that can take a string bigger than 332 * 2^31-1 in length, and a convenient class that doesn't make 333 * you add call strlen(s). 334 * 335 */ 329 336 330 337 /** … … 348 355 template<class T> 349 356 int 350 SimpleBuffer<T>::append(const T* bytes, int nmemb) 351 { 352 size_t newMembCnt = 0; 353 size_t nbytes = 0; 354 355 void* dest = NULL; 356 void const* src = NULL; 357 size_t size = 0; 357 SimpleBuffer<T>::append(const T* bytes, int numElems) 358 { 358 359 359 360 // User specified NULL buffer to append 360 if ( (bytes == NULL) && (nmemb < 1) ) { 361 return 0; 361 if (bytes == NULL) { 362 return 0; // Should not give append a NULL 363 // buffer pointer. 362 364 } 363 365 … … 367 369 // bytes in *bytes. 368 370 369 if (nmemb == -1) { 370 // user signaled null terminated string 371 // or that we should make an educated guess 372 // at the length of the object. 373 nbytes = __guesslen(bytes); 374 nmemb = nbytes/sizeof(T); 375 } 376 377 if (nmemb <= 0) { 371 size_t numBytes = 0; 372 if (numElems == -1) { 373 /* This should be moved into the SimpleCharBuffer. It doesn't make 374 * sense to look for a NUL byte unless it's a string buffer. We 375 * can then change numElems to be size_t. */ 376 numBytes = __guesslen(bytes); 377 numElems = numBytes / sizeof(T); 378 } 379 if (numElems <= 0) { 380 return numElems; 381 } 382 383 size_t newSize; 384 newSize = _numElemsUsed + numElems; 385 if (newSize > _numElemsAllocated) { 386 387 // buffer sizes less than min_size are set to min_size 388 if (newSize < _minNumElems) { 389 newSize = _minNumElems; 390 } 391 392 /* 393 * Allocate a larger buffer for the string if the current one isn't 394 * large enough. Allocate extra space in the new buffer so that there 395 * will be room to grow before we have to allocate again. 396 */ 397 size_t size; 398 size = (_numElemsAllocated > 0) ? _numElemsAllocated : _minNumElems; 399 while (newSize > size) { 400 size += size; 401 } 402 403 /* 404 * reallocate to a larger buffer 405 */ 406 if (set(size) != size) { 407 return 0; 408 } 409 } 410 memcpy(_buf + _numElemsUsed, bytes, numElems * sizeof(T)); 411 _numElemsUsed += numElems; 412 return numElems; 413 } 414 415 /** 416 * Append bytes to the end of this buffer 417 * @param pointer to bytes to be added 418 * @param number of bytes to be added 419 * @return number of bytes appended. 420 */ 421 template<class T> 422 size_t 423 SimpleBuffer<T>::extend(size_t numExtraElems) 424 { 425 size_t newSize; 426 427 newSize = _numElemsUsed + numExtraElems; 428 if (newSize > _numElemsAllocated) { 429 430 /* Enforce a minimum buffer size. */ 431 if (newSize < (size_t) _minNumElems) { 432 newSize = (size_t) _minNumElems; 433 } 434 435 size_t size; 436 size = (_numElemsAllocated > 0) ? _numElemsAllocated : _minNumElems; 437 438 /* Keep doubling the size of the buffer until we have enough space to 439 * hold the extra elements. */ 440 while (newSize > size) { 441 size += size; 442 } 443 /* Reallocate to a larger buffer. */ 444 if (set(size) != size) { 445 return 0; 446 } 447 } 448 return _numElemsAllocated; 449 } 450 451 /** 452 * Append formatted bytes to the end of this buffer 453 * @param pointer to bytes to be added 454 * @param number of bytes to be added 455 * @return number of bytes appended. 456 */ 457 template<class T> 458 int 459 SimpleBuffer<T>::appendf(const char *format, ...) 460 { 461 size_t newMembCnt = 0; 462 size_t nbytes = 0; 463 int nmemb = 0; 464 465 char* dest = NULL; 466 size_t size = 0; 467 size_t bytesAdded = 0; 468 va_list arg; 469 470 // User specified NULL format 471 if (format == NULL) { 472 return 0; 473 } 474 475 // FIXME: i think this needs to be division, 476 // need to create test case with array of ints 477 // i'm not sure we can even guess the number 478 // bytes in *bytes. 479 480 481 // add one for terminating null character 482 nbytes = strlen(format) + 1; 483 484 if (nbytes <= 0) { 378 485 // no data written, invalid option 379 return nmemb; 380 } 381 382 newMembCnt = (size_t)(_nMembStored + nmemb); 383 384 if (newMembCnt > _nMembAvl) { 486 return nbytes; 487 } 488 489 // FIXME: we need ceil of nbytes/sizeof(T), instead we add 1 for safety 490 491 nmemb = nbytes/sizeof(T); 492 if (nmemb == 0) { 493 nmemb++; 494 } 495 496 newMembCnt = (size_t)(_numElemsUsed + nmemb); 497 498 if (newMembCnt > _numElemsAllocated) { 385 499 386 500 // buffer sizes less than min_size are set to min_size 387 if (newMembCnt < (size_t) _min MembCnt) {388 newMembCnt = (size_t) _min MembCnt;501 if (newMembCnt < (size_t) _minNumElems) { 502 newMembCnt = (size_t) _minNumElems; 389 503 } 390 504 … … 395 509 */ 396 510 size_t membAvl; 397 membAvl = (_n MembAvl > 0) ? _nMembAvl : _minMembCnt;511 membAvl = (_numElemsAllocated > 0) ? _numElemsAllocated : _minNumElems; 398 512 while (newMembCnt > membAvl) { 399 513 membAvl += membAvl; … … 408 522 } 409 523 410 dest = (void*) (_buf + _nMembStored); 411 src = (void const*) bytes; 412 size = (size_t) (nmemb*sizeof(T)); 413 memcpy(dest,src,size); 414 415 _nMembStored += nmemb; 416 417 return nmemb; 418 } 419 420 /** 421 * Append formatted bytes to the end of this buffer 422 * @param pointer to bytes to be added 423 * @param number of bytes to be added 424 * @return number of bytes appended. 425 */ 426 template<class T> 427 int 428 SimpleBuffer<T>::appendf(const char *format, ...) 429 { 430 size_t newMembCnt = 0; 431 size_t nbytes = 0; 432 int nmemb = 0; 433 434 char* dest = NULL; 435 size_t size = 0; 436 size_t bytesAdded = 0; 437 va_list arg; 438 439 // User specified NULL format 440 if (format == NULL) { 441 return 0; 442 } 443 444 // FIXME: i think this needs to be division, 445 // need to create test case with array of ints 446 // i'm not sure we can even guess the number 447 // bytes in *bytes. 448 449 450 // add one for terminating null character 451 nbytes = strlen(format) + 1; 452 453 if (nbytes <= 0) { 454 // no data written, invalid option 455 return nbytes; 456 } 457 458 // FIXME: we need ceil of nbytes/sizeof(T), instead we add 1 for safety 459 460 nmemb = nbytes/sizeof(T); 461 if (nmemb == 0) { 462 nmemb++; 463 } 464 465 newMembCnt = (size_t)(_nMembStored + nmemb); 466 467 if (newMembCnt > _nMembAvl) { 468 469 // buffer sizes less than min_size are set to min_size 470 if (newMembCnt < (size_t) _minMembCnt) { 471 newMembCnt = (size_t) _minMembCnt; 472 } 473 474 /* 475 * Allocate a larger buffer for the string if the current one isn't 476 * large enough. Allocate extra space in the new buffer so that there 477 * will be room to grow before we have to allocate again. 478 */ 479 size_t membAvl; 480 membAvl = (_nMembAvl > 0) ? _nMembAvl : _minMembCnt; 481 while (newMembCnt > membAvl) { 482 membAvl += membAvl; 483 } 484 485 /* 486 * reallocate to a larger buffer 487 */ 488 if (set(membAvl) != membAvl) { 489 return 0; 490 } 491 } 492 493 dest = (char*) (_buf + _nMembStored); 494 size = (_nMembAvl-_nMembStored)*sizeof(T); 524 dest = (char*) (_buf + _numElemsUsed); 525 size = (_numElemsAllocated-_numElemsUsed)*sizeof(T); 495 526 496 527 va_start(arg,format); … … 511 542 512 543 // FIXME: round the new size up to the nearest multiple of 256? 513 set(_n MembStored+nmemb);544 set(_numElemsUsed+nmemb); 514 545 515 546 // reset dest because it may have moved during reallocation 516 dest = (char*) (_buf + _n MembStored);547 dest = (char*) (_buf + _numElemsUsed); 517 548 size = bytesAdded; 518 549 … … 528 559 } 529 560 530 _n MembStored += nmemb;561 _numElemsUsed += nmemb; 531 562 532 563 // remove the null character added by vsnprintf() … … 549 580 SimpleBuffer<T>::remove(int nmemb) 550 581 { 551 if ((_n MembStored - nmemb) < 0){552 _n MembStored = 0;582 if ((_numElemsUsed - nmemb) < 0){ 583 _numElemsUsed = 0; 553 584 _pos = 0; 554 585 } else { 555 _n MembStored -= nmemb;556 if (_pos >= _n MembStored) {586 _numElemsUsed -= nmemb; 587 if (_pos >= _numElemsUsed) { 557 588 // move _pos back to the new end of the buffer. 558 _pos = _n MembStored-1;589 _pos = _numElemsUsed-1; 559 590 } 560 591 } … … 563 594 return nmemb; 564 595 } 565 566 596 567 597 template<class T> … … 585 615 } 586 616 _buf = buf; 587 _nMembAvl = nmemb; 588 return _nMembAvl; 589 } 590 617 _numElemsAllocated = nmemb; 618 return _numElemsAllocated; 619 } 591 620 592 621 template<> inline … … 596 625 size_t curMemb = 0; 597 626 598 while (curMemb != _n MembStored) {627 while (curMemb != _numElemsUsed) { 599 628 fprintf(stdout,"_buf[%lu] = :%c:\n", (long unsigned int)curMemb, 600 629 _buf[curMemb]); 601 630 curMemb += 1; 602 631 } 603 fprintf(stdout,"_nMembAvl = :%lu:\n", (long unsigned int)_nMembAvl); 632 fprintf(stdout,"_numElemsAllocated = :%lu:\n", 633 (long unsigned int)_numElemsAllocated); 604 634 605 635 return *this; … … 613 643 size_t curMemb = 0; 614 644 615 while (curMemb != _n MembStored) {645 while (curMemb != _numElemsUsed) { 616 646 fprintf(stdout,"_buf[%lu] = :%#x:\n", (long unsigned int)curMemb, 617 647 (unsigned long)_buf[curMemb]); 618 648 curMemb += 1; 619 649 } 620 fprintf(stdout,"_n MembAvl = :%lu:\n", (long unsigned int)_nMembAvl);650 fprintf(stdout,"_numElemsAllocated = :%lu:\n", (long unsigned int)_numElemsAllocated); 621 651 622 652 return *this; … … 651 681 652 682 // make sure we don't read off the end of our buffer 653 if ( (_pos + nmemb) > _n MembStored ) {654 nMembRead = _n MembStored - _pos;683 if ( (_pos + nmemb) > _numElemsUsed ) { 684 nMembRead = _numElemsUsed - _pos; 655 685 } 656 686 else { … … 694 724 _pos = 0; 695 725 } 696 else if (offset >= (long)_n MembStored) {726 else if (offset >= (long)_numElemsUsed) { 697 727 /* dont go off the end of data */ 698 _pos = _n MembStored - 1;728 _pos = _numElemsUsed - 1; 699 729 } 700 730 else { … … 707 737 _pos = 0; 708 738 } 709 else if ((_pos + offset) >= _n MembStored) {739 else if ((_pos + offset) >= _numElemsUsed) { 710 740 /* dont go off the end of data */ 711 _pos = _n MembStored - 1;741 _pos = _numElemsUsed - 1; 712 742 } 713 743 else { … … 716 746 } 717 747 else if (whence == SEEK_END) { 718 if (offset <= (long)(-1*_n MembStored)) {748 if (offset <= (long)(-1*_numElemsUsed)) { 719 749 /* dont go off the beginning of data */ 720 750 _pos = 0; … … 722 752 else if (offset >= 0) { 723 753 /* dont go off the end of data */ 724 _pos = _n MembStored - 1;754 _pos = _numElemsUsed - 1; 725 755 } 726 756 else { 727 _pos = (size_t)((_n MembStored - 1) + offset);757 _pos = (size_t)((_numElemsUsed - 1) + offset); 728 758 } 729 759 } … … 794 824 SimpleBuffer<T>::eof() const 795 825 { 796 return (_pos >= _n MembStored);826 return (_pos >= _numElemsUsed); 797 827 } 798 828 … … 801 831 * Move the data from this SimpleBuffer to the SimpleBuffer provided by 802 832 * the caller. All data except the _pos is moved and this SimpleBuffer is 803 * re-initialized with bufferInit().833 * re-initialized with Initialize(). 804 834 * @param SimpleBuffer to move the information to 805 835 * @return reference to this SimpleBuffer object. … … 809 839 SimpleBuffer<T>::move(SimpleBuffer<T>& b) 810 840 { 811 bufferFree();841 Release(); 812 842 813 843 _buf = b._buf; 814 844 _pos = b._pos; 815 845 _fileState = b._fileState; 816 _n MembStored = b._nMembStored;817 _n MembAvl = b._nMembAvl;818 819 b. bufferInit();846 _numElemsUsed = b._numElemsUsed; 847 _numElemsAllocated = b._numElemsAllocated; 848 849 b.Initialize(); 820 850 821 851 return *this; … … 825 855 /** 826 856 * Initializes a dynamic buffer, discarding any previous contents 827 * of the buffer. bufferFree() should have been called already857 * of the buffer. Release() should have been called already 828 858 * if the dynamic buffer was previously in use. 829 859 */ 830 860 template<class T> 831 861 void 832 SimpleBuffer<T>:: bufferInit()862 SimpleBuffer<T>::Initialize() 833 863 { 834 864 _buf = NULL; 835 865 _pos = 0; 836 866 _fileState = true; 837 _n MembStored = 0;838 _n MembAvl= 0;867 _numElemsUsed = 0; 868 _numElemsAllocated = 0; 839 869 } 840 870 … … 846 876 template<class T> 847 877 void 848 SimpleBuffer<T>:: bufferFree()878 SimpleBuffer<T>::Release() 849 879 { 850 880 if (_buf != NULL) { … … 852 882 _buf = NULL; 853 883 } 854 bufferInit();884 Initialize(); 855 885 } 856 886
Note: See TracChangeset
for help on using the changeset viewer.