/** * Copyright 2003-2006 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef INPUTSTREAMBUFFER_H #define INPUTSTREAMBUFFER_H #include namespace jstreams { template class InputStreamBuffer { private: public: T* start; int32_t size; T* readPos; int32_t avail; T* markPos; int32_t markLimit; InputStreamBuffer(); ~InputStreamBuffer(); void setSize(int32_t size); void mark(int32_t readlimit); void reset(); int32_t read(const T*& start, int32_t max=0); /** * This function prepares the buffer for a new write. * returns the number of available places. **/ int32_t makeSpace(int32_t needed); }; template InputStreamBuffer::InputStreamBuffer() { markPos = readPos = start = 0; size = avail = 0; } template InputStreamBuffer::~InputStreamBuffer() { free(start); } template void InputStreamBuffer::setSize(int32_t size) { // store pointer information int32_t offset = readPos - start; int32_t markOffset = (markPos) ? markPos - start : -1; // allocate memory in the buffer start = (T*)realloc(start, size*sizeof(T)); this->size = size; // restore pointer information readPos = start + offset; markPos = (markOffset == -1) ?0 :start + markOffset; } template void InputStreamBuffer::mark(int32_t limit) { // if there's no buffer yet, allocate one now if (start == 0) { setSize(limit+1); } // if we had a larger limit defined for the same position, do nothing if (readPos == markPos && limit <= markLimit) { return; } markLimit = limit; // if we have enough room, only set the mark int32_t offset = readPos - start; if (size - offset >= limit) { markPos = readPos; return; } // if we don't have enough room start by // moving memory to the start of the buffer if (readPos != start) { memmove(start, readPos, avail*sizeof(T)); readPos = start; } // if we have enough room now, finish if (size >= limit) { markPos = readPos; return; } // last resort: increase buffer size setSize(limit+1); markPos = readPos; } template void InputStreamBuffer::reset() { if (markPos != 0) { avail += readPos - markPos; readPos = markPos; } } template int32_t InputStreamBuffer::makeSpace(int32_t needed) { // determine how much space is available for writing int32_t space = size - (readPos - start) - avail; if (space >= needed) { // there's enough space return space; } if (markPos && readPos - markPos <= markLimit) { // move data to the start of the buffer while respecting the set mark if (markPos != start) { // printf("moving with mark\n"); int32_t n = avail + readPos - markPos; memmove(start, markPos, n*sizeof(T)); readPos -= markPos - start; space += markPos - start; markPos = start; } } else if (avail) { if (readPos != start) { // printf("moving\n"); // move data to the start of the buffer memmove(start, readPos, avail*sizeof(T)); space += readPos - start; readPos = start; markPos = 0; } } else { // we may start writing at the start of the buffer markPos = 0; readPos = start; space = size; } if (space >= needed) { // there's enough space now return space; } // still not enough space, we have to allocate more // printf("resize %i %i %i %i %i\n", avail, needed, space, size + needed - space, size); setSize(size + needed - space); return needed; } template int32_t InputStreamBuffer::read(const T*& start, int32_t max) { start = readPos; if (max <= 0 || max > avail) { max = avail; } readPos += max; avail -= max; return max; } } // end namespace jstreams #endif