Reduce copies and allocations in SharedBuffer::append
[WebKit-https.git] / Source / WebCore / platform / SharedBuffer.cpp
1 /*
2  * Copyright (C) 2006-2016 Apple Inc. All rights reserved.
3  * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
4  * Copyright (C) 2015 Canon Inc. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
26  */
27
28 #include "config.h"
29 #include "SharedBuffer.h"
30
31 #include <algorithm>
32 #include <wtf/unicode/UTF8.h>
33
34 #if USE(SOUP)
35 #include "GUniquePtrSoup.h"
36 #endif
37
38 namespace WebCore {
39
40 SharedBuffer::SharedBuffer(const char* data, size_t size)
41 {
42     append(data, size);
43 }
44
45 SharedBuffer::SharedBuffer(const unsigned char* data, size_t size)
46 {
47     append(reinterpret_cast<const char*>(data), size);
48 }
49
50 SharedBuffer::SharedBuffer(MappedFileData&& fileData)
51     : m_size(fileData.size())
52 {
53     m_segments.append(DataSegment::create(WTFMove(fileData)));
54 }
55
56 SharedBuffer::SharedBuffer(Vector<char>&& data)
57 {
58     append(WTFMove(data));
59 }
60
61 RefPtr<SharedBuffer> SharedBuffer::createWithContentsOfFile(const String& filePath)
62 {
63     bool mappingSuccess;
64     MappedFileData mappedFileData(filePath, mappingSuccess);
65
66     if (!mappingSuccess)
67         return SharedBuffer::createFromReadingFile(filePath);
68
69     return adoptRef(new SharedBuffer(WTFMove(mappedFileData)));
70 }
71
72 Ref<SharedBuffer> SharedBuffer::create(Vector<char>&& vector)
73 {
74     return adoptRef(*new SharedBuffer(WTFMove(vector)));
75 }
76
77 void SharedBuffer::combineToOneSegment() const
78 {
79     if (m_segments.size() <= 1)
80         return;
81
82     Vector<char> combinedData;
83     combinedData.reserveInitialCapacity(m_size);
84     for (const auto& segment : m_segments)
85         combinedData.append(segment->data(), segment->size());
86     ASSERT(combinedData.size() == m_size);
87     m_segments.clear();
88     m_segments.append(DataSegment::create(WTFMove(combinedData)));
89     ASSERT(m_segments.size() == 1);
90 }
91
92 const char* SharedBuffer::data() const
93 {
94     if (!m_segments.size())
95         return nullptr;
96     combineToOneSegment();
97     return m_segments[0]->data();
98 }
99
100 RefPtr<ArrayBuffer> SharedBuffer::createArrayBuffer() const
101 {
102     RefPtr<ArrayBuffer> arrayBuffer = ArrayBuffer::createUninitialized(static_cast<unsigned>(size()), sizeof(char));
103     if (!arrayBuffer) {
104         WTFLogAlways("SharedBuffer::createArrayBuffer Unable to create buffer. Requested size was %d x %lu\n", size(), sizeof(char));
105         return nullptr;
106     }
107
108     size_t position = 0;
109     for (const auto& segment : m_segments) {
110         memcpy(static_cast<char*>(arrayBuffer->data()) + position, segment->data(), segment->size());
111         position += segment->size();
112     }
113
114     ASSERT(position == m_size);
115     return arrayBuffer;
116 }
117
118 void SharedBuffer::append(const SharedBuffer& data)
119 {
120     m_size += data.m_size;
121     m_segments.reserveCapacity(m_segments.size() + data.m_segments.size());
122     for (const auto& segment : data.m_segments)
123         m_segments.uncheckedAppend(segment.copyRef());
124 }
125
126 void SharedBuffer::append(const char* data, size_t length)
127 {
128     m_size += length;
129     Vector<char> vector;
130     vector.append(data, length);
131     m_segments.append(DataSegment::create(WTFMove(vector)));
132 }
133
134 void SharedBuffer::append(Vector<char>&& data)
135 {
136     m_size += data.size();
137     m_segments.append(DataSegment::create(WTFMove(data)));
138 }
139
140 void SharedBuffer::clear()
141 {
142     m_size = 0;
143     m_segments.clear();
144 }
145
146 Ref<SharedBuffer> SharedBuffer::copy() const
147 {
148     Ref<SharedBuffer> clone = adoptRef(*new SharedBuffer);
149     clone->m_size = m_size;
150     clone->m_segments.reserveInitialCapacity(m_segments.size());
151     for (const auto& segment : m_segments)
152         clone->m_segments.uncheckedAppend(segment.copyRef());
153     return clone;
154 }
155
156 const char* SharedBuffer::DataSegment::data() const
157 {
158     auto visitor = WTF::makeVisitor(
159         [](const Vector<char>& data) { return data.data(); },
160 #if USE(CF)
161         [](const RetainPtr<CFDataRef>& data) { return reinterpret_cast<const char*>(CFDataGetBytePtr(data.get())); },
162 #endif
163 #if USE(SOUP)
164         [](const GUniquePtr<SoupBuffer>& data) { return data->data; },
165 #endif
166         [](const MappedFileData& data) { return reinterpret_cast<const char*>(data.data()); }
167     );
168     return WTF::visit(visitor, m_immutableData);
169 }
170
171 #if !USE(CF)
172 void SharedBuffer::hintMemoryNotNeededSoon()
173 {
174 }
175 #endif
176
177 size_t SharedBuffer::DataSegment::size() const
178 {
179     auto visitor = WTF::makeVisitor(
180         [](const Vector<char>& data) { return data.size(); },
181 #if USE(CF)
182         [](const RetainPtr<CFDataRef>& data) { return CFDataGetLength(data.get()); },
183 #endif
184 #if USE(SOUP)
185         [](const GUniquePtr<SoupBuffer>& data) { return static_cast<size_t>(data->length); },
186 #endif
187         [](const MappedFileData& data) { return data.size(); }
188     );
189     return WTF::visit(visitor, m_immutableData);
190 }
191
192 RefPtr<SharedBuffer> utf8Buffer(const String& string)
193 {
194     // Allocate a buffer big enough to hold all the characters.
195     const int length = string.length();
196     Vector<char> buffer(length * 3);
197
198     // Convert to runs of 8-bit characters.
199     char* p = buffer.data();
200     WTF::Unicode::ConversionResult result;
201     if (length) {
202         if (string.is8Bit()) {
203             const LChar* d = string.characters8();
204             result = WTF::Unicode::convertLatin1ToUTF8(&d, d + length, &p, p + buffer.size());
205         } else {
206             const UChar* d = string.characters16();
207             result = WTF::Unicode::convertUTF16ToUTF8(&d, d + length, &p, p + buffer.size(), true);
208         }
209         if (result != WTF::Unicode::conversionOK)
210             return nullptr;
211     }
212
213     buffer.shrink(p - buffer.data());
214     return SharedBuffer::create(WTFMove(buffer));
215 }
216
217 } // namespace WebCore