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

Last change on this file since 1100 was 1100, checked in by gah, 16 years ago

assorted lang fixes

File size: 15.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
70namespace Rappture {
71
72template <class T>
73class SimpleBuffer {
74public:
75    SimpleBuffer();
76    SimpleBuffer(size_t nmemb);
77    SimpleBuffer(const T* bytes, int nmemb=-1);
78    SimpleBuffer(const SimpleBuffer& b);
79    SimpleBuffer<T>& operator=(const SimpleBuffer<T>& b);
80    SimpleBuffer     operator+(const SimpleBuffer& b) const;
81    SimpleBuffer<T>& operator+=(const SimpleBuffer<T>& b);
82    virtual ~SimpleBuffer();
83
84    const T* bytes() const;
85    size_t size() const;
86    size_t nmemb() const;
87
88    SimpleBuffer<T>& clear();
89    int append(const T* bytes, int nmemb=-1);
90    size_t read(const T* bytes, size_t nmemb);
91    int seek(long offset, int whence);
92    int tell() const;
93    size_t set(size_t nbytes);
94    SimpleBuffer<T>& rewind();
95    SimpleBuffer<T>& show();
96
97    bool good() const;
98    bool bad() const;
99    bool eof() const;
100
101    SimpleBuffer<T>& move(SimpleBuffer<T>& b);
102
103protected:
104
105    void bufferInit();
106    void bufferFree();
107
108private:
109
110    /// Pointer to the memory that holds our buffer's data
111    T* _buf;
112
113    /// Position offset within the buffer's memory
114    size_t _pos;
115
116    /// Number of members stored in the buffer
117    size_t _nMembStored;
118
119    /// Total number of members available in the buffer
120    size_t _nMembAvl;
121
122    /// State of the last file like operation.
123    bool _fileState;
124
125    /// Minimum number of members is set to the number you can fit in 256 bytes
126    const static int _minMembCnt=(256/sizeof(T));
127
128    size_t __guesslen(const T* bytes);
129
130};
131
132typedef SimpleBuffer<char>   SimpleCharBuffer;
133typedef SimpleBuffer<float>  SimpleFloatBuffer;
134typedef SimpleBuffer<double> SimpleDoubleBuffer;
135
136/**
137 * Construct an empty SimpleBuffer.
138 */
139template<class T>
140SimpleBuffer<T>::SimpleBuffer()
141{
142    bufferInit();
143}
144
145
146/**
147 * Construct an empty SimpleBuffer of specified size.
148 */
149template<class T>
150SimpleBuffer<T>::SimpleBuffer(size_t nmemb)
151{
152    bufferInit();
153
154    if (nmemb == 0) {
155        // ignore requests for sizes equal to zero
156        return;
157    }
158
159    // buffer sizes less than min_size are set to min_size
160    if (nmemb < (size_t) _minMembCnt) {
161        nmemb = _minMembCnt;
162    }
163
164    if (set(nmemb) != nmemb) {
165        return;
166    }
167    _nMembStored = nmemb;
168}
169
170
171/**
172 * Construct a SimpleBuffer loaded with initial data.
173 *
174 * @param bytes pointer to bytes being stored.
175 * @param nbytes number of bytes being stored.
176 */
177template<class T>
178SimpleBuffer<T>::SimpleBuffer(const T* bytes, int nmemb)
179{
180    bufferInit();
181    append(bytes,nmemb);
182}
183
184
185/**
186 * Copy constructor
187 * @param SimpleBuffer object to copy
188 */
189template<class T>
190SimpleBuffer<T>::SimpleBuffer(const SimpleBuffer<T>& b)
191{
192    bufferInit();
193    append(b.bytes(),b.nmemb());
194}
195
196
197/**
198 * Assignment operator
199 * @param SimpleBuffer object to copy
200 */
201template<class T>
202SimpleBuffer<T>&
203SimpleBuffer<T>::operator=(const SimpleBuffer<T>& b)
204{
205    bufferFree();
206    bufferInit();
207    append(b.bytes(),b.nmemb());
208    return *this;
209}
210
211
212/**
213 * Operator +
214 * @param SimpleBuffer object to add
215 */
216template<class T>
217SimpleBuffer<T>
218SimpleBuffer<T>::operator+(const SimpleBuffer<T>& b) const
219{
220    SimpleBuffer<T> newBuffer(*this);
221    newBuffer.operator+=(b);
222    return newBuffer;
223}
224
225
226/**
227 * Operator +=
228 * @param SimpleBuffer object to add
229 */
230template<class T>
231SimpleBuffer<T>&
232SimpleBuffer<T>::operator+=(const SimpleBuffer<T>& b)
233{
234    append(b.bytes(),b.nmemb());
235    return *this;
236}
237
238
239/**
240 * Destructor
241 */
242template<class T>
243SimpleBuffer<T>::~SimpleBuffer()
244{
245    bufferFree();
246}
247
248
249/**
250 * Get the bytes currently stored in the buffer.  These bytes can
251 * be stored, and used later to construct another Buffer to
252 * decode the information.
253 *
254 * @return Pointer to the bytes in the buffer.
255 */
256template<class T>
257const T*
258SimpleBuffer<T>::bytes() const
259{
260    return _buf;
261}
262
263
264/**
265 * Get the number of bytes currently stored in the buffer.
266 * @return Number of the bytes used in the buffer.
267 */
268template<class T>
269size_t
270SimpleBuffer<T>::size() const
271{
272    return _nMembStored*sizeof(T);
273}
274
275
276/**
277 * Get the number of members currently stored in the buffer.
278 * @return Number of the members used in the buffer.
279 */
280template<class T>
281size_t
282SimpleBuffer<T>::nmemb() const
283{
284    return _nMembStored;
285}
286
287
288/**
289 * Clear the buffer, making it empty.
290 * @return Reference to this buffer.
291 */
292template<class T>
293SimpleBuffer<T>&
294SimpleBuffer<T>::clear()
295{
296    bufferFree();
297    bufferInit();
298
299    return *this;
300}
301
302/**
303 * guess the length of a null terminated character buffer
304 * @param pointer to the buffer to guess the length of
305 * @return a guess of the length of the buffer.
306 */
307template<> inline
308size_t
309SimpleBuffer<char>::__guesslen(const char* bytes)
310{
311    return strlen(bytes);
312}
313
314/**
315 * guess the length of a non-null terminated character buffer
316 * @param pointer to the buffer to guess the length of
317 * @return a guess of the length of the buffer.
318 */
319template<class T>
320size_t
321SimpleBuffer<T>::__guesslen(const T* bytes)
322{
323    return (sizeof(T));
324}
325
326/**
327 * Append bytes to the end of this buffer
328 * @param pointer to bytes to be added
329 * @param number of bytes to be added
330 * @return number of bytes appended.
331 */
332template<class T>
333int
334SimpleBuffer<T>::append(const T* bytes, int nmemb)
335{
336    size_t newMembCnt = 0;
337    size_t nbytes = 0;
338
339    void* dest = NULL;
340    void const* src  = NULL;
341    size_t size = 0;
342
343    // User specified NULL buffer to append
344    if ( (bytes == NULL) && (nmemb < 1) ) {
345        return 0;
346    }
347
348    if (nmemb == -1) {
349        // user signaled null terminated string
350        // or that we should make an educated guess
351        // at the length of the object.
352        nbytes = __guesslen(bytes);
353        nmemb = nbytes*sizeof(T);
354    }
355
356    if (nmemb <= 0) {
357        // no data written, invalid option
358        return nmemb;
359    }
360
361    newMembCnt = (size_t)(_nMembStored + nmemb);
362
363    if (newMembCnt > _nMembAvl) {
364
365        // buffer sizes less than min_size are set to min_size
366        if (newMembCnt < (size_t) _minMembCnt) {
367            newMembCnt = (size_t) _minMembCnt;
368        }
369
370        /*
371         * Allocate a larger buffer for the string if the current one isn't
372         * large enough. Allocate extra space in the new buffer so that there
373         * will be room to grow before we have to allocate again.
374         */
375        size_t membAvl;
376        membAvl = (_nMembAvl > 0) ? _nMembAvl : _minMembCnt;
377        while (newMembCnt > membAvl) {
378            membAvl += membAvl;
379        }
380
381        /*
382         * reallocate to a larger buffer
383         */
384        if (set(membAvl) != membAvl) {
385            return 0;
386        }
387    }
388
389    dest = (void*) (_buf + _nMembStored);
390    src  = (void const*) bytes;
391    size = (size_t) (nmemb*sizeof(T));
392    memcpy(dest,src,size);
393
394    _nMembStored += nmemb;
395
396    return nmemb;
397}
398
399
400template<class T>
401size_t
402SimpleBuffer<T>::set(size_t nmemb)
403{
404    T *buf;
405    size_t nbytes = nmemb*sizeof(T);
406
407    if (_buf == NULL) {
408        buf = (T*) malloc(nbytes);
409    } else {
410        buf = (T*) realloc((void*) _buf, nbytes);
411    }
412
413    if (buf == NULL) {
414        fprintf(stderr,"Can't allocate %lu bytes of memory\n",
415            (long unsigned int)nbytes);
416        _fileState = false;
417        return 0;
418    }
419    _buf = buf;
420    _nMembAvl = nmemb;
421    return _nMembAvl;
422}
423
424
425template<> inline
426SimpleBuffer<char>&
427SimpleBuffer<char>::show()
428{
429    size_t curMemb = 0;
430
431    while (curMemb != _nMembStored) {
432        fprintf(stdout,"_buf[%lu] = :%c:\n", (long unsigned int)curMemb,
433                _buf[curMemb]);
434        curMemb += 1;
435    }
436    fprintf(stdout,"_nMembAvl = :%lu:\n", (long unsigned int)_nMembAvl);
437
438    return *this;
439}
440
441
442template<class T>
443SimpleBuffer<T>&
444SimpleBuffer<T>::show()
445{
446    size_t curMemb = 0;
447
448    while (curMemb != _nMembStored) {
449        fprintf(stdout,"_buf[%lu] = :%#x:\n", (long unsigned int)curMemb,
450                (unsigned long)_buf[curMemb]);
451        curMemb += 1;
452    }
453    fprintf(stdout,"_nMembAvl = :%lu:\n", (long unsigned int)_nMembAvl);
454
455    return *this;
456}
457
458
459/**
460 * Read data from the buffer into a memory location provided by caller
461 * @param Pointer locating where to place read bytes.
462 * @param Size of the memory location.
463 * @return Number of bytes written to memory location
464 */
465template<class T>
466size_t
467SimpleBuffer<T>::read(const T* bytes, size_t nmemb)
468{
469    size_t nMembRead = 0;
470
471    void* dest = NULL;
472    void const* src  = NULL;
473    size_t size = 0;
474
475    // SimpleBuffer is empty.
476    if (_buf == NULL) {
477        return 0;
478    }
479
480    // User specified NULL buffer.
481    if (bytes == NULL) {
482        return 0;
483    }
484
485    // make sure we don't read off the end of our buffer
486    if ( (_pos + nmemb) > _nMembStored ) {
487        nMembRead = _nMembStored - _pos;
488    }
489    else {
490        nMembRead = nmemb;
491    }
492
493    if (nMembRead <= 0) {
494        return 0;
495    }
496
497    dest = (void*) bytes;
498    src  = (void const*) (_buf + _pos);
499    size = nMembRead*sizeof(T);
500    memcpy(dest,src,size);
501
502    _pos = (_pos + nMembRead);
503
504    return nMembRead;
505}
506
507
508/**
509 * Set buffer position indicator to spot within the buffer
510 * @param Offset from whence location in buffer.
511 * @param Place from where offset is added or subtracted.
512 * @return 0 on success, anything else is failure
513 */
514template<class T>
515int
516SimpleBuffer<T>::seek(long offset, int whence)
517{
518    int retVal = 0;
519
520    if (_buf == NULL) {
521        return -1 ;
522    }
523
524    if (whence == SEEK_SET) {
525        if (offset < 0) {
526            /* dont go off the beginning of data */
527            _pos = 0;
528        }
529        else if (offset >= (long)_nMembStored) {
530            /* dont go off the end of data */
531            _pos = _nMembStored - 1;
532        }
533        else {
534            _pos = (size_t)(offset);
535        }
536    }
537    else if (whence == SEEK_CUR) {
538        if ( (_pos + offset) < 0) {
539            /* dont go off the beginning of data */
540            _pos = 0;
541        }
542        else if ((_pos + offset) >= _nMembStored) {
543            /* dont go off the end of data */
544            _pos = _nMembStored - 1;
545        }
546        else {
547            _pos = (size_t)(_pos + offset);
548        }
549    }
550    else if (whence == SEEK_END) {
551        if (offset <= (long)(-1*_nMembStored)) {
552            /* dont go off the beginning of data */
553            _pos = 0;
554        }
555        else if (offset >= 0) {
556            /* dont go off the end of data */
557            _pos = _nMembStored - 1;
558        }
559        else {
560            _pos = (size_t)((_nMembStored - 1) + offset);
561        }
562    }
563    else {
564        retVal = -1;
565    }
566
567    return retVal;
568}
569
570
571/**
572 * Tell caller the offset of the position indicator from the start of buffer
573 * @return Number of bytes the position indicator is from start of buffer
574 */
575template<class T>
576int
577SimpleBuffer<T>::tell() const
578{
579   return (int)_pos;
580}
581
582
583/**
584 * Read data from the buffer into a memory location provided by caller
585 */
586template<class T>
587SimpleBuffer<T>&
588SimpleBuffer<T>::rewind()
589{
590    _pos = 0;
591    return *this;
592}
593
594
595/**
596 * Tell if the last file like operation (ie. read()) was successful
597 * or if there was a failure like eof, or bad memory
598 * @return True or false boolean value
599 */
600template<class T>
601bool
602SimpleBuffer<T>::good() const
603{
604    return (_fileState);
605}
606
607
608/**
609 * Tell if the last file like operation (ie. read()) failed
610 * Opposite of good()
611 * @return True or false boolean value
612 */
613template<class T>
614bool
615SimpleBuffer<T>::bad() const
616{
617    return (!_fileState);
618}
619
620
621/**
622 * Tell if the position flag is at the end of the buffer
623 * @return True or false boolean value
624 */
625template<class T>
626bool
627SimpleBuffer<T>::eof() const
628{
629    return (_pos >= _nMembStored);
630}
631
632
633/**
634 * Move the data from this SimpleBuffer to the SimpleBuffer provided by
635 * the caller. All data except the _pos is moved and this SimpleBuffer is
636 * re-initialized with bufferInit().
637 * @param SimpleBuffer to move the information to
638 * @return reference to this SimpleBuffer object.
639 */
640template<class T>
641SimpleBuffer<T>&
642SimpleBuffer<T>::move(SimpleBuffer<T>& b)
643{
644    bufferFree();
645
646    _buf = b._buf;
647    _pos = b._pos;
648    _fileState = b._fileState;
649    _nMembStored = b._nMembStored;
650    _nMembAvl = b._nMembAvl;
651
652    b.bufferInit();
653
654    return *this;
655}
656
657
658 /**
659  *  Initializes a dynamic buffer, discarding any previous contents
660  *  of the buffer. bufferFree() should have been called already
661  *  if the dynamic buffer was previously in use.
662  */
663template<class T>
664void
665SimpleBuffer<T>::bufferInit()
666{
667    _buf = NULL;
668    _pos = 0;
669    _fileState = true;
670    _nMembStored = 0;
671    _nMembAvl = 0;
672}
673
674
675/**
676 *  Frees up any memory allocated for the dynamic buffer and
677 *  reinitializes the buffer to an empty state.
678 */
679template<class T>
680void
681SimpleBuffer<T>::bufferFree()
682{
683    if (_buf != NULL) {
684        free(_buf);
685        _buf = NULL;
686    }
687    bufferInit();
688}
689
690} // namespace Rappture
691
692#endif // RAPPTURE_SIMPLEBUFFER_H
Note: See TracBrowser for help on using the repository browser.