/* * CircularByteBuffer.cpp * 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. */ #include "cseries.h" // assert() #include "CircularByteBuffer.h" #include // std::min() // static std::pair CircularByteBuffer::splitIntoChunks(unsigned int inByteCount, unsigned int inStartingIndex, unsigned int inQueueSize) { // Copy, potentially, two separate chunks (one at end of buffer; one at beginning) unsigned int theSpaceAtEndOfBuffer = inQueueSize - inStartingIndex; unsigned int theFirstChunkSize = std::min(inByteCount, theSpaceAtEndOfBuffer); unsigned int theSecondChunkSize = inByteCount - theFirstChunkSize; return std::pair(theFirstChunkSize, theSecondChunkSize); } void CircularByteBuffer::enqueueBytes(const void* inBytes, unsigned int inByteCount) { // I believe everything works right without this check, but it makes me feel safer anyway. if(inByteCount > 0) { assert(inByteCount <= getRemainingSpace()); const char* theBytes = static_cast(inBytes); std::pair theChunkSizes = splitIntoChunks(inByteCount, mWriteIndex, mQueueSize); memcpy(&(mData[mWriteIndex]), theBytes, theChunkSizes.first); if(theChunkSizes.second > 0) memcpy(mData, &(theBytes[theChunkSizes.first]), theChunkSizes.second); advanceWriteIndex(inByteCount); } } void CircularByteBuffer::enqueueBytesNoCopyStart(unsigned int inByteCount, void** outFirstBytes, unsigned int* outFirstByteCount, void** outSecondBytes, unsigned int* outSecondByteCount) { void* theFirstBytes = NULL; void* theSecondBytes = NULL; unsigned int theFirstByteCount = 0; unsigned int theSecondByteCount = 0; if(inByteCount > 0) { assert(inByteCount <= getRemainingSpace()); std::pair theChunkSizes = splitIntoChunks(inByteCount, mWriteIndex, mQueueSize); theFirstBytes = &(mData[getWriteIndex()]); theFirstByteCount = theChunkSizes.first; theSecondByteCount = theChunkSizes.second; theSecondBytes = (theSecondByteCount > 0) ? mData : NULL; } if(outFirstBytes != NULL) *outFirstBytes = theFirstBytes; if(outFirstByteCount != NULL) *outFirstByteCount = theFirstByteCount; if(outSecondBytes != NULL) *outSecondBytes = theSecondBytes; if(outSecondByteCount != NULL) *outSecondByteCount = theSecondByteCount; } void CircularByteBuffer::enqueueBytesNoCopyFinish(unsigned int inActualByteCount) { if(inActualByteCount > 0) advanceWriteIndex(inActualByteCount); } void CircularByteBuffer::peekBytes(void* outBytes, unsigned int inByteCount) { // I believe everything works right without this check, but it makes me feel safer anyway. if(inByteCount > 0) { assert(inByteCount <= getCountOfElements()); char* theBytes = static_cast(outBytes); std::pair theChunkSizes = splitIntoChunks(inByteCount, mReadIndex, mQueueSize); memcpy(theBytes, &(mData[mReadIndex]), theChunkSizes.first); if(theChunkSizes.second > 0) memcpy(&(theBytes[theChunkSizes.first]), mData, theChunkSizes.second); } } void CircularByteBuffer::peekBytesNoCopy(unsigned int inByteCount, const void** outFirstBytes, unsigned int* outFirstByteCount, const void** outSecondBytes, unsigned int* outSecondByteCount) { void* theFirstBytes = NULL; void* theSecondBytes = NULL; unsigned int theFirstByteCount = 0; unsigned int theSecondByteCount = 0; if(inByteCount > 0) { assert(inByteCount <= getCountOfElements()); std::pair theChunkSizes = splitIntoChunks(inByteCount, mReadIndex, mQueueSize); theFirstBytes = &(mData[getReadIndex()]); theFirstByteCount = theChunkSizes.first; theSecondByteCount = theChunkSizes.second; theSecondBytes = (theSecondByteCount > 0) ? mData : NULL; } if(outFirstBytes != NULL) *outFirstBytes = theFirstBytes; if(outFirstByteCount != NULL) *outFirstByteCount = theFirstByteCount; if(outSecondBytes != NULL) *outSecondBytes = theSecondBytes; if(outSecondByteCount != NULL) *outSecondByteCount = theSecondByteCount; }