diff options
Diffstat (limited to 'WebCore/platform/SharedBuffer.cpp')
-rw-r--r-- | WebCore/platform/SharedBuffer.cpp | 139 |
1 files changed, 132 insertions, 7 deletions
diff --git a/WebCore/platform/SharedBuffer.cpp b/WebCore/platform/SharedBuffer.cpp index 4a0d0f3..4a46c2c 100644 --- a/WebCore/platform/SharedBuffer.cpp +++ b/WebCore/platform/SharedBuffer.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. + * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,30 +29,60 @@ #include "PurgeableBuffer.h" +using namespace std; + namespace WebCore { +static const unsigned segmentSize = 0x1000; +static const unsigned segmentPositionMask = 0x0FFF; + +static inline unsigned segmentIndex(unsigned position) +{ + return position / segmentSize; +} + +static inline unsigned offsetInSegment(unsigned position) +{ + return position & segmentPositionMask; +} + +static inline char* allocateSegment() +{ + return static_cast<char*>(fastMalloc(segmentSize)); +} + +static inline void freeSegment(char* p) +{ + fastFree(p); +} + SharedBuffer::SharedBuffer() + : m_size(0) { } SharedBuffer::SharedBuffer(const char* data, int size) + : m_size(0) { - m_buffer.append(data, size); + append(data, size); } SharedBuffer::SharedBuffer(const unsigned char* data, int size) + : m_size(0) { - m_buffer.append(data, size); + append(reinterpret_cast<const char*>(data), size); } SharedBuffer::~SharedBuffer() { + clear(); } PassRefPtr<SharedBuffer> SharedBuffer::adoptVector(Vector<char>& vector) { RefPtr<SharedBuffer> buffer = create(); buffer->m_buffer.swap(vector); + buffer->m_size = buffer->m_buffer.size(); return buffer.release(); } @@ -71,7 +102,7 @@ unsigned SharedBuffer::size() const if (m_purgeableBuffer) return m_purgeableBuffer->size(); - return m_buffer.size(); + return m_size; } const char* SharedBuffer::data() const @@ -82,29 +113,75 @@ const char* SharedBuffer::data() const if (m_purgeableBuffer) return m_purgeableBuffer->data(); - return m_buffer.data(); + return buffer().data(); } -void SharedBuffer::append(const char* data, int len) +void SharedBuffer::append(const char* data, unsigned length) { ASSERT(!m_purgeableBuffer); maybeTransferPlatformData(); - m_buffer.append(data, len); + unsigned positionInSegment = offsetInSegment(m_size - m_buffer.size()); + m_size += length; + + if (m_size <= segmentSize) { + // No need to use segments for small resource data + m_buffer.append(data, length); + return; + } + + char* segment; + if (!positionInSegment) { + segment = allocateSegment(); + m_segments.append(segment); + } else + segment = m_segments.last() + positionInSegment; + + unsigned segmentFreeSpace = segmentSize - positionInSegment; + unsigned bytesToCopy = min(length, segmentFreeSpace); + + for (;;) { + memcpy(segment, data, bytesToCopy); + if (static_cast<unsigned>(length) == bytesToCopy) + break; + + length -= bytesToCopy; + data += bytesToCopy; + segment = allocateSegment(); + m_segments.append(segment); + bytesToCopy = min(length, segmentSize); + } } void SharedBuffer::clear() { clearPlatformData(); + for (unsigned i = 0; i < m_segments.size(); ++i) + freeSegment(m_segments[i]); + + m_segments.clear(); + m_size = 0; + m_buffer.clear(); m_purgeableBuffer.clear(); } PassRefPtr<SharedBuffer> SharedBuffer::copy() const { - return SharedBuffer::create(data(), size()); + RefPtr<SharedBuffer> clone(adoptRef(new SharedBuffer)); + if (m_purgeableBuffer || hasPlatformData()) { + clone->append(data(), size()); + return clone; + } + + clone->m_size = m_size; + clone->m_buffer.reserveCapacity(m_size); + clone->m_buffer.append(m_buffer.data(), m_buffer.size()); + for (unsigned i = 0; i < m_segments.size(); ++i) + clone->m_buffer.append(m_segments[i], segmentSize); + return clone; } PurgeableBuffer* SharedBuffer::releasePurgeableBuffer() @@ -113,6 +190,54 @@ PurgeableBuffer* SharedBuffer::releasePurgeableBuffer() return m_purgeableBuffer.release(); } +const Vector<char>& SharedBuffer::buffer() const +{ + unsigned bufferSize = m_buffer.size(); + if (m_size > bufferSize) { + m_buffer.resize(m_size); + char* destination = m_buffer.data() + bufferSize; + unsigned bytesLeft = m_size - bufferSize; + for (unsigned i = 0; i < m_segments.size(); ++i) { + unsigned bytesToCopy = min(bytesLeft, segmentSize); + memcpy(destination, m_segments[i], bytesToCopy); + destination += bytesToCopy; + bytesLeft -= bytesToCopy; + freeSegment(m_segments[i]); + } + m_segments.clear(); + } + return m_buffer; +} + +unsigned SharedBuffer::getSomeData(const char*& someData, unsigned position) const +{ + if (hasPlatformData() || m_purgeableBuffer) { + someData = data() + position; + return size() - position; + } + + if (position >= m_size) { + someData = 0; + return 0; + } + + unsigned consecutiveSize = m_buffer.size(); + if (position < consecutiveSize) { + someData = m_buffer.data() + position; + return consecutiveSize - position; + } + + position -= consecutiveSize; + unsigned segmentedSize = m_size - consecutiveSize; + unsigned segments = m_segments.size(); + unsigned segment = segmentIndex(position); + ASSERT(segment < segments); + + unsigned positionInSegment = offsetInSegment(position); + someData = m_segments[segment] + positionInSegment; + return segment == segments - 1 ? segmentedSize - position : segmentSize - positionInSegment; +} + #if !PLATFORM(CF) inline void SharedBuffer::clearPlatformData() |