• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
segmentIndex(unsigned position)39 static inline unsigned segmentIndex(unsigned position)
40 {
41     return position / segmentSize;
42 }
43 
offsetInSegment(unsigned position)44 static inline unsigned offsetInSegment(unsigned position)
45 {
46     return position & segmentPositionMask;
47 }
48 
allocateSegment()49 static inline char* allocateSegment()
50 {
51     return static_cast<char*>(fastMalloc(segmentSize));
52 }
53 
freeSegment(char * p)54 static inline void freeSegment(char* p)
55 {
56     fastFree(p);
57 }
58 
SharedBuffer()59 SharedBuffer::SharedBuffer()
60     : m_size(0)
61 {
62 }
63 
SharedBuffer(const char * data,int size)64 SharedBuffer::SharedBuffer(const char* data, int size)
65     : m_size(0)
66 {
67     append(data, size);
68 }
69 
SharedBuffer(const unsigned char * data,int size)70 SharedBuffer::SharedBuffer(const unsigned char* data, int size)
71     : m_size(0)
72 {
73     append(reinterpret_cast<const char*>(data), size);
74 }
75 
~SharedBuffer()76 SharedBuffer::~SharedBuffer()
77 {
78     clear();
79 }
80 
adoptVector(Vector<char> & vector)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 
adoptPurgeableBuffer(PurgeableBuffer * purgeableBuffer)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 
size() const97 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 
data() const108 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 
append(const char * data,unsigned length)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 
clear()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 
copy() const171 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 
releasePurgeableBuffer()187 PurgeableBuffer* SharedBuffer::releasePurgeableBuffer()
188 {
189     ASSERT(hasOneRef());
190     return m_purgeableBuffer.release();
191 }
192 
buffer() const193 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 
getSomeData(const char * & someData,unsigned position) const212 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 
clearPlatformData()243 inline void SharedBuffer::clearPlatformData()
244 {
245 }
246 
maybeTransferPlatformData()247 inline void SharedBuffer::maybeTransferPlatformData()
248 {
249 }
250 
hasPlatformData() const251 inline bool SharedBuffer::hasPlatformData() const
252 {
253     return false;
254 }
255 
platformData() const256 inline const char* SharedBuffer::platformData() const
257 {
258     ASSERT_NOT_REACHED();
259 
260     return 0;
261 }
262 
platformDataSize() const263 inline unsigned SharedBuffer::platformDataSize() const
264 {
265     ASSERT_NOT_REACHED();
266 
267     return 0;
268 }
269 
270 #endif
271 
272 }
273