PagedBuffer.h

// PagedBuffer.h
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2004

#pragma once
#ifndef Ceda_cxUtils_PagedBuffer_H
#define Ceda_cxUtils_PagedBuffer_H

#include "cxUtils.h"
#include "xvector.h"
#include "xstring.h"
#include "Archive.h"
#include "VariableLengthSerialise.h"

#ifdef _MSC_VER
    // struct 'X' needs to have dll-interface to be used by clients of class 'Y'
    #pragma warning(disable:4251)
#endif

namespace ceda
{
class xostream;

///////////////////////////////////////////////////////////////////////////////////////////////////
// PagedBuffer

class cxUtils_API PagedBuffer
{
private:
    typedef octet_t Page;

public:
    explicit PagedBuffer(ssize_t pageSize = 4096);
    ~PagedBuffer();

    PagedBuffer(const PagedBuffer& other);
    PagedBuffer& operator=(const PagedBuffer& other);
    
    bool operator==(const PagedBuffer& rhs) const;
    bool operator!=(const PagedBuffer& rhs) const { return !operator==(rhs); }

    void Clear();

    void swap(PagedBuffer& rhs);

    ssize_t size() const { return m_totalSize; }
    ssize_t GetSize() const { return m_totalSize; }

    // Set the current write position.
    // If necessary the size of the PagedBuffer will grow (padded with zeros) to accommodate the 
    // given write position.
    // If truncateToWritePos is set and the current size of this PagedBuffer exceeds the given 
    // write position then this PagedBuffer is truncated to the given write position.
    void SetWritePos(ssize_t pos, bool truncateToWritePos);

    // Write the given buffer at the current write position.  
    // If necessary the size of this PagedBuffer will grow to accommodate the given data.
    // The write position is advanced by the given number of bytes.
    void Write(const void* buffer, ssize_t numBytes);
    
    // Write the contents of the PagedBuffer to the given buffer
    void WriteTo(octet_t* buffer) const;

    // Write the sequence of octets in this PagedBuffer to the given IOutputStream.
    void WriteTo(IOutputStream& os) const;

    // Write the sequence of octets in this PagedBuffer to the given xvector<octet_t>.
    void WriteTo(xvector<octet_t>& b) const;

    // Write the sequence of octets in this PagedBuffer to the given Archive.
    template<typename Archive>
    void WriteContent(Archive& ar) const
    {
        const ssize_t last = m_numPages - 1;      // index of the last page
        if (last >= 0)
        {
            for (ssize_t i=0 ; i < last ; ++i)
            {
                ar.WriteBuffer(m_pages[i],m_pageSize); 
            }
            const ssize_t x = m_totalSize - last*m_pageSize;
            cxAssert(1 <= x && x <= m_pageSize);
            ar.WriteBuffer(m_pages[last],x);
        }
    }

    template<typename Archive>
    void Serialise(Archive& ar) const
    {
        ar << AsCompressedInt(size());
        WriteContent(ar);
    }

    void Deserialise(InputArchive& ar);

    void GetString(xstring& s);

    class cxUtils_API Reader
    {
        cxNotCloneable(Reader)
    public:
        // Note that it is permissible for a PagedBuffer::Reader to bind to its PageBuffer before data has
        // been written to the PagedBuffer.
        Reader(const PagedBuffer& pb);

        ssize_t GetPos() const;
        void SetPos(ssize_t pos);
        ssize_t Read(void* buffer, ssize_t numBytes);

    private:
        const PagedBuffer& m_pb;
        ssize_t m_pageIndex;
        const Page* m_rpage;    // Current page being read
        ssize_t m_rpos;         // Position within current page
        ssize_t m_overallPos;   // Overall position
    };

private:
    void CopyFrom(const PagedBuffer& other);

    // Set new size without regard for the current write position
    void SetSize(ssize_t size);

#ifdef CEDA_CHECK_ASSERTIONS
    void Validate() const;
#endif

private:
    typedef xvector<Page*> PAGES;

    ssize_t m_pageSize;
    PAGES m_pages;
    ssize_t m_numPages;
    ssize_t m_totalSize;
    ssize_t m_writePos;         // Current write position in range [0,m_totalSize]

    friend class Reader;
};

cxUtils_API void DumpPagedBuffer(xostream& os, ssize_t numPerLine, const PagedBuffer& pb);
cxUtils_API xostream& operator<<(xostream& os, const PagedBuffer& pb);

} // namespace ceda

#endif // include guard