summaryrefslogtreecommitdiff
path: root/indra/llcorehttp/bufferarray.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcorehttp/bufferarray.cpp')
-rw-r--r--indra/llcorehttp/bufferarray.cpp281
1 files changed, 281 insertions, 0 deletions
diff --git a/indra/llcorehttp/bufferarray.cpp b/indra/llcorehttp/bufferarray.cpp
new file mode 100644
index 0000000000..4c20350b13
--- /dev/null
+++ b/indra/llcorehttp/bufferarray.cpp
@@ -0,0 +1,281 @@
+/**
+ * @file bufferarray.cpp
+ * @brief Implements the BufferArray scatter/gather buffer
+ *
+ * $LicenseInfo:firstyear=2012&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2012, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "bufferarray.h"
+
+
+namespace LLCore
+{
+
+
+// ==================================
+// BufferArray::Block Declaration
+// ==================================
+
+class BufferArray::Block
+{
+public:
+ ~Block();
+
+ void operator delete(void *);
+ void operator delete(void *, size_t len);
+
+protected:
+ Block(size_t len);
+
+ Block(const Block &); // Not defined
+ void operator=(const Block &); // Not defined
+
+ // Allocate the block with the additional space for the
+ // buffered data at the end of the object.
+ void * operator new(size_t len, size_t addl_len);
+
+public:
+ // Only public entry to get a block.
+ static Block * alloc(size_t len);
+
+public:
+ size_t mLen;
+
+ // *NOTE: Must be last member of the object. We'll
+ // overallocate as requested via operator new and index
+ // into the array at will.
+ char mData[1];
+};
+
+
+// ==================================
+// BufferArray Definitions
+// ==================================
+
+
+BufferArray::BufferArray()
+ : LLCoreInt::RefCounted(true),
+ mPos(0),
+ mLen(0)
+{}
+
+
+BufferArray::~BufferArray()
+{
+ for (container_t::iterator it(mBlocks.begin());
+ it != mBlocks.end();
+ ++it)
+ {
+ delete *it;
+ *it = NULL;
+ }
+ mBlocks.clear();
+}
+
+
+size_t BufferArray::append(const char * src, size_t len)
+{
+ if (len)
+ {
+ if (mBlocks.size() >= mBlocks.capacity())
+ {
+ mBlocks.reserve(mBlocks.size() + 5);
+ }
+ Block * block = Block::alloc(len);
+ memcpy(block->mData, src, len);
+ mBlocks.push_back(block);
+ mLen += len;
+ mPos = mLen;
+ }
+ return len;
+}
+
+
+char * BufferArray::appendBufferAlloc(size_t len)
+{
+ // If someone asks for zero-length, we give them a valid pointer.
+ if (mBlocks.size() >= mBlocks.capacity())
+ {
+ mBlocks.reserve(mBlocks.size() + 5);
+ }
+ Block * block = Block::alloc(len);
+ mBlocks.push_back(block);
+ mLen += len;
+ mPos = mLen;
+ return block->mData;
+}
+
+
+size_t BufferArray::seek(size_t pos)
+{
+ if (pos > mLen)
+ pos = mLen;
+ mPos = pos;
+ return mPos;
+}
+
+
+size_t BufferArray::read(char * dst, size_t len)
+{
+ size_t result(0), offset(0);
+ size_t len_limit(mLen - mPos);
+ len = std::min(len, len_limit);
+
+ if (mPos >= mLen || 0 == len)
+ return 0;
+
+ const int block_limit(mBlocks.size());
+ int block_start(findBlock(mPos, &offset));
+ if (block_start < 0)
+ return 0;
+
+ do
+ {
+ Block & block(*mBlocks[block_start]);
+ size_t block_limit(block.mLen - offset);
+ size_t block_len(std::min(block_limit, len));
+
+ memcpy(dst, &block.mData[offset], block_len);
+ result += block_len;
+ len -= block_len;
+ dst += block_len;
+ offset = 0;
+ ++block_start;
+ }
+ while (len && block_start < block_limit);
+
+ mPos += result;
+ return result;
+}
+
+
+size_t BufferArray::write(const char * src, size_t len)
+{
+ size_t result(0), offset(0);
+ if (mPos > mLen || 0 == len)
+ return 0;
+
+ const int block_limit(mBlocks.size());
+ int block_start(findBlock(mPos, &offset));
+
+ if (block_start >= 0)
+ {
+ // Some or all of the write will be on top of
+ // existing data.
+ do
+ {
+ Block & block(*mBlocks[block_start]);
+ size_t block_limit(block.mLen - offset);
+ size_t block_len(std::min(block_limit, len));
+
+ memcpy(&block.mData[offset], src, block_len);
+ result += block_len;
+ len -= block_len;
+ src += block_len;
+ offset = 0;
+ ++block_start;
+ }
+ while (len && block_start < block_limit);
+ }
+ mPos += result;
+
+ if (len)
+ {
+ // Some or all of the remaining write data will
+ // be an append.
+ result += append(src, len);
+ }
+
+ return result;
+}
+
+
+int BufferArray::findBlock(size_t pos, size_t * ret_offset)
+{
+ *ret_offset = 0;
+ if (pos >= mLen)
+ return -1; // Doesn't exist
+
+ const int block_limit(mBlocks.size());
+ for (int i(0); i < block_limit; ++i)
+ {
+ if (pos < mBlocks[i]->mLen)
+ {
+ *ret_offset = pos;
+ return i;
+ }
+ pos -= mBlocks[i]->mLen;
+ }
+
+ // Shouldn't get here but...
+ return -1;
+}
+
+
+// ==================================
+// BufferArray::Block Definitions
+// ==================================
+
+
+BufferArray::Block::Block(size_t len)
+ : mLen(len)
+{
+ memset(mData, 0, len);
+}
+
+
+BufferArray::Block::~Block()
+{
+ mLen = 0;
+}
+
+
+void * BufferArray::Block::operator new(size_t len, size_t addl_len)
+{
+ void * mem = new char[len + addl_len + sizeof(void *)];
+ return mem;
+}
+
+
+void BufferArray::Block::operator delete(void * mem)
+{
+ char * cmem = static_cast<char *>(mem);
+ delete [] cmem;
+}
+
+
+void BufferArray::Block::operator delete(void * mem, size_t)
+{
+ operator delete(mem);
+}
+
+
+BufferArray::Block * BufferArray::Block::alloc(size_t len)
+{
+ Block * block = new (len) Block(len);
+ return block;
+}
+
+
+} // end namespace LLCore
+
+