source: trunk/src/core/RpSimpleBuffer.h @ 1559

Last change on this file since 1559 was 1527, checked in by dkearney, 15 years ago

various code cleanups, mainly tabs. adding units ohms and amps, adding appendf interface to the simple buffer so we can append formatted strings.

File size: 19.8 KB
Line 
1/*
2 * ======================================================================
3 *  Rappture::SimpleBuffer
4 *
5 *  AUTHOR:  Derrick Kearney, Purdue University
6 *
7 *  Copyright (c) 2004-2008  Purdue Research Foundation
8 * ----------------------------------------------------------------------
9 *  See the file "license.terms" for information on usage and
10 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
11 * ======================================================================
12 *
13 *  This code is based on the Tcl_DString facility included in the
14 *  Tcl source release, which includes the following copyright:
15 *
16 *  Copyright (c) 1987-1993 The Regents of the University of California.
17 *  Copyright (c) 1994-1998 Sun Microsystems, Inc.
18 *  Copyright (c) 2001 by Kevin B. Kenny.  All rights reserved.
19 *
20 *  This software is copyrighted by the Regents of the University of
21 *  California, Sun Microsystems, Inc., Scriptics Corporation,
22 *  and other parties.  The following terms apply to all files associated
23 *  with the software unless explicitly disclaimed in individual files.
24 *
25 *  The authors hereby grant permission to use, copy, modify, distribute,
26 *  and license this software and its documentation for any purpose, provided
27 *  that existing copyright notices are retained in all copies and that this
28 *  notice is included verbatim in any distributions. No written agreement,
29 *  license, or royalty fee is required for any of the authorized uses.
30 *  Modifications to this software may be copyrighted by their authors
31 *  and need not follow the licensing terms described here, provided that
32 *  the new terms are clearly indicated on the first page of each file where
33 *  they apply.
34 *
35 *  IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
36 *  FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
37 *  ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
38 *  DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
39 *  POSSIBILITY OF SUCH DAMAGE.
40 *
41 *  THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
42 *  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
43 *  FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE
44 *  IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
45 *  NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
46 *  MODIFICATIONS.
47 *
48 *  GOVERNMENT USE: If you are acquiring this software on behalf of the
49 *  U.S. government, the Government shall have only "Restricted Rights"
50 *  in the software and related documentation as defined in the Federal·
51 *  Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2).  If you
52 *  are acquiring the software on behalf of the Department of Defense, the
53 *  software shall be classified as "Commercial Computer Software" and the
54 *  Government shall have only "Restricted Rights" as defined in Clause
55 *  252.227-7013 (c) (1) of DFARs.  Notwithstanding the foregoing, the
56 *  authors grant the U.S. Government and others acting in its behalf
57 *  permission to use and distribute the software in accordance with the
58 *  terms specified in this license.·
59 *
60 * ======================================================================
61 */
62
63#ifndef RAPPTURE_SIMPLEBUFFER_H
64#define RAPPTURE_SIMPLEBUFFER_H
65
66#include <fstream>
67#include <cstring>
68#include <cstdlib>
69#include <cstdarg>
70
71namespace Rappture {
72
73template <class T>
74class SimpleBuffer {
75public:
76    SimpleBuffer();
77    SimpleBuffer(size_t nmemb);
78    SimpleBuffer(const T* bytes, int nmemb=-1);
79    SimpleBuffer(const SimpleBuffer& b);
80    SimpleBuffer<T>& operator=(const SimpleBuffer<T>& b);
81    SimpleBuffer     operator+(const SimpleBuffer& b) const;
82    SimpleBuffer<T>& operator+=(const SimpleBuffer<T>& b);
83    virtual ~SimpleBuffer();
84
85    const T* bytes() const;
86    size_t size() const;
87    size_t nmemb() const;
88
89    SimpleBuffer<T>& clear();
90    int append(const T* bytes, int nmemb=-1);
91    int appendf(const char *format, ...);
92    int remove(int nmemb);
93    size_t read(const T* bytes, size_t nmemb);
94    int seek(long offset, int whence);
95    int tell() const;
96    size_t set(size_t nmemb);
97    SimpleBuffer<T>& rewind();
98    SimpleBuffer<T>& show();
99
100    bool good() const;
101    bool bad() const;
102    bool eof() const;
103
104    SimpleBuffer<T>& move(SimpleBuffer<T>& b);
105
106protected:
107
108    void bufferInit();
109    void bufferFree();
110
111private:
112
113    /// Pointer to the memory that holds our buffer's data
114    T* _buf;
115
116    /// Position offset within the buffer's memory
117    size_t _pos;
118
119    /// Number of members stored in the buffer
120    size_t _nMembStored;
121
122    /// Total number of members available in the buffer
123    size_t _nMembAvl;
124
125    /// State of the last file like operation.
126    bool _fileState;
127
128    /// Minimum number of members is set to the number you can fit in 256 bytes
129    const static int _minMembCnt=(256/sizeof(T));
130
131    size_t __guesslen(const T* bytes);
132
133};
134
135typedef SimpleBuffer<char>   SimpleCharBuffer;
136typedef SimpleBuffer<float>  SimpleFloatBuffer;
137typedef SimpleBuffer<double> SimpleDoubleBuffer;
138
139/**
140 * Construct an empty SimpleBuffer.
141 */
142template<class T>
143SimpleBuffer<T>::SimpleBuffer()
144{
145    bufferInit();
146}
147
148
149/**
150 * Construct an empty SimpleBuffer of specified size.
151 */
152template<class T>
153SimpleBuffer<T>::SimpleBuffer(size_t nmemb)
154{
155    bufferInit();
156
157    if (nmemb == 0) {
158        // ignore requests for sizes equal to zero
159        return;
160    }
161
162    // buffer sizes less than min_size are set to min_size
163    if (nmemb < (size_t) _minMembCnt) {
164        nmemb = _minMembCnt;
165    }
166
167    if (set(nmemb) != nmemb) {
168        return;
169    }
170    _nMembStored = nmemb;
171}
172
173
174/**
175 * Construct a SimpleBuffer loaded with initial data.
176 *
177 * @param bytes pointer to bytes being stored.
178 * @param nbytes number of bytes being stored.
179 */
180template<class T>
181SimpleBuffer<T>::SimpleBuffer(const T* bytes, int nmemb)
182{
183    bufferInit();
184    append(bytes,nmemb);
185}
186
187
188/**
189 * Copy constructor
190 * @param SimpleBuffer object to copy
191 */
192template<class T>
193SimpleBuffer<T>::SimpleBuffer(const SimpleBuffer<T>& b)
194{
195    bufferInit();
196    append(b.bytes(),b.nmemb());
197}
198
199
200/**
201 * Assignment operator
202 * @param SimpleBuffer object to copy
203 */
204template<class T>
205SimpleBuffer<T>&
206SimpleBuffer<T>::operator=(const SimpleBuffer<T>& b)
207{
208    bufferFree();
209    bufferInit();
210    append(b.bytes(),b.nmemb());
211    return *this;
212}
213
214
215/**
216 * Operator +
217 * @param SimpleBuffer object to add
218 */
219template<class T>
220SimpleBuffer<T>
221SimpleBuffer<T>::operator+(const SimpleBuffer<T>& b) const
222{
223    SimpleBuffer<T> newBuffer(*this);
224    newBuffer.operator+=(b);
225    return newBuffer;
226}
227
228
229/**
230 * Operator +=
231 * @param SimpleBuffer object to add
232 */
233template<class T>
234SimpleBuffer<T>&
235SimpleBuffer<T>::operator+=(const SimpleBuffer<T>& b)
236{
237    append(b.bytes(),b.nmemb());
238    return *this;
239}
240
241
242/**
243 * Destructor
244 */
245template<class T>
246SimpleBuffer<T>::~SimpleBuffer()
247{
248    bufferFree();
249}
250
251
252/**
253 * Get the bytes currently stored in the buffer.  These bytes can
254 * be stored, and used later to construct another Buffer to
255 * decode the information.
256 *
257 * @return Pointer to the bytes in the buffer.
258 */
259template<class T>
260const T*
261SimpleBuffer<T>::bytes() const
262{
263    return _buf;
264}
265
266
267/**
268 * Get the number of bytes currently stored in the buffer.
269 * @return Number of the bytes used in the buffer.
270 */
271template<class T>
272size_t
273SimpleBuffer<T>::size() const
274{
275    return _nMembStored*sizeof(T);
276}
277
278
279/**
280 * Get the number of members currently stored in the buffer.
281 * @return Number of the members used in the buffer.
282 */
283template<class T>
284size_t
285SimpleBuffer<T>::nmemb() const
286{
287    return _nMembStored;
288}
289
290
291/**
292 * Clear the buffer, making it empty.
293 * @return Reference to this buffer.
294 */
295template<class T>
296SimpleBuffer<T>&
297SimpleBuffer<T>::clear()
298{
299    bufferFree();
300    bufferInit();
301
302    return *this;
303}
304
305/**
306 * guess the length of a null terminated character buffer
307 * @param pointer to the buffer to guess the length of
308 * @return a guess of the length of the buffer.
309 */
310template<> inline
311size_t
312SimpleBuffer<char>::__guesslen(const char* bytes)
313{
314    return strlen(bytes);
315}
316
317/**
318 * guess the length of a non-null terminated character buffer
319 * @param pointer to the buffer to guess the length of
320 * @return a guess of the length of the buffer.
321 */
322template<class T>
323size_t
324SimpleBuffer<T>::__guesslen(const T* bytes)
325{
326    return (sizeof(T));
327}
328
329/**
330 * Append bytes to the end of this buffer
331 * @param pointer to bytes to be added
332 * @param number of bytes to be added
333 * @return number of bytes appended.
334 */
335template<class T>
336int
337SimpleBuffer<T>::append(const T* bytes, int nmemb)
338{
339    size_t newMembCnt = 0;
340    size_t nbytes = 0;
341
342    void* dest = NULL;
343    void const* src  = NULL;
344    size_t size = 0;
345
346    // User specified NULL buffer to append
347    if ( (bytes == NULL) && (nmemb < 1) ) {
348        return 0;
349    }
350
351    // FIXME: i think this needs to be division,
352    // need to create test case with array of ints
353    // i'm not sure we can even guess the number
354    // bytes in *bytes.
355
356    if (nmemb == -1) {
357        // user signaled null terminated string
358        // or that we should make an educated guess
359        // at the length of the object.
360        nbytes = __guesslen(bytes);
361        nmemb = nbytes/sizeof(T);
362    }
363
364    if (nmemb <= 0) {
365        // no data written, invalid option
366        return nmemb;
367    }
368
369    newMembCnt = (size_t)(_nMembStored + nmemb);
370
371    if (newMembCnt > _nMembAvl) {
372
373        // buffer sizes less than min_size are set to min_size
374        if (newMembCnt < (size_t) _minMembCnt) {
375            newMembCnt = (size_t) _minMembCnt;
376        }
377
378        /*
379         * Allocate a larger buffer for the string if the current one isn't
380         * large enough. Allocate extra space in the new buffer so that there
381         * will be room to grow before we have to allocate again.
382         */
383        size_t membAvl;
384        membAvl = (_nMembAvl > 0) ? _nMembAvl : _minMembCnt;
385        while (newMembCnt > membAvl) {
386            membAvl += membAvl;
387        }
388
389        /*
390         * reallocate to a larger buffer
391         */
392        if (set(membAvl) != membAvl) {
393            return 0;
394        }
395    }
396
397    dest = (void*) (_buf + _nMembStored);
398    src  = (void const*) bytes;
399    size = (size_t) (nmemb*sizeof(T));
400    memcpy(dest,src,size);
401
402    _nMembStored += nmemb;
403
404    return nmemb;
405}
406
407/**
408 * Append formatted bytes to the end of this buffer
409 * @param pointer to bytes to be added
410 * @param number of bytes to be added
411 * @return number of bytes appended.
412 */
413template<class T>
414int
415SimpleBuffer<T>::appendf(const char *format, ...)
416{
417    size_t newMembCnt = 0;
418    size_t nbytes = 0;
419    int nmemb = 0;
420
421    char* dest = NULL;
422    size_t size = 0;
423    size_t bytesAdded = 0;
424    va_list arg;
425
426    // User specified NULL format
427    if (format == NULL) {
428        return 0;
429    }
430
431    // FIXME: i think this needs to be division,
432    // need to create test case with array of ints
433    // i'm not sure we can even guess the number
434    // bytes in *bytes.
435
436
437    // add one for terminating null character
438    nbytes = strlen(format) + 1;
439
440    if (nbytes <= 0) {
441        // no data written, invalid option
442        return nbytes;
443    }
444
445    // FIXME: we need ceil of nbytes/sizeof(T), instead we add 1 for safety
446
447    nmemb = nbytes/sizeof(T);
448    if (nmemb == 0) {
449        nmemb++;
450    }
451
452    newMembCnt = (size_t)(_nMembStored + nmemb);
453
454    if (newMembCnt > _nMembAvl) {
455
456        // buffer sizes less than min_size are set to min_size
457        if (newMembCnt < (size_t) _minMembCnt) {
458            newMembCnt = (size_t) _minMembCnt;
459        }
460
461        /*
462         * Allocate a larger buffer for the string if the current one isn't
463         * large enough. Allocate extra space in the new buffer so that there
464         * will be room to grow before we have to allocate again.
465         */
466        size_t membAvl;
467        membAvl = (_nMembAvl > 0) ? _nMembAvl : _minMembCnt;
468        while (newMembCnt > membAvl) {
469            membAvl += membAvl;
470        }
471
472        /*
473         * reallocate to a larger buffer
474         */
475        if (set(membAvl) != membAvl) {
476            return 0;
477        }
478    }
479
480    dest = (char*) (_buf + _nMembStored);
481    size = (_nMembAvl-_nMembStored)*sizeof(T);
482
483    va_start(arg,format);
484    bytesAdded = vsnprintf(dest,size,format,arg);
485    va_end(arg);
486
487    // bytesAdded contains the number of bytes that would have
488    // been placed in the buffer if the call was successful.
489    // this value does not include the trailing null character.
490    // so we add one to account for it.
491
492    bytesAdded++;
493    nmemb = bytesAdded/sizeof(T);
494
495    if (bytesAdded > size) {
496        // we did not fit everything in the original buffer
497        // resize and try again.
498
499        // FIXME: round the new size up to the nearest multiple of 256?
500        set(_nMembStored+nmemb);
501
502        // reset dest because it may have moved during reallocation
503        dest = (char*) (_buf + _nMembStored);
504        size = bytesAdded;
505
506        va_start(arg,format);
507        bytesAdded = vsnprintf(dest,size,format,arg);
508        va_end(arg);
509
510        if (bytesAdded > size) {
511            // crystals grow, people grow, data doesn't grow...
512            // issue error
513            fprintf(stderr,"error in appendf while appending data");
514        }
515    }
516
517    _nMembStored += nmemb;
518
519    // remove the null character added by vsnprintf()
520    // we do this because if we are appending strings,
521    // the embedded null acts as a terminating null char.
522    // this is a generic buffer so if user wants a
523    // terminating null, they should append it.
524    remove(1);
525
526    return nmemb;
527}
528
529/**
530 * Remove bytes from the end of this buffer
531 * @param number of bytes to be removed
532 * @return number of bytes removed.
533 */
534template<class T>
535int
536SimpleBuffer<T>::remove(int nmemb)
537{
538    if ((_nMembStored - nmemb) < 0){
539        _nMembStored = 0;
540        _pos = 0;
541    } else {
542        _nMembStored -= nmemb;
543        if (_pos >= _nMembStored) {
544            // move _pos back to the new end of the buffer.
545            _pos = _nMembStored-1;
546        }
547    }
548
549
550    return nmemb;
551}
552
553
554template<class T>
555size_t
556SimpleBuffer<T>::set(size_t nmemb)
557{
558    T *buf;
559    size_t nbytes = nmemb*sizeof(T);
560
561    if (_buf == NULL) {
562        buf = (T*) malloc(nbytes);
563    } else {
564        buf = (T*) realloc((void*) _buf, nbytes);
565    }
566
567    if (buf == NULL) {
568        fprintf(stderr,"Can't allocate %lu bytes of memory\n",
569            (long unsigned int)nbytes);
570        _fileState = false;
571        return 0;
572    }
573    _buf = buf;
574    _nMembAvl = nmemb;
575    return _nMembAvl;
576}
577
578
579template<> inline
580SimpleBuffer<char>&
581SimpleBuffer<char>::show()
582{
583    size_t curMemb = 0;
584
585    while (curMemb != _nMembStored) {
586        fprintf(stdout,"_buf[%lu] = :%c:\n", (long unsigned int)curMemb,
587                _buf[curMemb]);
588        curMemb += 1;
589    }
590    fprintf(stdout,"_nMembAvl = :%lu:\n", (long unsigned int)_nMembAvl);
591
592    return *this;
593}
594
595
596template<class T>
597SimpleBuffer<T>&
598SimpleBuffer<T>::show()
599{
600    size_t curMemb = 0;
601
602    while (curMemb != _nMembStored) {
603        fprintf(stdout,"_buf[%lu] = :%#x:\n", (long unsigned int)curMemb,
604                (unsigned long)_buf[curMemb]);
605        curMemb += 1;
606    }
607    fprintf(stdout,"_nMembAvl = :%lu:\n", (long unsigned int)_nMembAvl);
608
609    return *this;
610}
611
612
613/**
614 * Read data from the buffer into a memory location provided by caller
615 * @param Pointer locating where to place read bytes.
616 * @param Size of the memory location.
617 * @return Number of bytes written to memory location
618 */
619template<class T>
620size_t
621SimpleBuffer<T>::read(const T* bytes, size_t nmemb)
622{
623    size_t nMembRead = 0;
624
625    void* dest = NULL;
626    void const* src  = NULL;
627    size_t size = 0;
628
629    // SimpleBuffer is empty.
630    if (_buf == NULL) {
631        return 0;
632    }
633
634    // User specified NULL buffer.
635    if (bytes == NULL) {
636        return 0;
637    }
638
639    // make sure we don't read off the end of our buffer
640    if ( (_pos + nmemb) > _nMembStored ) {
641        nMembRead = _nMembStored - _pos;
642    }
643    else {
644        nMembRead = nmemb;
645    }
646
647    if (nMembRead <= 0) {
648        return 0;
649    }
650
651    dest = (void*) bytes;
652    src  = (void const*) (_buf + _pos);
653    size = nMembRead*sizeof(T);
654    memcpy(dest,src,size);
655
656    _pos = (_pos + nMembRead);
657
658    return nMembRead;
659}
660
661
662/**
663 * Set buffer position indicator to spot within the buffer
664 * @param Offset from whence location in buffer.
665 * @param Place from where offset is added or subtracted.
666 * @return 0 on success, anything else is failure
667 */
668template<class T>
669int
670SimpleBuffer<T>::seek(long offset, int whence)
671{
672    int retVal = 0;
673
674    if (_buf == NULL) {
675        return -1 ;
676    }
677
678    if (whence == SEEK_SET) {
679        if (offset < 0) {
680            /* dont go off the beginning of data */
681            _pos = 0;
682        }
683        else if (offset >= (long)_nMembStored) {
684            /* dont go off the end of data */
685            _pos = _nMembStored - 1;
686        }
687        else {
688            _pos = (size_t)(offset);
689        }
690    }
691    else if (whence == SEEK_CUR) {
692        if ( (_pos + offset) < 0) {
693            /* dont go off the beginning of data */
694            _pos = 0;
695        }
696        else if ((_pos + offset) >= _nMembStored) {
697            /* dont go off the end of data */
698            _pos = _nMembStored - 1;
699        }
700        else {
701            _pos = (size_t)(_pos + offset);
702        }
703    }
704    else if (whence == SEEK_END) {
705        if (offset <= (long)(-1*_nMembStored)) {
706            /* dont go off the beginning of data */
707            _pos = 0;
708        }
709        else if (offset >= 0) {
710            /* dont go off the end of data */
711            _pos = _nMembStored - 1;
712        }
713        else {
714            _pos = (size_t)((_nMembStored - 1) + offset);
715        }
716    }
717    else {
718        retVal = -1;
719    }
720
721    return retVal;
722}
723
724
725/**
726 * Tell caller the offset of the position indicator from the start of buffer
727 * @return Number of bytes the position indicator is from start of buffer
728 */
729template<class T>
730int
731SimpleBuffer<T>::tell() const
732{
733   return (int)_pos;
734}
735
736
737/**
738 * Read data from the buffer into a memory location provided by caller
739 */
740template<class T>
741SimpleBuffer<T>&
742SimpleBuffer<T>::rewind()
743{
744    _pos = 0;
745    return *this;
746}
747
748
749/**
750 * Tell if the last file like operation (ie. read()) was successful
751 * or if there was a failure like eof, or bad memory
752 * @return True or false boolean value
753 */
754template<class T>
755bool
756SimpleBuffer<T>::good() const
757{
758    return (_fileState);
759}
760
761
762/**
763 * Tell if the last file like operation (ie. read()) failed
764 * Opposite of good()
765 * @return True or false boolean value
766 */
767template<class T>
768bool
769SimpleBuffer<T>::bad() const
770{
771    return (!_fileState);
772}
773
774
775/**
776 * Tell if the position flag is at the end of the buffer
777 * @return True or false boolean value
778 */
779template<class T>
780bool
781SimpleBuffer<T>::eof() const
782{
783    return (_pos >= _nMembStored);
784}
785
786
787/**
788 * Move the data from this SimpleBuffer to the SimpleBuffer provided by
789 * the caller. All data except the _pos is moved and this SimpleBuffer is
790 * re-initialized with bufferInit().
791 * @param SimpleBuffer to move the information to
792 * @return reference to this SimpleBuffer object.
793 */
794template<class T>
795SimpleBuffer<T>&
796SimpleBuffer<T>::move(SimpleBuffer<T>& b)
797{
798    bufferFree();
799
800    _buf = b._buf;
801    _pos = b._pos;
802    _fileState = b._fileState;
803    _nMembStored = b._nMembStored;
804    _nMembAvl = b._nMembAvl;
805
806    b.bufferInit();
807
808    return *this;
809}
810
811
812 /**
813  *  Initializes a dynamic buffer, discarding any previous contents
814  *  of the buffer. bufferFree() should have been called already
815  *  if the dynamic buffer was previously in use.
816  */
817template<class T>
818void
819SimpleBuffer<T>::bufferInit()
820{
821    _buf = NULL;
822    _pos = 0;
823    _fileState = true;
824    _nMembStored = 0;
825    _nMembAvl = 0;
826}
827
828
829/**
830 *  Frees up any memory allocated for the dynamic buffer and
831 *  reinitializes the buffer to an empty state.
832 */
833template<class T>
834void
835SimpleBuffer<T>::bufferFree()
836{
837    if (_buf != NULL) {
838        free(_buf);
839        _buf = NULL;
840    }
841    bufferInit();
842}
843
844} // namespace Rappture
845
846#endif // RAPPTURE_SIMPLEBUFFER_H
Note: See TracBrowser for help on using the repository browser.