00001
00009 #include <atoms/buffer.hh>
00010 #include <string.h>
00011 #include <algorithm>
00012 #include <limits>
00013 #include <boost/shared_ptr.hpp>
00014 #include <atoms/stream.hh>
00015 #include <atoms/error.hh>
00016
00017 using namespace std;
00018 using namespace boost;
00019
00020 namespace atoms {
00021
00022 size_t Buffer::MINIMUM_ALLOCATION = 1024;
00023 DebugLogger Buffer::LOGGER("org.atoms.slamb.Buffer");
00024
00025
00026 size_t Buffer::readAndAppend(Stream *s, size_t min) {
00027 assert(s != NULL);
00028 prepareForAppend(min);
00029 size_t actuallyRead = s->read(buf + limit, capacity - limit);
00030 assert(0 < actuallyRead && actuallyRead <= capacity - limit);
00031 limit += actuallyRead;
00032 return actuallyRead;
00033 }
00034
00035 void Buffer::append(const void *src, size_t n) {
00036 assert(src != NULL);
00037 prepareForAppend(n);
00038 memcpy(buf + limit, src, n);
00039 limit += n;
00040 }
00041
00042 void Buffer::replace(const void *src, size_t p, size_t n) {
00043 assert(src != NULL);
00044 assert(p <= limit - position);
00045 size_t excess = 0;
00046 if (p + n > limit - position) {
00047 excess = (p + n) - (limit - position);
00048 prepareForAppend(excess);
00049 }
00050 memcpy(buf + position + p, src, n);
00051 limit += excess;
00052 }
00053
00054 size_t Buffer::writeAndShift(Stream *s, size_t max) {
00055 assert(s != NULL);
00056 assert(limit - position >= max);
00057 size_t actuallyWritten = s->write(buf + position, max);
00058 position += actuallyWritten;
00059 return actuallyWritten;
00060 }
00061
00062 void Buffer::shift(void *dest, size_t n) {
00063 assert(limit - position >= n);
00064 if (dest != NULL)
00065 memcpy(dest, buf + position, n);
00066 position += n;
00067 }
00068
00069 size_t Buffer::truncate(size_t n) {
00070 assert(limit - position >= n);
00071 size_t numTruncated = limit - position - n;
00072 limit -= numTruncated;
00073 return numTruncated;
00074 }
00075
00076 void Buffer::prepareForAppend(size_t n) {
00077 if (!markSet)
00078 mark = position;
00079 size_t currentBytesToKeep = limit - mark;
00080 size_t bytesNeeded = currentBytesToKeep + n;
00081 if (bytesNeeded < currentBytesToKeep) {
00082
00083 throw std::bad_alloc();
00084 }
00085 if (bytesNeeded > capacity) {
00086
00087 size_t newCapacity = max(MINIMUM_ALLOCATION, capacity);
00088 if (bytesNeeded>static_cast<size_t>(numeric_limits<ssize_t>::max())) {
00089
00090
00091 throw std::bad_alloc();
00092 }
00093 while (newCapacity < bytesNeeded)
00094 newCapacity <<= 1;
00095 LOGGER.log(DebugLogger::lInfo, "Expanding buffer %p to %zu bytes",
00096 this, newCapacity);
00097 char *newBuf = reinterpret_cast<char*>(realloc(buf, newCapacity));
00098 if (newBuf == NULL)
00099 throw std::bad_alloc();
00100 buf = newBuf;
00101 capacity = newCapacity;
00102 }
00103 if (bytesNeeded > capacity - mark) {
00104
00105 memmove(buf, buf + mark, currentBytesToKeep);
00106 limit -= mark;
00107 position -= mark;
00108 mark = 0;
00109 }
00110 }
00111
00112 }