Listing 2: Support classes: template class MsgPart, an explicit specialization of MsgPart, class MsgPartRef, Message, and MsgExtension

#include "Listing1.h"


template <class T> class MsgPart {
public:
    //      Type definitions for convenience:
    typedef T Type;
    typedef MsgBuf::Size Size;
    typedef const T &ConstRef;
    //      Calculated current (actual from the message)
    //      and default size:
    static inline Size size (const MsgBuf &buffer, Size bufOffset)
        {return sizeof (T);}
    static inline Size defaultSize ()
        {return sizeof (T);}
    //      Assign to the object's buffer representation:
    static inline void
    assign (MsgBuf &b, Size bufOffset, ConstRef value)
        {* (T*) (b.buffer (bufOffset + sizeof (T)) + bufOffset) =
             value;}
    //      initialize the object:
    static inline void initialize (MsgBuf &b, Size bufOffset)
        {memset (b.buffer (bufOffset + sizeof (T)) + bufOffset,
                           0, sizeof (T));}
};

template <> class MsgPart <char*> {
public:
    //      Type definitions for convenience:
    typedef char *Type;
    typedef MsgBuf::Size Size;
    typedef const char *ConstRef;
    //      Calculated (actual) or default size:
    static inline Size size (const MsgBuf &buf, Size bufOffset)
    {
        const char *b = buf + bufOffset;
        void *p = memchr (b, 0, buf.length () - bufOffset);
        return p ? ((const char*) p - b + 1) : 0;
    }
    static inline Size defaultSize ()
    {
        return sizeof (char);
    }
    //      Assign to the object's buffer representation:
    static inline void
    assign (MsgBuf &b, Size bufOffset, ConstRef value)
    {
        Size s = value ? strlen (value) : 0;
        b.resizePart (bufOffset, size (b, bufOffset), s + 1);
        if (value) memcpy (b.buffer (bufOffset + s) + bufOffset,
                           value, s);
        b.buffer (bufOffset + s + 1) [bufOffset + s] = 0;
    }
    //      Initialize the object:
    static inline void initialize (MsgBuf &b, Size bufOffset)
    {
        b.buffer (bufOffset + 1) [bufOffset] = 0;
    }
};

template <class T> class MsgPartRef {
public:
    //      Convenience types:
    typedef MsgPart <T> Definition;
    typedef MsgBuf::Size Size;
private:
    //      The containing message and offset:
    MsgBuf &buffer;
    Size offset;
    //      Prevent accidental miss-use:
    MsgPartRef <T> &operator = (const MsgPartRef <T> &);
public:
    //      Ctors:
    inline MsgPartRef (MsgBuf &b, Size o)
        : buffer (b), offset (o) {}
    inline MsgPartRef (const MsgPartRef <T> &o)
        : buffer (o.buffer), offset (o.offset) {}
    //      Assignment:
    template <class A> inline MsgPartRef &operator = (A v)
        {Definition::assign (buffer, offset, v); return *this;}
    inline MsgPartRef &operator = (Definition::ConstRef v)
        {Definition::assign (buffer, offset, v); return *this;}
    //      Allow read-only use as an object of the required type:
    inline operator Definition::ConstRef () const
        {return * (T*) ((const char*) buffer + offset);}
};

class Message {
public:
    //      Convenience type:
    typedef MsgBuf::Size Size;
protected:
    //      The message buffer:
    MsgBuf buffer;
    //      Access to portions of the message,
    //      and related information:
    inline char *value (Size pos, Size s)
        {return buffer.buffer (pos + s) + pos;}
    inline const char *value (Size pos) const
        {return (const char*) buffer + pos;}
    //      The offset of this portion of the message
    //      into the buffer:
    inline Size offset () const
        {return 0;}
    //      The size of this part of the message:
    inline Size partSize (Size) const
        {return 0;}
    //      The total size of this and all previous parts
    //      of the message:
    inline Size totalSize () const
        {return 0;}
public:
    //      Ctor, taking initial size if user expects growth
    //      or if derived class knows its size (for efficiency):
    inline Message (Size initContentSize = 0)
        : buffer (initContentSize) {}
    //      Copy ctor (note message buffer is
    //      delayed-copy on write):
    inline Message (const Message &o)
        : buffer (o.buffer) {}
    //      Ctor taking a message buffer (for re-construction):
    inline Message (const MsgBuf &b)
        : buffer (b) {}
    //      Dtor not required to be virtual:
    //      derived only via MsgExtension, which has no members
    //      Get the raw message:
    Size size () const
        {return buffer.length ();}
    const char *rawData () const
        {return buffer;}
};

template <class B, class T> class MsgExtension : public B {
public:
    //      Convenience types:
    typedef MsgBuf::Size Size;
    typedef T Part;
    typedef B Base;
    typedef MsgPart <T> Definition;
private:
    //      Inline methods just to ensure parameter is
    //      calculated only once:
    inline Size calcOffset (Size p) const
        {return p + B::partSize (p);}
    inline Size calcSize (Size p) const
        {return p + partSize (p);}
protected:
    //      Calculate the offset in the message buffer
    //      of this part:
    inline Size offset () const
        {return calcOffset (B::offset ());}
    //      The size of this part:
    inline Size partSize (Size p) const
        {return Definition::size (buffer, p);}
    //      Total size of this and all previous parts:
    inline Size totalSize () const
        {return calcSize (B::totalSize ());}
public:
    //      Ctor taking initial size of 'rest' of message
    //      (ie, excluding this and preceding content):
    inline MsgExtension (Size initContentSize = 0)
        : B (initContentSize + Definition::defaultSize ())
        {Definition::initialize (buffer, offset ());}
    //      Use default assignment operator and copy ctor
    //      Ctor overlaying another message:
    inline MsgExtension (const Message &m)
        : B (m)
    {
        //      Check the overlaid message is large enough:
        if (buffer.length () < size ())
            throw "Overlaid message too small";
    }
    //      Access to the message data:
    inline MsgPartRef <T> part ()
        {return MsgPartRef <T> (buffer, offset ());}
    Definition::ConstRef part () const
        {return * (const Part*) value (offset ());}
    //      Wrappers to 'part()', use by
    //      'msg.MessageStruct::operator->()->field',
    //      or by the neater 'msg.MessageStruct::data()->field'.
    //      (data() canít return pointer to part, as this would
    //      allow direct access to variable-size parts).
    //      For 'whole' part, access by
    //      "msg.MessageStruct::part ()" These should only be
    //      instantiated when used, ie, for struct T
    inline MsgExtension <B, T> &data () {return *this;}
    inline const MsgExtension <B, T> &data () const {return *this;}
    inline Part *operator -> ()
    {
        Size o = offset ();
        return (Part*) value (o, partSize (o));
    }
    inline const Part *operator -> () const
        {return (const Part*) value (offset ());}
};
/* End of File */