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

Last change on this file since 1617 was 1560, checked in by dkearney, 15 years ago

updates to the object system, fixed up tree and xml parser objects, added some basic tests for them and adopted number object to accept xml text and configure itself from the parsed xml. added fermi3.cc example program which contains suggested interface from apps meeting.

File size: 20.0 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    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();
91    int append(const T* bytes, int nmemb=-1);
92    int appendf(const char *format, ...);
93    int remove(int nmemb);
94    size_t read(const T* bytes, size_t nmemb);
95    int seek(long offset, int whence);
96    int tell() const;
97    size_t set(size_t nmemb);
98    SimpleBuffer<T>& rewind();
99    SimpleBuffer<T>& show();
100
101    bool good() const;
102    bool bad() const;
103    bool eof() const;
104
105    SimpleBuffer<T>& move(SimpleBuffer<T>& b);
106
107protected:
108
109    void bufferInit();
110    void bufferFree();
111
112private:
113
114    /// Pointer to the memory that holds our buffer's data
115    T* _buf;
116
117    /// Position offset within the buffer's memory
118    size_t _pos;
119
120    /// Number of members stored in the buffer
121    size_t _nMembStored;
122
123    /// Total number of members available in the buffer
124    size_t _nMembAvl;
125
126    /// State of the last file like operation.
127    bool _fileState;
128
129    /// Minimum number of members is set to the number you can fit in 256 bytes
130    const static int _minMembCnt=(256/sizeof(T));
131
132    size_t __guesslen(const T* bytes);
133
134};
135
136typedef SimpleBuffer<char>   SimpleCharBuffer;
137typedef SimpleBuffer<float>  SimpleFloatBuffer;
138typedef SimpleBuffer<double> SimpleDoubleBuffer;
139
140/**
141 * Construct an empty SimpleBuffer.
142 */
143template<class T>
144SimpleBuffer<T>::SimpleBuffer()
145{
146    bufferInit();
147}
148
149
150/**
151 * Construct an empty SimpleBuffer of specified size.
152 */
153template<class T>
154SimpleBuffer<T>::SimpleBuffer(size_t nmemb)
155{
156    bufferInit();
157
158    if (nmemb == 0) {
159        // ignore requests for sizes equal to zero
160        return;
161    }
162
163    // buffer sizes less than min_size are set to min_size
164    if (nmemb < (size_t) _minMembCnt) {
165        nmemb = _minMembCnt;
166    }
167
168    if (set(nmemb) != nmemb) {
169        return;
170    }
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 */
181template<class T>
182SimpleBuffer<T>::SimpleBuffer(const T* bytes, int nmemb)
183{
184    bufferInit();
185    append(bytes,nmemb);
186}
187
188
189/**
190 * Copy constructor
191 * @param SimpleBuffer object to copy
192 */
193template<class T>
194SimpleBuffer<T>::SimpleBuffer(const SimpleBuffer<T>& b)
195{
196    bufferInit();
197    append(b.bytes(),b.nmemb());
198}
199
200
201/**
202 * Assignment operator
203 * @param SimpleBuffer object to copy
204 */
205template<class T>
206SimpleBuffer<T>&
207SimpleBuffer<T>::operator=(const SimpleBuffer<T>& b)
208{
209    bufferFree();
210    bufferInit();
211    append(b.bytes(),b.nmemb());
212    return *this;
213}
214
215
216/**
217 * Operator +
218 * @param SimpleBuffer object to add
219 */
220template<class T>
221SimpleBuffer<T>
222SimpleBuffer<T>::operator+(const SimpleBuffer<T>& b) const
223{
224    SimpleBuffer<T> newBuffer(*this);
225    newBuffer.operator+=(b);
226    return newBuffer;
227}
228
229
230/**
231 * Operator +=
232 * @param SimpleBuffer object to add
233 */
234template<class T>
235SimpleBuffer<T>&
236SimpleBuffer<T>::operator+=(const SimpleBuffer<T>& b)
237{
238    append(b.bytes(),b.nmemb());
239    return *this;
240}
241
242
243/**
244 * Operator []
245 * @param index into the buffer
246 */
247template<class T>
248T
249SimpleBuffer<T>::operator[](size_t idx)
250{
251    return (_buf+idx);
252}
253
254
255/**
256 * Destructor
257 */
258template<class T>
259SimpleBuffer<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 */
272template<class T>
273const T*
274SimpleBuffer<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 */
284template<class T>
285size_t
286SimpleBuffer<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 */
296template<class T>
297size_t
298SimpleBuffer<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 */
308template<class T>
309SimpleBuffer<T>&
310SimpleBuffer<T>::clear()
311{
312    bufferFree();
313    bufferInit();
314
315    return *this;
316}
317
318/**
319 * guess the length of a null terminated character buffer
320 * @param pointer to the buffer to guess the length of
321 * @return a guess of the length of the buffer.
322 */
323template<> inline
324size_t
325SimpleBuffer<char>::__guesslen(const char* bytes)
326{
327    return strlen(bytes);
328}
329
330/**
331 * guess the length of a non-null terminated character buffer
332 * @param pointer to the buffer to guess the length of
333 * @return a guess of the length of the buffer.
334 */
335template<class T>
336size_t
337SimpleBuffer<T>::__guesslen(const T* bytes)
338{
339    return (sizeof(T));
340}
341
342/**
343 * Append bytes to the end of this buffer
344 * @param pointer to bytes to be added
345 * @param number of bytes to be added
346 * @return number of bytes appended.
347 */
348template<class T>
349int
350SimpleBuffer<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;
358
359    // User specified NULL buffer to append
360    if ( (bytes == NULL) && (nmemb < 1) ) {
361        return 0;
362    }
363
364    // FIXME: i think this needs to be division,
365    // need to create test case with array of ints
366    // i'm not sure we can even guess the number
367    // bytes in *bytes.
368
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) {
378        // no data written, invalid option
379        return nmemb;
380    }
381
382    newMembCnt = (size_t)(_nMembStored + nmemb);
383
384    if (newMembCnt > _nMembAvl) {
385
386        // buffer sizes less than min_size are set to min_size
387        if (newMembCnt < (size_t) _minMembCnt) {
388            newMembCnt = (size_t) _minMembCnt;
389        }
390
391        /*
392         * Allocate a larger buffer for the string if the current one isn't
393         * large enough. Allocate extra space in the new buffer so that there
394         * will be room to grow before we have to allocate again.
395         */
396        size_t membAvl;
397        membAvl = (_nMembAvl > 0) ? _nMembAvl : _minMembCnt;
398        while (newMembCnt > membAvl) {
399            membAvl += membAvl;
400        }
401
402        /*
403         * reallocate to a larger buffer
404         */
405        if (set(membAvl) != membAvl) {
406            return 0;
407        }
408    }
409
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 */
426template<class T>
427int
428SimpleBuffer<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);
495
496    va_start(arg,format);
497    bytesAdded = vsnprintf(dest,size,format,arg);
498    va_end(arg);
499
500    // bytesAdded contains the number of bytes that would have
501    // been placed in the buffer if the call was successful.
502    // this value does not include the trailing null character.
503    // so we add one to account for it.
504
505    bytesAdded++;
506    nmemb = bytesAdded/sizeof(T);
507
508    if (bytesAdded > size) {
509        // we did not fit everything in the original buffer
510        // resize and try again.
511
512        // FIXME: round the new size up to the nearest multiple of 256?
513        set(_nMembStored+nmemb);
514
515        // reset dest because it may have moved during reallocation
516        dest = (char*) (_buf + _nMembStored);
517        size = bytesAdded;
518
519        va_start(arg,format);
520        bytesAdded = vsnprintf(dest,size,format,arg);
521        va_end(arg);
522
523        if (bytesAdded > size) {
524            // crystals grow, people grow, data doesn't grow...
525            // issue error
526            fprintf(stderr,"error in appendf while appending data");
527        }
528    }
529
530    _nMembStored += nmemb;
531
532    // remove the null character added by vsnprintf()
533    // we do this because if we are appending strings,
534    // the embedded null acts as a terminating null char.
535    // this is a generic buffer so if user wants a
536    // terminating null, they should append it.
537    remove(1);
538
539    return nmemb;
540}
541
542/**
543 * Remove bytes from the end of this buffer
544 * @param number of bytes to be removed
545 * @return number of bytes removed.
546 */
547template<class T>
548int
549SimpleBuffer<T>::remove(int nmemb)
550{
551    if ((_nMembStored - nmemb) < 0){
552        _nMembStored = 0;
553        _pos = 0;
554    } else {
555        _nMembStored -= nmemb;
556        if (_pos >= _nMembStored) {
557            // move _pos back to the new end of the buffer.
558            _pos = _nMembStored-1;
559        }
560    }
561
562
563    return nmemb;
564}
565
566
567template<class T>
568size_t
569SimpleBuffer<T>::set(size_t nmemb)
570{
571    T *buf;
572    size_t nbytes = nmemb*sizeof(T);
573
574    if (_buf == NULL) {
575        buf = (T*) malloc(nbytes);
576    } else {
577        buf = (T*) realloc((void*) _buf, nbytes);
578    }
579
580    if (buf == NULL) {
581        fprintf(stderr,"Can't allocate %lu bytes of memory\n",
582            (long unsigned int)nbytes);
583        _fileState = false;
584        return 0;
585    }
586    _buf = buf;
587    _nMembAvl = nmemb;
588    return _nMembAvl;
589}
590
591
592template<> inline
593SimpleBuffer<char>&
594SimpleBuffer<char>::show()
595{
596    size_t curMemb = 0;
597
598    while (curMemb != _nMembStored) {
599        fprintf(stdout,"_buf[%lu] = :%c:\n", (long unsigned int)curMemb,
600                _buf[curMemb]);
601        curMemb += 1;
602    }
603    fprintf(stdout,"_nMembAvl = :%lu:\n", (long unsigned int)_nMembAvl);
604
605    return *this;
606}
607
608
609template<class T>
610SimpleBuffer<T>&
611SimpleBuffer<T>::show()
612{
613    size_t curMemb = 0;
614
615    while (curMemb != _nMembStored) {
616        fprintf(stdout,"_buf[%lu] = :%#x:\n", (long unsigned int)curMemb,
617                (unsigned long)_buf[curMemb]);
618        curMemb += 1;
619    }
620    fprintf(stdout,"_nMembAvl = :%lu:\n", (long unsigned int)_nMembAvl);
621
622    return *this;
623}
624
625
626/**
627 * Read data from the buffer into a memory location provided by caller
628 * @param Pointer locating where to place read bytes.
629 * @param Size of the memory location.
630 * @return Number of bytes written to memory location
631 */
632template<class T>
633size_t
634SimpleBuffer<T>::read(const T* bytes, size_t nmemb)
635{
636    size_t nMembRead = 0;
637
638    void* dest = NULL;
639    void const* src  = NULL;
640    size_t size = 0;
641
642    // SimpleBuffer is empty.
643    if (_buf == NULL) {
644        return 0;
645    }
646
647    // User specified NULL buffer.
648    if (bytes == NULL) {
649        return 0;
650    }
651
652    // make sure we don't read off the end of our buffer
653    if ( (_pos + nmemb) > _nMembStored ) {
654        nMembRead = _nMembStored - _pos;
655    }
656    else {
657        nMembRead = nmemb;
658    }
659
660    if (nMembRead <= 0) {
661        return 0;
662    }
663
664    dest = (void*) bytes;
665    src  = (void const*) (_buf + _pos);
666    size = nMembRead*sizeof(T);
667    memcpy(dest,src,size);
668
669    _pos = (_pos + nMembRead);
670
671    return nMembRead;
672}
673
674
675/**
676 * Set buffer position indicator to spot within the buffer
677 * @param Offset from whence location in buffer.
678 * @param Place from where offset is added or subtracted.
679 * @return 0 on success, anything else is failure
680 */
681template<class T>
682int
683SimpleBuffer<T>::seek(long offset, int whence)
684{
685    int retVal = 0;
686
687    if (_buf == NULL) {
688        return -1 ;
689    }
690
691    if (whence == SEEK_SET) {
692        if (offset < 0) {
693            /* dont go off the beginning of data */
694            _pos = 0;
695        }
696        else if (offset >= (long)_nMembStored) {
697            /* dont go off the end of data */
698            _pos = _nMembStored - 1;
699        }
700        else {
701            _pos = (size_t)(offset);
702        }
703    }
704    else if (whence == SEEK_CUR) {
705        if ( (_pos + offset) < 0) {
706            /* dont go off the beginning of data */
707            _pos = 0;
708        }
709        else if ((_pos + offset) >= _nMembStored) {
710            /* dont go off the end of data */
711            _pos = _nMembStored - 1;
712        }
713        else {
714            _pos = (size_t)(_pos + offset);
715        }
716    }
717    else if (whence == SEEK_END) {
718        if (offset <= (long)(-1*_nMembStored)) {
719            /* dont go off the beginning of data */
720            _pos = 0;
721        }
722        else if (offset >= 0) {
723            /* dont go off the end of data */
724            _pos = _nMembStored - 1;
725        }
726        else {
727            _pos = (size_t)((_nMembStored - 1) + offset);
728        }
729    }
730    else {
731        retVal = -1;
732    }
733
734    return retVal;
735}
736
737
738/**
739 * Tell caller the offset of the position indicator from the start of buffer
740 * @return Number of bytes the position indicator is from start of buffer
741 */
742template<class T>
743int
744SimpleBuffer<T>::tell() const
745{
746   return (int)_pos;
747}
748
749
750/**
751 * Read data from the buffer into a memory location provided by caller
752 */
753template<class T>
754SimpleBuffer<T>&
755SimpleBuffer<T>::rewind()
756{
757    _pos = 0;
758    return *this;
759}
760
761
762/**
763 * Tell if the last file like operation (ie. read()) was successful
764 * or if there was a failure like eof, or bad memory
765 * @return True or false boolean value
766 */
767template<class T>
768bool
769SimpleBuffer<T>::good() const
770{
771    return (_fileState);
772}
773
774
775/**
776 * Tell if the last file like operation (ie. read()) failed
777 * Opposite of good()
778 * @return True or false boolean value
779 */
780template<class T>
781bool
782SimpleBuffer<T>::bad() const
783{
784    return (!_fileState);
785}
786
787
788/**
789 * Tell if the position flag is at the end of the buffer
790 * @return True or false boolean value
791 */
792template<class T>
793bool
794SimpleBuffer<T>::eof() const
795{
796    return (_pos >= _nMembStored);
797}
798
799
800/**
801 * Move the data from this SimpleBuffer to the SimpleBuffer provided by
802 * the caller. All data except the _pos is moved and this SimpleBuffer is
803 * re-initialized with bufferInit().
804 * @param SimpleBuffer to move the information to
805 * @return reference to this SimpleBuffer object.
806 */
807template<class T>
808SimpleBuffer<T>&
809SimpleBuffer<T>::move(SimpleBuffer<T>& b)
810{
811    bufferFree();
812
813    _buf = b._buf;
814    _pos = b._pos;
815    _fileState = b._fileState;
816    _nMembStored = b._nMembStored;
817    _nMembAvl = b._nMembAvl;
818
819    b.bufferInit();
820
821    return *this;
822}
823
824
825 /**
826  *  Initializes a dynamic buffer, discarding any previous contents
827  *  of the buffer. bufferFree() should have been called already
828  *  if the dynamic buffer was previously in use.
829  */
830template<class T>
831void
832SimpleBuffer<T>::bufferInit()
833{
834    _buf = NULL;
835    _pos = 0;
836    _fileState = true;
837    _nMembStored = 0;
838    _nMembAvl = 0;
839}
840
841
842/**
843 *  Frees up any memory allocated for the dynamic buffer and
844 *  reinitializes the buffer to an empty state.
845 */
846template<class T>
847void
848SimpleBuffer<T>::bufferFree()
849{
850    if (_buf != NULL) {
851        free(_buf);
852        _buf = NULL;
853    }
854    bufferInit();
855}
856
857} // namespace Rappture
858
859#endif // RAPPTURE_SIMPLEBUFFER_H
Note: See TracBrowser for help on using the repository browser.