Unreviewed, rolling out r126169.
[WebKit-https.git] / Source / WebCore / platform / SharedBuffer.cpp
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 "MemoryInstrumentation.h"
31 #include "PurgeableBuffer.h"
32 #include <wtf/PassOwnPtr.h>
33
34 using namespace std;
35
36 namespace WebCore {
37
38 static const unsigned segmentSize = 0x1000;
39 static const unsigned segmentPositionMask = 0x0FFF;
40
41 static inline unsigned segmentIndex(unsigned position)
42 {
43     return position / segmentSize;
44 }
45
46 static inline unsigned offsetInSegment(unsigned position)
47 {
48     return position & segmentPositionMask;
49 }
50
51 static inline char* allocateSegment()
52 {
53     return static_cast<char*>(fastMalloc(segmentSize));
54 }
55
56 static inline void freeSegment(char* p)
57 {
58     fastFree(p);
59 }
60
61 SharedBuffer::SharedBuffer()
62     : m_size(0)
63 {
64 }
65
66 SharedBuffer::SharedBuffer(size_t size)
67     : m_size(size)
68     , m_buffer(size)
69 {
70 }
71
72 SharedBuffer::SharedBuffer(const char* data, int size)
73     : m_size(0)
74 {
75     // FIXME: Use unsigned consistently, and check for invalid casts when calling into SharedBuffer from other code.
76     if (size < 0)
77         CRASH();
78
79     append(data, size);
80 }
81
82 SharedBuffer::SharedBuffer(const unsigned char* data, int size)
83     : m_size(0)
84 {
85     // FIXME: Use unsigned consistently, and check for invalid casts when calling into SharedBuffer from other code.
86     if (size < 0)
87         CRASH();
88
89     append(reinterpret_cast<const char*>(data), size);
90 }
91     
92 SharedBuffer::~SharedBuffer()
93 {
94     clear();
95 }
96
97 PassRefPtr<SharedBuffer> SharedBuffer::adoptVector(Vector<char>& vector)
98 {
99     RefPtr<SharedBuffer> buffer = create();
100     buffer->m_buffer.swap(vector);
101     buffer->m_size = buffer->m_buffer.size();
102     return buffer.release();
103 }
104
105 PassRefPtr<SharedBuffer> SharedBuffer::adoptPurgeableBuffer(PassOwnPtr<PurgeableBuffer> purgeableBuffer) 
106
107     ASSERT(!purgeableBuffer->isPurgeable());
108     RefPtr<SharedBuffer> buffer = create();
109     buffer->m_purgeableBuffer = purgeableBuffer;
110     return buffer.release();
111 }
112
113 unsigned SharedBuffer::size() const
114 {
115     if (hasPlatformData())
116         return platformDataSize();
117     
118     if (m_purgeableBuffer)
119         return m_purgeableBuffer->size();
120     
121     return m_size;
122 }
123
124 const char* SharedBuffer::data() const
125 {
126     if (hasPlatformData())
127         return platformData();
128     
129     if (m_purgeableBuffer)
130         return m_purgeableBuffer->data();
131     
132     return buffer().data();
133 }
134
135 void SharedBuffer::append(SharedBuffer* data)
136 {
137     const char* segment;
138     size_t position = 0;
139     while (size_t length = data->getSomeData(segment, position)) {
140         append(segment, length);
141         position += length;
142     }
143 }
144
145 void SharedBuffer::append(const char* data, unsigned length)
146 {
147     ASSERT(!m_purgeableBuffer);
148
149     maybeTransferPlatformData();
150     
151     unsigned positionInSegment = offsetInSegment(m_size - m_buffer.size());
152     m_size += length;
153
154     if (m_size <= segmentSize) {
155         // No need to use segments for small resource data
156         m_buffer.append(data, length);
157         return;
158     }
159
160     char* segment;
161     if (!positionInSegment) {
162         segment = allocateSegment();
163         m_segments.append(segment);
164     } else
165         segment = m_segments.last() + positionInSegment;
166
167     unsigned segmentFreeSpace = segmentSize - positionInSegment;
168     unsigned bytesToCopy = min(length, segmentFreeSpace);
169
170     for (;;) {
171         memcpy(segment, data, bytesToCopy);
172         if (static_cast<unsigned>(length) == bytesToCopy)
173             break;
174
175         length -= bytesToCopy;
176         data += bytesToCopy;
177         segment = allocateSegment();
178         m_segments.append(segment);
179         bytesToCopy = min(length, segmentSize);
180     }
181 }
182
183 void SharedBuffer::append(const Vector<char>& data)
184 {
185     append(data.data(), data.size());
186 }
187
188 void SharedBuffer::clear()
189 {
190     clearPlatformData();
191     
192     for (unsigned i = 0; i < m_segments.size(); ++i)
193         freeSegment(m_segments[i]);
194
195     m_segments.clear();
196     m_size = 0;
197
198     m_buffer.clear();
199     m_purgeableBuffer.clear();
200 #if HAVE(NETWORK_CFDATA_ARRAY_CALLBACK)
201     m_dataArray.clear();
202 #endif
203 }
204
205 PassRefPtr<SharedBuffer> SharedBuffer::copy() const
206 {
207     RefPtr<SharedBuffer> clone(adoptRef(new SharedBuffer));
208     if (m_purgeableBuffer || hasPlatformData()) {
209         clone->append(data(), size());
210         return clone;
211     }
212
213     clone->m_size = m_size;
214     clone->m_buffer.reserveCapacity(m_size);
215     clone->m_buffer.append(m_buffer.data(), m_buffer.size());
216     for (unsigned i = 0; i < m_segments.size(); ++i)
217         clone->m_buffer.append(m_segments[i], segmentSize);
218     return clone;
219 }
220
221 PassOwnPtr<PurgeableBuffer> SharedBuffer::releasePurgeableBuffer()
222
223     ASSERT(hasOneRef()); 
224     return m_purgeableBuffer.release(); 
225 }
226
227 const Vector<char>& SharedBuffer::buffer() const
228 {
229     unsigned bufferSize = m_buffer.size();
230     if (m_size > bufferSize) {
231         m_buffer.resize(m_size);
232         char* destination = m_buffer.data() + bufferSize;
233         unsigned bytesLeft = m_size - bufferSize;
234         for (unsigned i = 0; i < m_segments.size(); ++i) {
235             unsigned bytesToCopy = min(bytesLeft, segmentSize);
236             memcpy(destination, m_segments[i], bytesToCopy);
237             destination += bytesToCopy;
238             bytesLeft -= bytesToCopy;
239             freeSegment(m_segments[i]);
240         }
241         m_segments.clear();
242 #if HAVE(NETWORK_CFDATA_ARRAY_CALLBACK)
243         copyDataArrayAndClear(destination, bytesLeft);
244 #endif
245     }
246     return m_buffer;
247 }
248
249 void SharedBuffer::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
250 {
251     MemoryClassInfo info(memoryObjectInfo, this, MemoryInstrumentation::Other);
252     info.addVector(m_buffer);
253     info.addVector(m_segments);
254     for (unsigned i = 0; i < m_segments.size(); ++i)
255         info.addRawBuffer(m_segments[i], segmentSize);
256     info.addMember(m_purgeableBuffer.get());
257 }
258
259 unsigned SharedBuffer::getSomeData(const char*& someData, unsigned position) const
260 {
261     unsigned totalSize = size();
262     if (position >= totalSize) {
263         someData = 0;
264         return 0;
265     }
266
267     if (hasPlatformData() || m_purgeableBuffer) {
268         ASSERT(position < size());
269         someData = data() + position;
270         return totalSize - position;
271     }
272
273     ASSERT(position < m_size);
274     unsigned consecutiveSize = m_buffer.size();
275     if (position < consecutiveSize) {
276         someData = m_buffer.data() + position;
277         return consecutiveSize - position;
278     }
279  
280     position -= consecutiveSize;
281     unsigned segments = m_segments.size();
282     unsigned maxSegmentedSize = segments * segmentSize;
283     unsigned segment = segmentIndex(position);
284     if (segment < segments) {
285         unsigned bytesLeft = totalSize - consecutiveSize;
286         unsigned segmentedSize = min(maxSegmentedSize, bytesLeft);
287
288         unsigned positionInSegment = offsetInSegment(position);
289         someData = m_segments[segment] + positionInSegment;
290         return segment == segments - 1 ? segmentedSize - position : segmentSize - positionInSegment;
291     }
292 #if HAVE(NETWORK_CFDATA_ARRAY_CALLBACK)
293     ASSERT(maxSegmentedSize <= position);
294     position -= maxSegmentedSize;
295     return copySomeDataFromDataArray(someData, position);
296 #else
297     ASSERT_NOT_REACHED();
298     return 0;
299 #endif
300 }
301
302 #if !USE(CF) || PLATFORM(QT)
303
304 inline void SharedBuffer::clearPlatformData()
305 {
306 }
307
308 inline void SharedBuffer::maybeTransferPlatformData()
309 {
310 }
311
312 inline bool SharedBuffer::hasPlatformData() const
313 {
314     return false;
315 }
316
317 inline const char* SharedBuffer::platformData() const
318 {
319     ASSERT_NOT_REACHED();
320
321     return 0;
322 }
323
324 inline unsigned SharedBuffer::platformDataSize() const
325 {
326     ASSERT_NOT_REACHED();
327     
328     return 0;
329 }
330
331 #endif
332
333 }