WebCore/platform/SharedBuffer.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /*
       
     2  * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
       
     3  * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
       
     4  *
       
     5  * Redistribution and use in source and binary forms, with or without
       
     6  * modification, are permitted provided that the following conditions
       
     7  * are met:
       
     8  * 1. Redistributions of source code must retain the above copyright
       
     9  *    notice, this list of conditions and the following disclaimer.
       
    10  * 2. Redistributions in binary form must reproduce the above copyright
       
    11  *    notice, this list of conditions and the following disclaimer in the
       
    12  *    documentation and/or other materials provided with the distribution.
       
    13  *
       
    14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
       
    15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
       
    16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
       
    17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
       
    18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
       
    19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
       
    20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
       
    21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
       
    22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       
    23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
       
    24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
       
    25  */
       
    26 
       
    27 #include "config.h"
       
    28 #include "SharedBuffer.h"
       
    29 
       
    30 #include "PurgeableBuffer.h"
       
    31 #include <wtf/PassOwnPtr.h>
       
    32 
       
    33 using namespace std;
       
    34 
       
    35 namespace WebCore {
       
    36 
       
    37 static const unsigned segmentSize = 0x1000;
       
    38 static const unsigned segmentPositionMask = 0x0FFF;
       
    39 
       
    40 static inline unsigned segmentIndex(unsigned position)
       
    41 {
       
    42     return position / segmentSize;
       
    43 }
       
    44 
       
    45 static inline unsigned offsetInSegment(unsigned position)
       
    46 {
       
    47     return position & segmentPositionMask;
       
    48 }
       
    49 
       
    50 static inline char* allocateSegment()
       
    51 {
       
    52     return static_cast<char*>(fastMalloc(segmentSize));
       
    53 }
       
    54 
       
    55 static inline void freeSegment(char* p)
       
    56 {
       
    57     fastFree(p);
       
    58 }
       
    59 
       
    60 SharedBuffer::SharedBuffer()
       
    61     : m_size(0)
       
    62 {
       
    63 }
       
    64 
       
    65 SharedBuffer::SharedBuffer(const char* data, int size)
       
    66     : m_size(0)
       
    67 {
       
    68     append(data, size);
       
    69 }
       
    70 
       
    71 SharedBuffer::SharedBuffer(const unsigned char* data, int size)
       
    72     : m_size(0)
       
    73 {
       
    74     append(reinterpret_cast<const char*>(data), size);
       
    75 }
       
    76     
       
    77 SharedBuffer::~SharedBuffer()
       
    78 {
       
    79     clear();
       
    80 }
       
    81 
       
    82 PassRefPtr<SharedBuffer> SharedBuffer::adoptVector(Vector<char>& vector)
       
    83 {
       
    84     RefPtr<SharedBuffer> buffer = create();
       
    85     buffer->m_buffer.swap(vector);
       
    86     buffer->m_size = buffer->m_buffer.size();
       
    87     return buffer.release();
       
    88 }
       
    89 
       
    90 PassRefPtr<SharedBuffer> SharedBuffer::adoptPurgeableBuffer(PassOwnPtr<PurgeableBuffer> purgeableBuffer) 
       
    91 { 
       
    92     ASSERT(!purgeableBuffer->isPurgeable());
       
    93     RefPtr<SharedBuffer> buffer = create();
       
    94     buffer->m_purgeableBuffer = purgeableBuffer;
       
    95     return buffer.release();
       
    96 }
       
    97 
       
    98 unsigned SharedBuffer::size() const
       
    99 {
       
   100     if (hasPlatformData())
       
   101         return platformDataSize();
       
   102     
       
   103     if (m_purgeableBuffer)
       
   104         return m_purgeableBuffer->size();
       
   105     
       
   106     return m_size;
       
   107 }
       
   108 
       
   109 const char* SharedBuffer::data() const
       
   110 {
       
   111     if (hasPlatformData())
       
   112         return platformData();
       
   113     
       
   114     if (m_purgeableBuffer)
       
   115         return m_purgeableBuffer->data();
       
   116     
       
   117     return buffer().data();
       
   118 }
       
   119 
       
   120 void SharedBuffer::append(const char* data, unsigned length)
       
   121 {
       
   122     ASSERT(!m_purgeableBuffer);
       
   123 
       
   124     maybeTransferPlatformData();
       
   125     
       
   126     unsigned positionInSegment = offsetInSegment(m_size - m_buffer.size());
       
   127     m_size += length;
       
   128 
       
   129     if (m_size <= segmentSize) {
       
   130         // No need to use segments for small resource data
       
   131         m_buffer.append(data, length);
       
   132         return;
       
   133     }
       
   134 
       
   135     char* segment;
       
   136     if (!positionInSegment) {
       
   137         segment = allocateSegment();
       
   138         m_segments.append(segment);
       
   139     } else
       
   140         segment = m_segments.last() + positionInSegment;
       
   141 
       
   142     unsigned segmentFreeSpace = segmentSize - positionInSegment;
       
   143     unsigned bytesToCopy = min(length, segmentFreeSpace);
       
   144 
       
   145     for (;;) {
       
   146         memcpy(segment, data, bytesToCopy);
       
   147         if (static_cast<unsigned>(length) == bytesToCopy)
       
   148             break;
       
   149 
       
   150         length -= bytesToCopy;
       
   151         data += bytesToCopy;
       
   152         segment = allocateSegment();
       
   153         m_segments.append(segment);
       
   154         bytesToCopy = min(length, segmentSize);
       
   155     }
       
   156 }
       
   157 
       
   158 void SharedBuffer::clear()
       
   159 {
       
   160     clearPlatformData();
       
   161     
       
   162     for (unsigned i = 0; i < m_segments.size(); ++i)
       
   163         freeSegment(m_segments[i]);
       
   164 
       
   165     m_segments.clear();
       
   166     m_size = 0;
       
   167 
       
   168     m_buffer.clear();
       
   169     m_purgeableBuffer.clear();
       
   170 }
       
   171 
       
   172 PassRefPtr<SharedBuffer> SharedBuffer::copy() const
       
   173 {
       
   174     RefPtr<SharedBuffer> clone(adoptRef(new SharedBuffer));
       
   175     if (m_purgeableBuffer || hasPlatformData()) {
       
   176         clone->append(data(), size());
       
   177         return clone;
       
   178     }
       
   179 
       
   180     clone->m_size = m_size;
       
   181     clone->m_buffer.reserveCapacity(m_size);
       
   182     clone->m_buffer.append(m_buffer.data(), m_buffer.size());
       
   183     for (unsigned i = 0; i < m_segments.size(); ++i)
       
   184         clone->m_buffer.append(m_segments[i], segmentSize);
       
   185     return clone;
       
   186 }
       
   187 
       
   188 PassOwnPtr<PurgeableBuffer> SharedBuffer::releasePurgeableBuffer()
       
   189 { 
       
   190     ASSERT(hasOneRef()); 
       
   191     return m_purgeableBuffer.release(); 
       
   192 }
       
   193 
       
   194 const Vector<char>& SharedBuffer::buffer() const
       
   195 {
       
   196     unsigned bufferSize = m_buffer.size();
       
   197     if (m_size > bufferSize) {
       
   198         m_buffer.resize(m_size);
       
   199         char* destination = m_buffer.data() + bufferSize;
       
   200         unsigned bytesLeft = m_size - bufferSize;
       
   201         for (unsigned i = 0; i < m_segments.size(); ++i) {
       
   202             unsigned bytesToCopy = min(bytesLeft, segmentSize);
       
   203             memcpy(destination, m_segments[i], bytesToCopy);
       
   204             destination += bytesToCopy;
       
   205             bytesLeft -= bytesToCopy;
       
   206             freeSegment(m_segments[i]);
       
   207         }
       
   208         m_segments.clear();
       
   209     }
       
   210     return m_buffer;
       
   211 }
       
   212 
       
   213 unsigned SharedBuffer::getSomeData(const char*& someData, unsigned position) const
       
   214 {
       
   215     if (hasPlatformData() || m_purgeableBuffer) {
       
   216         someData = data() + position;
       
   217         return size() - position;
       
   218     }
       
   219 
       
   220     if (position >= m_size) {
       
   221         someData = 0;
       
   222         return 0;
       
   223     }
       
   224 
       
   225     unsigned consecutiveSize = m_buffer.size();
       
   226     if (position < consecutiveSize) {
       
   227         someData = m_buffer.data() + position;
       
   228         return consecutiveSize - position;
       
   229     }
       
   230  
       
   231     position -= consecutiveSize;
       
   232     unsigned segmentedSize = m_size - consecutiveSize;
       
   233     unsigned segments = m_segments.size();
       
   234     unsigned segment = segmentIndex(position);
       
   235     ASSERT(segment < segments);
       
   236 
       
   237     unsigned positionInSegment = offsetInSegment(position);
       
   238     someData = m_segments[segment] + positionInSegment;
       
   239     return segment == segments - 1 ? segmentedSize - position : segmentSize - positionInSegment;
       
   240 }
       
   241 
       
   242 #if !PLATFORM(CF)
       
   243 
       
   244 inline void SharedBuffer::clearPlatformData()
       
   245 {
       
   246 }
       
   247 
       
   248 inline void SharedBuffer::maybeTransferPlatformData()
       
   249 {
       
   250 }
       
   251 
       
   252 inline bool SharedBuffer::hasPlatformData() const
       
   253 {
       
   254     return false;
       
   255 }
       
   256 
       
   257 inline const char* SharedBuffer::platformData() const
       
   258 {
       
   259     ASSERT_NOT_REACHED();
       
   260 
       
   261     return 0;
       
   262 }
       
   263 
       
   264 inline unsigned SharedBuffer::platformDataSize() const
       
   265 {
       
   266     ASSERT_NOT_REACHED();
       
   267     
       
   268     return 0;
       
   269 }
       
   270 
       
   271 #endif
       
   272 
       
   273 }