/*
* CircularByteBuffer.h
* created for Marathon: Aleph One
Copyright (C) 2003 Woody Zenfell, III
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 2 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.
This license is contained in the file "COPYING",
which is included with this source code; it is available online at
http://www.gnu.org/licenses/gpl.html
* A circular queue of bytes, with support for mass enqueueing from/peeking to caller's buffer
*
* Created by Woody Zenfell, III on Sun Jun 29 2003.
July 19, 2003 (Woody Zenfell):
Additional "NoCopy" interface may let clients avoid a copy, though it's not as safe.
*/
#ifndef CIRCULAR_BYTE_BUFFER_H
#define CIRCULAR_BYTE_BUFFER_H
#include // std::pair
#include "CircularQueue.h"
typedef CircularQueue CircularByteBufferBase;
class CircularByteBuffer : public CircularByteBufferBase
{
public:
CircularByteBuffer(unsigned int inUsableBytes) : CircularByteBufferBase(inUsableBytes) {}
// These peek and enqueue a chunk of data inByteCount long, correctly handling wraparound.
// Caller must make sure there is enough data/space available first.
void peekBytes(void* outBytes, unsigned int inByteCount);
void enqueueBytes(const void* inBytes, unsigned int inByteCount);
// These routines allow more-direct access to the buffer itself - something I'd like to
// avoid, strictly speaking, but there are so many places where it would let us skip a copy...
// Returns pointers into the buffer and the number of bytes to be taken from each.
// Caller is responsible for checking inByteCount <= getCountOfElements().
// The First and SecondByteCounts will sum to inByteCount.
// We expose both pointers and lengths at once to facilitate the use of writev()-type routines.
// *outSecondBytes == NULL && *outSecondByteCount == 0 if the second chunk is unneeded.
// Clearly, you may choose to read fewer than inByteCount bytes, as the read index is not actually advanced
// until you call dequeue().
// Any of the out-pointers may be passed as NULL if you don't care about the returned value.
void peekBytesNoCopy(unsigned int inByteCount, const void** outFirstBytes, unsigned int* outFirstByteCount,
const void** outSecondBytes, unsigned int* outSecondByteCount);
// The following two should be paired...
// Call enqueueBytesNoCopyStart(), write your bytes into the pointer, then call enqueueBytesNoCopyFinish().
// This starts an enqueueing operation: it gives you pointers into the buffer where you should
// stick data and the number of bytes that you may stick there. Caller is responsible for checking
// that inByteCount <= getRemainingSpace(). The First and SecondByteCounts will sum to inByteCount.
// We expose both pointers and lengths at once to facilitate the use of readv()-style routines.
// *outSecondBytes == NULL && *outSecondByteCount == 0 if the second chunk is unneeded.
// You may write fewer than inByteCount bytes; specify how many were actually written when
// calling enqueueBytesNoCopyFinish().
// Any of the out-pointers may be passed as NULL if you don't care about the returned value.
void enqueueBytesNoCopyStart(unsigned int inByteCount, void** outFirstBytes, unsigned int* outFirstByteCount,
void** outSecondBytes, unsigned int* outSecondByteCount);
// This finishes an enqueueing operation: you tell it how many bytes you actually enqueued.
// This cannot be rolled into the above, as proper operation for the data structure requires that
// data be written before the write index is advanced. It is legal to write fewer bytes than
// you said you planned to at the start.
void enqueueBytesNoCopyFinish(unsigned int inActualByteCount);
// Circular buffer may have incoming or outgoing data splitting across the "seam"
// so this routine returns the length of the chunk at the starting index "first" and
// the length of the chunk needed from the beginning of the buffer to satisfy inByteCount.
// (If the chunk does not need splitting, the result's first == inByteCount and second == 0.)
// This is static since it can be, basically; others clients (outside this class) could use it if they wanted to...
// I'm still not totally happy with it because it seems it'd be too easy to mix up the parameters,
// but OTOH using a structure for the parameters seems too clunky for such a simple routine...
static std::pair splitIntoChunks(unsigned int inByteCount, unsigned int inStartingIndex, unsigned int inQueueSize);
protected:
};
#endif // CIRCULAR_BYTE_BUFFER_H