#ifndef _H_BUFFER
#define _H_BUFFER
#include <security_utilities/utilities.h>
#include <cstdarg>
#include <limits.h>
namespace Security {
class Buffer {
public:
Buffer(size_t size); ~Buffer();
static Buffer reader(void *base, size_t size, bool owned = false)
{ return Buffer(base, size, true, owned); }
static Buffer writer(void *base, size_t size, bool owned = false)
{ return Buffer(base, size, false, owned); }
size_t available(bool heavy = false) const
{ return heavy ? ((mTop - mEnd) + (mStart - mBase)): (mTop - mEnd); }
bool isFull(bool heavy = false) const
{ return heavy ? (mEnd == mTop && mStart == mBase) : (mEnd == mTop); }
bool isEmpty() const { return mStart == mEnd; }
size_t length() const { return mEnd - mStart; }
void *data() { assert(mStart == mBase); return mStart; }
void clear() { mStart = mEnd = mBase; }
protected:
Buffer(void *base, size_t size, bool filled, bool owned = false);
size_t shuffle(size_t needed = UINT_MAX);
void adjustGet()
{
if (isEmpty()) mStart = mEnd = mBase;
}
public:
size_t put(const void *data, size_t length)
{
if (length > available())
length = shuffle(length);
memcpy(mEnd, data, length);
mEnd += length;
return length;
}
template <class T> void locatePut(T * &addr, size_t &length)
{
if (length > available())
length = shuffle(length);
addr = reinterpret_cast<T *>(mEnd);
}
void usePut(size_t length)
{
assert(length <= available());
mEnd += length;
}
template <class T> void locateGet(T * &addr, size_t &length)
{
if (length > size_t(mEnd - mStart))
length = mEnd - mStart;
addr = reinterpret_cast<T *>(mStart);
}
void useGet(size_t length)
{
assert(length <= this->length());
mStart += length;
adjustGet();
}
template <class IO>
size_t read(IO &io, size_t length)
{
if (length > available())
length = shuffle(length);
size_t bytesRead = io.read(mEnd, length);
mEnd += bytesRead;
return bytesRead;
}
template <class IO>
size_t write(IO &io, size_t length)
{
length = min(this->length(), length);
size_t bytesWritten = io.write(mStart, length);
mStart += bytesWritten;
adjustGet();
return bytesWritten;
}
template <class IO> size_t read(IO &io, bool heavy = false)
{ return read(io, available(heavy)); }
template <class IO> size_t write(IO &io)
{ return write(io, length()); }
void printf(const char *format, ...);
void vprintf(const char *format, va_list args);
void own() { mOwningMemory = true; }
private:
char *const mBase; char *const mTop; char *mStart; char *mEnd; bool mOwningMemory; };
}
#endif //_H_BUFFER