root/headers/private/net/NetBufferUtilities.h
/*
 * Copyright 2006-2010, Haiku, Inc. All Rights Reserved.
 * Distributed under the terms of the MIT License.
 */
#ifndef NET_BUFFER_UTILITIES_H
#define NET_BUFFER_UTILITIES_H


#include <net_buffer.h>
#include <AutoDeleter.h>


extern net_buffer_module_info* gBufferModule;


class NetBufferModuleGetter {
        public:
                static net_buffer_module_info *Get() { return gBufferModule; }
};


//! A class to access a field safely across node boundaries
template<typename Type, int Offset, typename Module = NetBufferModuleGetter>
class NetBufferFieldReader {
public:
        NetBufferFieldReader(net_buffer* buffer)
                :
                fBuffer(buffer)
        {
                fStatus = Module::Get()->direct_access(fBuffer, Offset, sizeof(Type),
                        (void**)&fData);
                if (fStatus != B_OK) {
                        fStatus = Module::Get()->read(fBuffer, Offset, &fDataBuffer,
                                sizeof(Type));
                        fData = &fDataBuffer;
                }
        }

        status_t Status() const
        {
                return fStatus;
        }

        Type& Data() const
        {
                return *fData;
        }

        Type* operator->() const
        {
                return fData;
        }

        Type& operator*() const
        {
                return *fData;
        }

        void Sync()
        {
                if (fBuffer == NULL || fStatus < B_OK)
                        return;

                if (fData == &fDataBuffer)
                        Module::Get()->write(fBuffer, Offset, fData, sizeof(Type));

                fBuffer = NULL;
        }

protected:
        NetBufferFieldReader()
        {
        }

        net_buffer*     fBuffer;
        status_t        fStatus;
        Type*           fData;
        Type            fDataBuffer;
};


//! Writes back any changed data on destruction
template<typename Type, int Offset, typename Module = NetBufferModuleGetter>
class NetBufferField : public NetBufferFieldReader<Type, Offset, Module> {
public:
        NetBufferField(net_buffer* buffer)
                :
                NetBufferFieldReader<Type, Offset, Module>(buffer)
        {
        }

        ~NetBufferField()
        {
                // Note, "this->" is needed here for GCC4
                this->Sync();
        }
};


//! Can remove the header from the buffer
template<typename Type, typename Module = NetBufferModuleGetter>
class NetBufferHeaderReader : public NetBufferFieldReader<Type, 0, Module> {
public:
        NetBufferHeaderReader(net_buffer* buffer)
                :
                NetBufferFieldReader<Type, 0, Module>(buffer)
        {
        }

        void Remove()
        {
                Remove(sizeof(Type));
        }

        void Remove(size_t bytes)
        {
                if (this->fBuffer != NULL) {
                        Module::Get()->remove_header(this->fBuffer, bytes);
                        this->fBuffer = NULL;
                }
        }
};


//!     Removes the header on destruction
template<typename Type, typename Module = NetBufferModuleGetter>
class NetBufferHeaderRemover : public NetBufferHeaderReader<Type, Module> {
public:
        NetBufferHeaderRemover(net_buffer* buffer)
                :
                NetBufferHeaderReader<Type, Module>(buffer)
        {
        }

        ~NetBufferHeaderRemover()
        {
                this->Remove();
        }
};


//! A class to add a header to a buffer, syncs itself on destruction
template<typename Type, typename Module = NetBufferModuleGetter>
class NetBufferPrepend : public NetBufferFieldReader<Type, 0, Module> {
public:
        NetBufferPrepend(net_buffer* buffer, size_t size = sizeof(Type))
        {
                this->fBuffer = buffer;

                this->fStatus = Module::Get()->prepend_size(buffer, size,
                        (void**)&this->fData);
                if (this->fStatus == B_OK && this->fData == NULL)
                        this->fData = &this->fDataBuffer;
        }

        ~NetBufferPrepend()
        {
                this->Sync();
        }
};


//! A class to automatically delete buffers on scope exit
template<typename Module>
struct NetBufferDelete
{
        inline void operator()(net_buffer* buffer)
        {
                if (buffer != NULL)
                        Module::Get()->free(buffer);
        }
};


template<typename Module = NetBufferModuleGetter>
struct NetBufferDeleter
        : BPrivate::AutoDeleter<net_buffer, NetBufferDelete<Module> >
{
        NetBufferDeleter(net_buffer* buffer)
                : BPrivate::AutoDeleter<net_buffer, NetBufferDelete<Module> >(buffer)
        {}
};



#endif  // NET_BUFFER_UTILITIES_H