diff -r 000000000000 -r 4f2f89ce4247 WebCore/platform/SharedBuffer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebCore/platform/SharedBuffer.cpp Fri Sep 17 09:02:29 2010 +0300 @@ -0,0 +1,273 @@ +/* + * 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 + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "SharedBuffer.h" + +#include "PurgeableBuffer.h" +#include + +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(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) +{ + append(data, size); +} + +SharedBuffer::SharedBuffer(const unsigned char* data, int size) + : m_size(0) +{ + append(reinterpret_cast(data), size); +} + +SharedBuffer::~SharedBuffer() +{ + clear(); +} + +PassRefPtr SharedBuffer::adoptVector(Vector& vector) +{ + RefPtr buffer = create(); + buffer->m_buffer.swap(vector); + buffer->m_size = buffer->m_buffer.size(); + return buffer.release(); +} + +PassRefPtr SharedBuffer::adoptPurgeableBuffer(PassOwnPtr purgeableBuffer) +{ + ASSERT(!purgeableBuffer->isPurgeable()); + RefPtr buffer = create(); + buffer->m_purgeableBuffer = purgeableBuffer; + return buffer.release(); +} + +unsigned SharedBuffer::size() const +{ + if (hasPlatformData()) + return platformDataSize(); + + if (m_purgeableBuffer) + return m_purgeableBuffer->size(); + + return m_size; +} + +const char* SharedBuffer::data() const +{ + if (hasPlatformData()) + return platformData(); + + if (m_purgeableBuffer) + return m_purgeableBuffer->data(); + + return buffer().data(); +} + +void SharedBuffer::append(const char* data, unsigned length) +{ + ASSERT(!m_purgeableBuffer); + + maybeTransferPlatformData(); + + 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(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::copy() const +{ + RefPtr 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; +} + +PassOwnPtr SharedBuffer::releasePurgeableBuffer() +{ + ASSERT(hasOneRef()); + return m_purgeableBuffer.release(); +} + +const Vector& 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() +{ +} + +inline void SharedBuffer::maybeTransferPlatformData() +{ +} + +inline bool SharedBuffer::hasPlatformData() const +{ + return false; +} + +inline const char* SharedBuffer::platformData() const +{ + ASSERT_NOT_REACHED(); + + return 0; +} + +inline unsigned SharedBuffer::platformDataSize() const +{ + ASSERT_NOT_REACHED(); + + return 0; +} + +#endif + +}