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

Last change on this file since 1427 was 1398, checked in by dkearney, 16 years ago

fixing compiler warnings about the size of the pointer. we cast the value to unsigned long, changed the format of the pointer in printf to be long

File size: 15.7 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 %zu bytes of memory\n",nbytes);
415        _fileState = false;
416        return 0;
417    }
418    _buf = buf;
419    _nMembAvl = nmemb;
420    return _nMembAvl;
421}
422
423
424template<> inline
425SimpleBuffer<char>&
426SimpleBuffer<char>::show()
427{
428    size_t curMemb = 0;
429
430    while (curMemb != _nMembStored) {
431        fprintf(stdout,"_buf[%zu] = :%c:\n", curMemb, _buf[curMemb]);
432        curMemb += 1;
433    }
434    fprintf(stdout,"_nMembAvl = :%zu:\n", _nMembAvl);
435
436    return *this;
437}
438
439
440template<class T>
441SimpleBuffer<T>&
442SimpleBuffer<T>::show()
443{
444    size_t curMemb = 0;
445
446    while (curMemb != _nMembStored) {
447        fprintf(stdout,"_buf[%zu] = :%#lx:\n", curMemb,
448            (long unsigned)_buf[curMemb]);
449        curMemb += 1;
450    }
451    fprintf(stdout,"_nMembAvl = :%zu:\n", _nMembAvl);
452
453    return *this;
454}
455
456
457/**
458 * Read data from the buffer into a memory location provided by caller
459 * @param Pointer locating where to place read bytes.
460 * @param Size of the memory location.
461 * @return Number of bytes written to memory location
462 */
463template<class T>
464size_t
465SimpleBuffer<T>::read(const T* bytes, size_t nmemb)
466{
467    size_t nMembRead = 0;
468
469    void* dest = NULL;
470    void const* src  = NULL;
471    size_t size = 0;
472
473    // SimpleBuffer is empty.
474    if (_buf == NULL) {
475        return 0;
476    }
477
478    // User specified NULL buffer.
479    if (bytes == NULL) {
480        return 0;
481    }
482
483    // make sure we don't read off the end of our buffer
484    if ( (_pos + nmemb) > _nMembStored ) {
485        nMembRead = _nMembStored - _pos;
486    }
487    else {
488        nMembRead = nmemb;
489    }
490
491    if (nMembRead <= 0) {
492        return 0;
493    }
494
495    dest = (void*) bytes;
496    src  = (void const*) (_buf + _pos);
497    size = nMembRead*sizeof(T);
498    memcpy(dest,src,size);
499
500    _pos = (_pos + nMembRead);
501
502    return nMembRead;
503}
504
505
506/**
507 * Set buffer position indicator to spot within the buffer
508 * @param Offset from whence location in buffer.
509 * @param Place from where offset is added or subtracted.
510 * @return 0 on success, anything else is failure
511 */
512template<class T>
513int
514SimpleBuffer<T>::seek(long offset, int whence)
515{
516    int retVal = 0;
517
518    if (_buf == NULL) {
519        return -1 ;
520    }
521
522    if (whence == SEEK_SET) {
523        if (offset < 0) {
524            /* dont go off the beginning of data */
525            _pos = 0;
526        }
527        else if (offset >= (long)_nMembStored) {
528            /* dont go off the end of data */
529            _pos = _nMembStored - 1;
530        }
531        else {
532            _pos = (size_t)(offset);
533        }
534    }
535    else if (whence == SEEK_CUR) {
536        if ( (_pos + offset) < 0) {
537            /* dont go off the beginning of data */
538            _pos = 0;
539        }
540        else if ((_pos + offset) >= _nMembStored) {
541            /* dont go off the end of data */
542            _pos = _nMembStored - 1;
543        }
544        else {
545            _pos = (size_t)(_pos + offset);
546        }
547    }
548    else if (whence == SEEK_END) {
549        if (offset <= (long)(-1*_nMembStored)) {
550            /* dont go off the beginning of data */
551            _pos = 0;
552        }
553        else if (offset >= 0) {
554            /* dont go off the end of data */
555            _pos = _nMembStored - 1;
556        }
557        else {
558            _pos = (size_t)((_nMembStored - 1) + offset);
559        }
560    }
561    else {
562        retVal = -1;
563    }
564
565    return retVal;
566}
567
568
569/**
570 * Tell caller the offset of the position indicator from the start of buffer
571 * @return Number of bytes the position indicator is from start of buffer
572 */
573template<class T>
574int
575SimpleBuffer<T>::tell() const
576{
577   return (int)_pos;
578}
579
580
581/**
582 * Read data from the buffer into a memory location provided by caller
583 */
584template<class T>
585SimpleBuffer<T>&
586SimpleBuffer<T>::rewind()
587{
588    _pos = 0;
589    return *this;
590}
591
592
593/**
594 * Tell if the last file like operation (ie. read()) was successful
595 * or if there was a failure like eof, or bad memory
596 * @return True or false boolean value
597 */
598template<class T>
599bool
600SimpleBuffer<T>::good() const
601{
602    return (_fileState);
603}
604
605
606/**
607 * Tell if the last file like operation (ie. read()) failed
608 * Opposite of good()
609 * @return True or false boolean value
610 */
611template<class T>
612bool
613SimpleBuffer<T>::bad() const
614{
615    return (!_fileState);
616}
617
618
619/**
620 * Tell if the position flag is at the end of the buffer
621 * @return True or false boolean value
622 */
623template<class T>
624bool
625SimpleBuffer<T>::eof() const
626{
627    return (_pos >= _nMembStored);
628}
629
630
631/**
632 * Move the data from this SimpleBuffer to the SimpleBuffer provided by
633 * the caller. All data except the _pos is moved and this SimpleBuffer is
634 * re-initialized with bufferInit().
635 * @param SimpleBuffer to move the information to
636 * @return reference to this SimpleBuffer object.
637 */
638template<class T>
639SimpleBuffer<T>&
640SimpleBuffer<T>::move(SimpleBuffer<T>& b)
641{
642    bufferFree();
643
644    _buf = b._buf;
645    _pos = b._pos;
646    _fileState = b._fileState;
647    _nMembStored = b._nMembStored;
648    _nMembAvl = b._nMembAvl;
649
650    b.bufferInit();
651
652    return *this;
653}
654
655
656 /**
657  *  Initializes a dynamic buffer, discarding any previous contents
658  *  of the buffer. bufferFree() should have been called already
659  *  if the dynamic buffer was previously in use.
660  */
661template<class T>
662void
663SimpleBuffer<T>::bufferInit()
664{
665    _buf = NULL;
666    _pos = 0;
667    _fileState = true;
668    _nMembStored = 0;
669    _nMembAvl = 0;
670}
671
672
673/**
674 *  Frees up any memory allocated for the dynamic buffer and
675 *  reinitializes the buffer to an empty state.
676 */
677template<class T>
678void
679SimpleBuffer<T>::bufferFree()
680{
681    if (_buf != NULL) {
682        free(_buf);
683        _buf = NULL;
684    }
685    bufferInit();
686}
687
688} // namespace Rappture
689
690#endif // RAPPTURE_SIMPLEBUFFER_H
Note: See TracBrowser for help on using the repository browser.