root/libbase/SimpleBuffer.h

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


// 
//   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010,
//   2011 Free Software Foundation, Inc
// 
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

#ifndef GNASH_SIMPLEBUFFER_H
#define GNASH_SIMPLEBUFFER_H


#include <boost/cstdint.hpp> // for boost::uint8_t
#include <algorithm> // for std::copy
#include <boost/scoped_array.hpp>
#include <cassert>


namespace gnash {

/// A simple buffer of bytes
//
/// This class is fully inlined and just aiming to provide RIIA
/// and unified view of memory buffers.
/// It is a kind of a std::vector with a reduced interface
/// in the intentions of the author.
///
class SimpleBuffer {

public:

        /// Construct a SimpleBuffer with an optional initial capacity
        //
        /// @param capacity
        ///     The initial buffer capacity. This is the amount of
        ///     bytes you can append to the buffer before a new reallocation
        ///     will occur.
        ///
        SimpleBuffer(size_t capacity=0)
                :
                _size(0),
                _capacity(capacity)
        {
                if ( _capacity )
                {
                        _data.reset(new boost::uint8_t[_capacity]);
                }
        }

        /// Copy constructor
        //
        /// The copy ctor will set capacity to be
        /// as small as required to hold the size of the
        /// model buffer.
        ///
        SimpleBuffer(const SimpleBuffer& b)
                :
                _size(b._size),
                _capacity(b._size)
        {
                if ( _size )
                {
                        _data.reset(new boost::uint8_t[_size]);
                        std::copy(b.data(), b.data()+b.size(), _data.get());
                }
        }

        /// Assignment operator
        //
        /// The assignment op will not reset capacity
        ///
        SimpleBuffer& operator= (const SimpleBuffer& b)
        {
                if ( this != &b )  // don't waste time on self-assignment
                {
                        resize(0); // shouldn't deallocate memory
                        append(b);
                }
                return *this;
        }

        /// Return true if buffer is empty
        bool empty() const { return _size==0; }

        /// Return size of the buffer
        size_t size() const { return _size; }

        /// Return capacity of the buffer
        size_t capacity() const { return _capacity; }

        /// Get a pointer to start of data. May be NULL if size==0.
        boost::uint8_t* data() { return _data.get(); }

        /// Get a pointer to start of data. May be NULL if size==0.
        const boost::uint8_t* data() const { return _data.get(); }

        /// Resize the buffer
        void resize(size_t newSize)
        {
                reserve(newSize); // will set capacity
                _size = newSize;
        }

        /// Ensure at least 'newCapacity' bytes are allocated for this buffer
        void reserve(size_t newCapacity)
        {
                if ( _capacity >= newCapacity ) return;

                // TODO: use smalles power of 2 bigger then newCapacity
                _capacity = std::max(newCapacity, _capacity*2);

                boost::scoped_array<boost::uint8_t> tmp;
                tmp.swap(_data);
                
                _data.reset(new boost::uint8_t[_capacity]);

                if ( tmp.get() )
                {
                        if ( _size ) std::copy(tmp.get(), tmp.get()+_size, _data.get());
                }
        }

        /// Append data to the buffer
        //
        /// The buffer will be appropriately resized to have space for
        /// the incoming data. The data will be copied.
        ///
        /// @param inData
        ///     Data to append. Will be copied.
        ///
        /// @param size
        ///     Size of data to append
        ///
        void append(const void* inData, size_t size)
        {
                const boost::uint8_t* newData = 
            reinterpret_cast<const boost::uint8_t*>(inData);
                size_t curSize = _size;
                resize(curSize+size);
                std::copy(newData, newData+size, _data.get()+curSize);
                assert(_size == curSize+size);
        }

        /// Append a byte to the buffer
        //
        /// The buffer will be appropriately resized to have space.
        ///
        /// @param b
        ///     Byte to append.
        ///
        void appendByte(const boost::uint8_t b)
        {
                resize(_size + 1);
                _data[_size - 1] = b;
        }

        /// Append 2 bytes to the buffer
        //
        /// The buffer will be appropriately resized to have space.
        ///
        /// @param s
        ///     Short to append. Will be appended in network order. ie
        ///  with high order byte first.
        ///
        void appendNetworkShort(const boost::uint16_t s)
        {
                resize(_size + 2);
                _data[_size - 2] = s >> 8;
                _data[_size - 1] = s & 0xff;
        }

        /// Append 4 bytes to the buffer
        //
        /// The buffer will be appropriately resized to have space.
        ///
        /// @param l
        ///     Long to append. Will be appended in network order. ie
        ///  with high order bytes first.
        ///
        void appendNetworkLong(const boost::uint32_t l)
        {
                resize(_size + 4);
                _data[_size - 4] = l >> 24;
                _data[_size - 3] = (l >> 16) & 0xff;
                _data[_size - 2] = (l >> 8) & 0xff;
                _data[_size - 1] = l & 0xff;
        }

        /// Append data to the buffer
        //
        /// The buffer will be appropriately resized to have space for
        /// the incoming data. The data will be copied.
        ///
        /// @param buf
        ///     SimpleBuffer containing data to append
        ///
        void append(const SimpleBuffer& buf)
        {
                size_t incomingDataSize = buf.size();
                const boost::uint8_t* incomingData = buf.data();
                append(incomingData, incomingDataSize);
        }

private:
        size_t _size;
        size_t _capacity;

        boost::scoped_array<boost::uint8_t> _data;
};


}       // namespace gnash

#endif // GNASH_SIMPLEBUFFER_H

/* [<][>][^][v][top][bottom][index][help] */