Home | History | Annotate | Download | only in platform
      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 
     32 using namespace std;
     33 
     34 namespace WebCore {
     35 
     36 static const unsigned segmentSize = 0x1000;
     37 static const unsigned segmentPositionMask = 0x0FFF;
     38 
     39 static inline unsigned segmentIndex(unsigned position)
     40 {
     41     return position / segmentSize;
     42 }
     43 
     44 static inline unsigned offsetInSegment(unsigned position)
     45 {
     46     return position & segmentPositionMask;
     47 }
     48 
     49 static inline char* allocateSegment()
     50 {
     51     return static_cast<char*>(fastMalloc(segmentSize));
     52 }
     53 
     54 static inline void freeSegment(char* p)
     55 {
     56     fastFree(p);
     57 }
     58 
     59 SharedBuffer::SharedBuffer()
     60     : m_size(0)
     61 {
     62 }
     63 
     64 SharedBuffer::SharedBuffer(const char* data, int size)
     65     : m_size(0)
     66 {
     67     append(data, size);
     68 }
     69 
     70 SharedBuffer::SharedBuffer(const unsigned char* data, int size)
     71     : m_size(0)
     72 {
     73     append(reinterpret_cast<const char*>(data), size);
     74 }
     75 
     76 SharedBuffer::~SharedBuffer()
     77 {
     78     clear();
     79 }
     80 
     81 PassRefPtr<SharedBuffer> SharedBuffer::adoptVector(Vector<char>& vector)
     82 {
     83     RefPtr<SharedBuffer> buffer = create();
     84     buffer->m_buffer.swap(vector);
     85     buffer->m_size = buffer->m_buffer.size();
     86     return buffer.release();
     87 }
     88 
     89 PassRefPtr<SharedBuffer> SharedBuffer::adoptPurgeableBuffer(PurgeableBuffer* purgeableBuffer)
     90 {
     91     ASSERT(!purgeableBuffer->isPurgeable());
     92     RefPtr<SharedBuffer> buffer = create();
     93     buffer->m_purgeableBuffer.set(purgeableBuffer);
     94     return buffer.release();
     95 }
     96 
     97 unsigned SharedBuffer::size() const
     98 {
     99     if (hasPlatformData())
    100         return platformDataSize();
    101 
    102     if (m_purgeableBuffer)
    103         return m_purgeableBuffer->size();
    104 
    105     return m_size;
    106 }
    107 
    108 const char* SharedBuffer::data() const
    109 {
    110     if (hasPlatformData())
    111         return platformData();
    112 
    113     if (m_purgeableBuffer)
    114         return m_purgeableBuffer->data();
    115 
    116     return buffer().data();
    117 }
    118 
    119 void SharedBuffer::append(const char* data, unsigned length)
    120 {
    121     ASSERT(!m_purgeableBuffer);
    122 
    123     maybeTransferPlatformData();
    124 
    125     unsigned positionInSegment = offsetInSegment(m_size - m_buffer.size());
    126     m_size += length;
    127 
    128     if (m_size <= segmentSize) {
    129         // No need to use segments for small resource data
    130         m_buffer.append(data, length);
    131         return;
    132     }
    133 
    134     char* segment;
    135     if (!positionInSegment) {
    136         segment = allocateSegment();
    137         m_segments.append(segment);
    138     } else
    139         segment = m_segments.last() + positionInSegment;
    140 
    141     unsigned segmentFreeSpace = segmentSize - positionInSegment;
    142     unsigned bytesToCopy = min(length, segmentFreeSpace);
    143 
    144     for (;;) {
    145         memcpy(segment, data, bytesToCopy);
    146         if (static_cast<unsigned>(length) == bytesToCopy)
    147             break;
    148 
    149         length -= bytesToCopy;
    150         data += bytesToCopy;
    151         segment = allocateSegment();
    152         m_segments.append(segment);
    153         bytesToCopy = min(length, segmentSize);
    154     }
    155 }
    156 
    157 void SharedBuffer::clear()
    158 {
    159     clearPlatformData();
    160 
    161     for (unsigned i = 0; i < m_segments.size(); ++i)
    162         freeSegment(m_segments[i]);
    163 
    164     m_segments.clear();
    165     m_size = 0;
    166 
    167     m_buffer.clear();
    168     m_purgeableBuffer.clear();
    169 }
    170 
    171 PassRefPtr<SharedBuffer> SharedBuffer::copy() const
    172 {
    173     RefPtr<SharedBuffer> clone(adoptRef(new SharedBuffer));
    174     if (m_purgeableBuffer || hasPlatformData()) {
    175         clone->append(data(), size());
    176         return clone;
    177     }
    178 
    179     clone->m_size = m_size;
    180     clone->m_buffer.reserveCapacity(m_size);
    181     clone->m_buffer.append(m_buffer.data(), m_buffer.size());
    182     for (unsigned i = 0; i < m_segments.size(); ++i)
    183         clone->m_buffer.append(m_segments[i], segmentSize);
    184     return clone;
    185 }
    186 
    187 PurgeableBuffer* SharedBuffer::releasePurgeableBuffer()
    188 {
    189     ASSERT(hasOneRef());
    190     return m_purgeableBuffer.release();
    191 }
    192 
    193 const Vector<char>& SharedBuffer::buffer() const
    194 {
    195     unsigned bufferSize = m_buffer.size();
    196     if (m_size > bufferSize) {
    197         m_buffer.resize(m_size);
    198         char* destination = m_buffer.data() + bufferSize;
    199         unsigned bytesLeft = m_size - bufferSize;
    200         for (unsigned i = 0; i < m_segments.size(); ++i) {
    201             unsigned bytesToCopy = min(bytesLeft, segmentSize);
    202             memcpy(destination, m_segments[i], bytesToCopy);
    203             destination += bytesToCopy;
    204             bytesLeft -= bytesToCopy;
    205             freeSegment(m_segments[i]);
    206         }
    207         m_segments.clear();
    208     }
    209     return m_buffer;
    210 }
    211 
    212 unsigned SharedBuffer::getSomeData(const char*& someData, unsigned position) const
    213 {
    214     if (hasPlatformData() || m_purgeableBuffer) {
    215         someData = data() + position;
    216         return size() - position;
    217     }
    218 
    219     if (position >= m_size) {
    220         someData = 0;
    221         return 0;
    222     }
    223 
    224     unsigned consecutiveSize = m_buffer.size();
    225     if (position < consecutiveSize) {
    226         someData = m_buffer.data() + position;
    227         return consecutiveSize - position;
    228     }
    229 
    230     position -= consecutiveSize;
    231     unsigned segmentedSize = m_size - consecutiveSize;
    232     unsigned segments = m_segments.size();
    233     unsigned segment = segmentIndex(position);
    234     ASSERT(segment < segments);
    235 
    236     unsigned positionInSegment = offsetInSegment(position);
    237     someData = m_segments[segment] + positionInSegment;
    238     return segment == segments - 1 ? segmentedSize - position : segmentSize - positionInSegment;
    239 }
    240 
    241 #if !PLATFORM(CF)
    242 
    243 inline void SharedBuffer::clearPlatformData()
    244 {
    245 }
    246 
    247 inline void SharedBuffer::maybeTransferPlatformData()
    248 {
    249 }
    250 
    251 inline bool SharedBuffer::hasPlatformData() const
    252 {
    253     return false;
    254 }
    255 
    256 inline const char* SharedBuffer::platformData() const
    257 {
    258     ASSERT_NOT_REACHED();
    259 
    260     return 0;
    261 }
    262 
    263 inline unsigned SharedBuffer::platformDataSize() const
    264 {
    265     ASSERT_NOT_REACHED();
    266 
    267     return 0;
    268 }
    269 
    270 #endif
    271 
    272 }
    273