string-buffer.cpp

Go to the documentation of this file.
00001 /*
00002  * string-buffer.cpp
00003  *
00004  * Copyright (C) 2010  Thomas A. Vaughan
00005  * All rights reserved.
00006  *
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are met:
00010  *     * Redistributions of source code must retain the above copyright
00011  *       notice, this list of conditions and the following disclaimer.
00012  *     * Redistributions in binary form must reproduce the above copyright
00013  *       notice, this list of conditions and the following disclaimer in the
00014  *       documentation and/or other materials provided with the distribution.
00015  *     * Neither the name of the <organization> nor the
00016  *       names of its contributors may be used to endorse or promote products
00017  *       derived from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THOMAS A. VAUGHAN ''AS IS'' AND ANY
00020  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00021  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00022  * DISCLAIMED. IN NO EVENT SHALL THOMAS A. VAUGHAN BE LIABLE FOR ANY
00023  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00024  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00025  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00026  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  *
00030  *
00031  * Implementation of a string buffer (see string-buffer.h)
00032  */
00033 
00034 // includes --------------------------------------------------------------------
00035 #include "string-buffer.h"      // always include our own header first!
00036 
00037 #include "common/wave_ex.h"     // exceptions
00038 
00039 
00040 // interface destructor implementations
00041 StringBuffer::~StringBuffer(void) throw() { }
00042 
00043 
00044 ////////////////////////////////////////////////////////////////////////////////
00045 //
00046 //      static helper methods
00047 //
00048 ////////////////////////////////////////////////////////////////////////////////
00049 
00050 
00051 ////////////////////////////////////////////////////////////////////////////////
00052 //
00053 //      SBuffer - implementation of the StringBuffer interface
00054 //
00055 ////////////////////////////////////////////////////////////////////////////////
00056 
00057 class SBuffer : public StringBuffer {
00058 public:
00059         // constructor, destructor ---------------------------------------------
00060         SBuffer(void) throw();
00061         ~SBuffer(void) throw() { }
00062 
00063         // public class methods ------------------------------------------------
00064         void initialize(IN int initialBytes);
00065 
00066         // StringBuffer class interface methods --------------------------------
00067         int appendString(IN const char * string);
00068         const char * getString(IN int offset) const throw();
00069         void getIterator(OUT iterator_t& i) const throw();
00070         const char * getNextString(IO iterator_t& i) const throw();
00071         void dumpStrings(IO std::ostream& stream) const;
00072 
00073 private:
00074         // private typedefs ----------------------------------------------------
00075         struct real_iter_t {
00076                 int     offset; // offset into buffer
00077         };
00078 
00079         // private helper methods ----------------------------------------------
00080         static real_iter_t * getRealIterator(IN iterator_t& i) throw() {
00081                         return (real_iter_t *) &i;
00082                 }
00083 
00084         // private member data -------------------------------------------------
00085         char *          m_buffer;       // raw buffer
00086         int             m_offset;       // pointer to next open spot in buffer
00087         int             m_size;         // total size of buffer (bytes)
00088 };
00089 
00090 
00091 SBuffer::SBuffer(void)
00092 throw()
00093 {
00094         m_buffer = NULL;
00095         m_offset = 0;
00096         m_size = 0;
00097 }
00098 
00099 
00100 
00101 void
00102 SBuffer::initialize
00103 (
00104 IN int initialBytes
00105 )
00106 {
00107         ASSERT(initialBytes > 0, "Bad initial bytes: %d", initialBytes);
00108 
00109         m_buffer = (char *) malloc(initialBytes);
00110         ASSERT_THROW(m_buffer, "out of memory");
00111         m_offset = 0;
00112         m_size = initialBytes;
00113 }
00114 
00115 
00116 
00117 ////////////////////////////////////////////////////////////////////////////////
00118 //
00119 //      SBuffer -- StringBuffer class interface methods
00120 //
00121 ////////////////////////////////////////////////////////////////////////////////
00122 
00123 int
00124 SBuffer::appendString
00125 (
00126 IN const char * string
00127 )
00128 {
00129         ASSERT(string, "null");
00130         int len = strlen(string);
00131 
00132         int newOffset = m_offset + len + 1;     // add one for null terminator
00133         while (newOffset >= m_size) {
00134                 // need to re-allocate buffer!
00135                 int newSize = 2 * m_size;
00136                 char * p = (char *) realloc(m_buffer, newSize);
00137                 ASSERT_THROW(p, "out of memory");
00138                 m_buffer = p;
00139                 m_size = newSize;
00140                 DPRINTF("re-allocated to new size: %d", newSize);
00141         }
00142         ASSERT(newOffset < m_size, "Should be fine now!");
00143 
00144         // copy into buffer
00145         strncpy(m_buffer + m_offset, string, len);
00146         m_buffer[m_offset + len] = 0;   // null terminate
00147         int oldOffset = m_offset;
00148         m_offset = newOffset;
00149         return oldOffset;
00150 }
00151 
00152 
00153 
00154 const char *
00155 SBuffer::getString
00156 (
00157 IN int offset
00158 )
00159 const
00160 throw()
00161 {
00162         ASSERT(m_buffer, "null");
00163         ASSERT(offset >= 0, "Bad input offset: %d", offset);
00164         ASSERT(offset < m_size, "Bad input offset: %d", offset);
00165 
00166         return m_buffer + offset;
00167 }
00168 
00169 
00170 
00171 void
00172 SBuffer::dumpStrings
00173 (
00174 IO std::ostream& stream
00175 )
00176 const
00177 {
00178         ASSERT_THROW(stream.good(), "bad stream");
00179 
00180         iterator_t i;
00181         this->getIterator(i);
00182         while (const char * p = this->getNextString(i)) {
00183                 stream << p << "\n";
00184         }
00185 }
00186 
00187 
00188 
00189 void
00190 SBuffer::getIterator
00191 (
00192 OUT iterator_t& i
00193 )
00194 const
00195 throw()
00196 {
00197         ASSERT_THROW(sizeof(iterator_t) >= sizeof(real_iter_t),
00198             "StringBuffer iterator size mismatch!  Public iterator is " <<
00199             sizeof(iterator_t) << " bytes, but the real (private) iterator is "
00200             << sizeof(real_iter_t) << " bytes.");
00201 
00202         real_iter_t * pri = getRealIterator(i);
00203         pri->offset = 0;
00204 }
00205 
00206 
00207 
00208 
00209 const char *
00210 SBuffer::getNextString
00211 (
00212 IO iterator_t& i
00213 )
00214 const
00215 throw()
00216 {
00217         real_iter_t * pri = getRealIterator(i);
00218 
00219         if (pri->offset >= m_offset) {
00220                 // at end of array!
00221                 return NULL;
00222         }
00223         const char * val = m_buffer + pri->offset;
00224         pri->offset += strlen(val) + 1;
00225         return val;
00226 }
00227 
00228 
00229 
00230 ////////////////////////////////////////////////////////////////////////////////
00231 //
00232 //      public API
00233 //
00234 ////////////////////////////////////////////////////////////////////////////////
00235 
00236 smart_ptr<StringBuffer>
00237 StringBuffer::create
00238 (
00239 IN int initialBytes
00240 )
00241 {
00242         ASSERT(initialBytes > 0, "Bad initial bytes; %d", initialBytes);
00243 
00244         smart_ptr<SBuffer> local = new SBuffer;
00245         ASSERT(local, "out of memory");
00246 
00247         local->initialize(initialBytes);
00248 
00249         return local;
00250 }
00251 
00252