Changeset 217260 in webkit
- Timestamp:
- May 22, 2017 5:50:58 PM (7 years ago)
- Location:
- trunk
- Files:
-
- 17 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r217256 r217260 1 2017-05-20 Alex Christensen <achristensen@webkit.org> 2 3 REGRESSION(r215686): O(n^2) algorithm in CachedRawResource::addDataBuffer 4 https://bugs.webkit.org/show_bug.cgi?id=172406 5 <rdar://32109532> 6 7 Reviewed by Brady Eidson. 8 9 CachedRawResource::calculateIncrementalDataChunk was calling SharedBuffer::data each time the data 10 was appended to the SharedBuffer. This causes the data to be copied from two segments to one segment, 11 which causes the O(n^2) behavior I was worried about in r215686. These append/data/append/data calls 12 used to cause O(1) copies per byte which was amortized because of the exponential growth of the buffer. 13 After this change, there should be 0 copies per byte here, and instead a O(log(n)) binary search in the 14 call to std::upper_bound to find the next segment of data with a given starting location in the SharedBuffer. 15 We need to store the additional information of the offsets of the beginnings of the segments in a 16 SharedBuffer. This doesn't asymptotically increase our memory usage, but it does allow us to asymptotically 17 decrease the amount of time it takes to find data at a given offset in a SharedBuffer from O(n) to O(log(n)). 18 19 This allows us to complete http://speedtest.xfinity.com and new functionality in SharedBuffer is covered by API tests. 20 21 * loader/TextTrackLoader.cpp: 22 (WebCore::TextTrackLoader::processNewCueData): 23 * loader/cache/CachedRawResource.cpp: 24 (WebCore::CachedRawResource::calculateIncrementalDataChunk): 25 (WebCore::CachedRawResource::addDataBuffer): 26 (WebCore::CachedRawResource::finishLoading): 27 * loader/cache/CachedRawResource.h: 28 * platform/SharedBuffer.cpp: 29 (WebCore::SharedBuffer::SharedBuffer): 30 (WebCore::SharedBuffer::combineIntoOneSegment): 31 (WebCore::SharedBuffer::data): 32 (WebCore::SharedBuffer::getSomeData): 33 (WebCore::SharedBuffer::tryCreateArrayBuffer): 34 (WebCore::SharedBuffer::append): 35 (WebCore::SharedBuffer::clear): 36 (WebCore::SharedBuffer::copy): 37 (WebCore::SharedBuffer::internallyConsistent): 38 (WebCore::SharedBuffer::hintMemoryNotNeededSoon): 39 (WebCore::SharedBufferDataView::SharedBufferDataView): 40 (WebCore::SharedBufferDataView::size): 41 (WebCore::SharedBufferDataView::data): 42 * platform/SharedBuffer.h: 43 * platform/cf/SharedBufferCF.cpp: 44 (WebCore::SharedBuffer::createCFData): 45 (WebCore::SharedBuffer::hintMemoryNotNeededSoon): 46 (WebCore::SharedBuffer::append): 47 * platform/cocoa/SharedBufferCocoa.mm: 48 (WebCore::SharedBuffer::createNSData): 49 (WebCore::SharedBuffer::createCFData): 50 (WebCore::SharedBuffer::createNSDataArray): 51 1 52 2017-05-22 Chris Dumez <cdumez@apple.com> 2 53 -
trunk/Source/WebCore/loader/TextTrackLoader.cpp
r216217 r217260 92 92 m_cueParser = std::make_unique<WebVTTParser>(static_cast<WebVTTParserClient*>(this), m_scriptExecutionContext); 93 93 94 auto bytesToSkip = m_parseOffset; 95 for (const auto& segment : *buffer) { 96 if (bytesToSkip > segment->size()) { 97 bytesToSkip -= segment->size(); 98 continue; 99 } 100 auto bytesToUse = segment->size() - bytesToSkip; 101 m_cueParser->parseBytes(segment->data() + bytesToSkip, bytesToUse); 102 bytesToSkip = 0; 103 m_parseOffset += bytesToUse; 94 while (m_parseOffset < buffer->size()) { 95 auto data = buffer->getSomeData(m_parseOffset); 96 m_cueParser->parseBytes(data.data(), data.size()); 97 m_parseOffset += data.size(); 104 98 } 105 99 } -
trunk/Source/WebCore/loader/cache/CachedRawResource.cpp
r212449 r217260 45 45 } 46 46 47 const char* CachedRawResource::calculateIncrementalDataChunk(SharedBuffer* data, unsigned& incrementalDataLength) 48 { 49 incrementalDataLength = 0; 50 if (!data) 51 return nullptr; 52 53 unsigned previousDataLength = encodedSize(); 54 ASSERT(data->size() >= previousDataLength); 55 incrementalDataLength = data->size() - previousDataLength; 56 return data->data() + previousDataLength; 47 std::optional<SharedBufferDataView> CachedRawResource::calculateIncrementalDataChunk(const SharedBuffer* data) const 48 { 49 size_t previousDataLength = encodedSize(); 50 if (!data || data->size() <= previousDataLength) 51 return std::nullopt; 52 return data->getSomeData(previousDataLength); 57 53 } 58 54 … … 63 59 m_data = &data; 64 60 65 unsigned incrementalDataLength; 66 const char* incrementalData = calculateIncrementalDataChunk(&data, incrementalDataLength); 61 auto incrementalData = calculateIncrementalDataChunk(&data); 67 62 setEncodedSize(data.size()); 68 notifyClientsDataWasReceived(incrementalData, incrementalDataLength); 63 if (incrementalData) 64 notifyClientsDataWasReceived(incrementalData->data(), incrementalData->size()); 69 65 if (dataBufferingPolicy() == DoNotBufferData) { 70 66 if (m_loader) … … 91 87 m_data = data; 92 88 93 unsigned incrementalDataLength; 94 const char* incrementalData = calculateIncrementalDataChunk(data, incrementalDataLength); 95 if (data) 89 if (auto incrementalData = calculateIncrementalDataChunk(data)) { 96 90 setEncodedSize(data->size()); 97 notifyClientsDataWasReceived(incrementalData, incrementalDataLength); 91 notifyClientsDataWasReceived(incrementalData->data(), incrementalData->size()); 92 } 98 93 } 99 94 -
trunk/Source/WebCore/loader/cache/CachedRawResource.h
r212449 r217260 29 29 class CachedResourceClient; 30 30 class ResourceTiming; 31 class SharedBufferDataView; 31 32 class SubresourceLoader; 32 33 … … 70 71 bool mayTryReplaceEncodedData() const override { return m_allowEncodedDataReplacement; } 71 72 72 const char* calculateIncrementalDataChunk(SharedBuffer*, unsigned& incrementalDataLength);73 std::optional<SharedBufferDataView> calculateIncrementalDataChunk(const SharedBuffer*) const; 73 74 void notifyClientsDataWasReceived(const char* data, unsigned length); 74 75 -
trunk/Source/WebCore/platform/SharedBuffer.cpp
r215686 r217260 51 51 : m_size(fileData.size()) 52 52 { 53 m_segments.append( DataSegment::create(WTFMove(fileData)));53 m_segments.append({0, DataSegment::create(WTFMove(fileData))}); 54 54 } 55 55 … … 77 77 void SharedBuffer::combineIntoOneSegment() const 78 78 { 79 #if !ASSERT_DISABLED 80 // FIXME: We ought to be able to set this to true and have no assertions fire. 81 // Remove all instances of appending after calling this, because they are all O(n^2) algorithms since r215686. 82 // m_hasBeenCombinedIntoOneSegment = true; 83 #endif 79 84 if (m_segments.size() <= 1) 80 85 return; … … 83 88 combinedData.reserveInitialCapacity(m_size); 84 89 for (const auto& segment : m_segments) 85 combinedData.append(segment ->data(),segment->size());90 combinedData.append(segment.segment->data(), segment.segment->size()); 86 91 ASSERT(combinedData.size() == m_size); 87 92 m_segments.clear(); 88 m_segments.append( DataSegment::create(WTFMove(combinedData)));93 m_segments.append({0, DataSegment::create(WTFMove(combinedData))}); 89 94 ASSERT(m_segments.size() == 1); 95 ASSERT(internallyConsistent()); 90 96 } 91 97 … … 95 101 return nullptr; 96 102 combineIntoOneSegment(); 97 return m_segments[0]->data(); 103 ASSERT(internallyConsistent()); 104 return m_segments[0].segment->data(); 105 } 106 107 SharedBufferDataView SharedBuffer::getSomeData(size_t position) const 108 { 109 RELEASE_ASSERT(position < m_size); 110 auto comparator = [](const size_t& position, const DataSegmentVectorEntry& entry) { 111 return position < entry.beginPosition; 112 }; 113 const DataSegmentVectorEntry* element = std::upper_bound(m_segments.begin(), m_segments.end(), position, comparator); 114 element--; // std::upper_bound gives a pointer to the element that is greater than position. We want the element just before that. 115 return { element->segment.copyRef(), position - element->beginPosition }; 98 116 } 99 117 … … 108 126 size_t position = 0; 109 127 for (const auto& segment : m_segments) { 110 memcpy(static_cast<char*>(arrayBuffer->data()) + position, segment ->data(),segment->size());111 position += segment ->size();128 memcpy(static_cast<char*>(arrayBuffer->data()) + position, segment.segment->data(), segment.segment->size()); 129 position += segment.segment->size(); 112 130 } 113 131 114 132 ASSERT(position == m_size); 133 ASSERT(internallyConsistent()); 115 134 return arrayBuffer; 116 135 } … … 118 137 void SharedBuffer::append(const SharedBuffer& data) 119 138 { 120 m_size += data.m_size;139 ASSERT(!m_hasBeenCombinedIntoOneSegment); 121 140 m_segments.reserveCapacity(m_segments.size() + data.m_segments.size()); 122 for (const auto& segment : data.m_segments) 123 m_segments.uncheckedAppend(segment.copyRef()); 141 for (const auto& element : data.m_segments) { 142 m_segments.uncheckedAppend({m_size, element.segment.copyRef()}); 143 m_size += element.segment->size(); 144 } 145 ASSERT(internallyConsistent()); 124 146 } 125 147 126 148 void SharedBuffer::append(const char* data, size_t length) 127 149 { 128 m_size += length;150 ASSERT(!m_hasBeenCombinedIntoOneSegment); 129 151 Vector<char> vector; 130 152 vector.append(data, length); 131 m_segments.append(DataSegment::create(WTFMove(vector))); 153 m_segments.append({m_size, DataSegment::create(WTFMove(vector))}); 154 m_size += length; 155 ASSERT(internallyConsistent()); 132 156 } 133 157 134 158 void SharedBuffer::append(Vector<char>&& data) 135 159 { 136 m_size += data.size(); 137 m_segments.append(DataSegment::create(WTFMove(data))); 160 ASSERT(!m_hasBeenCombinedIntoOneSegment); 161 auto dataSize = data.size(); 162 m_segments.append({m_size, DataSegment::create(WTFMove(data))}); 163 m_size += dataSize; 164 ASSERT(internallyConsistent()); 138 165 } 139 166 … … 142 169 m_size = 0; 143 170 m_segments.clear(); 171 ASSERT(internallyConsistent()); 144 172 } 145 173 … … 149 177 clone->m_size = m_size; 150 178 clone->m_segments.reserveInitialCapacity(m_segments.size()); 151 for (const auto& segment : m_segments) 152 clone->m_segments.uncheckedAppend(segment.copyRef()); 179 for (const auto& element : m_segments) 180 clone->m_segments.uncheckedAppend({element.beginPosition, element.segment.copyRef()}); 181 ASSERT(clone->internallyConsistent()); 182 ASSERT(internallyConsistent()); 153 183 return clone; 154 184 } 185 186 #if !ASSERT_DISABLED 187 bool SharedBuffer::internallyConsistent() const 188 { 189 size_t position = 0; 190 for (const auto& element : m_segments) { 191 if (element.beginPosition != position) 192 return false; 193 position += element.segment->size(); 194 } 195 return position == m_size; 196 } 197 #endif 155 198 156 199 const char* SharedBuffer::DataSegment::data() const … … 170 213 171 214 #if !USE(CF) 172 void SharedBuffer::hintMemoryNotNeededSoon() 215 void SharedBuffer::hintMemoryNotNeededSoon() const 173 216 { 174 217 } … … 188 231 ); 189 232 return WTF::visit(visitor, m_immutableData); 233 } 234 235 SharedBufferDataView::SharedBufferDataView(Ref<SharedBuffer::DataSegment>&& segment, size_t positionWithinSegment) 236 : m_positionWithinSegment(positionWithinSegment) 237 , m_segment(WTFMove(segment)) 238 { 239 ASSERT(positionWithinSegment < m_segment->size()); 240 } 241 242 size_t SharedBufferDataView::size() const 243 { 244 return m_segment->size() - m_positionWithinSegment; 245 } 246 247 const char* SharedBufferDataView::data() const 248 { 249 return m_segment->data() + m_positionWithinSegment; 190 250 } 191 251 -
trunk/Source/WebCore/platform/SharedBuffer.h
r215686 r217260 50 50 51 51 namespace WebCore { 52 52 53 class SharedBufferDataView; 54 53 55 class WEBCORE_EXPORT SharedBuffer : public RefCounted<SharedBuffer> { 54 56 public: … … 61 63 62 64 #if USE(FOUNDATION) 63 RetainPtr<NSData> createNSData() ;65 RetainPtr<NSData> createNSData() const; 64 66 RetainPtr<NSArray> createNSDataArray() const; 65 67 static Ref<SharedBuffer> create(NSData *); 66 68 #endif 67 69 #if USE(CF) 68 RetainPtr<CFDataRef> createCFData() ;70 RetainPtr<CFDataRef> createCFData() const; 69 71 static Ref<SharedBuffer> create(CFDataRef); 70 72 void append(CFDataRef); … … 139 141 }; 140 142 141 using DataSegmentVector = Vector<Ref<DataSegment>, 1>; 143 struct DataSegmentVectorEntry { 144 size_t beginPosition; 145 Ref<DataSegment> segment; 146 }; 147 using DataSegmentVector = Vector<DataSegmentVectorEntry, 1>; 142 148 DataSegmentVector::const_iterator begin() const { return m_segments.begin(); } 143 149 DataSegmentVector::const_iterator end() const { return m_segments.end(); } 150 151 // begin and end take O(1) time, this takes O(log(N)) time. 152 SharedBufferDataView getSomeData(size_t position) const; 144 153 145 void hintMemoryNotNeededSoon() ;154 void hintMemoryNotNeededSoon() const; 146 155 147 156 private: … … 164 173 size_t m_size { 0 }; 165 174 mutable DataSegmentVector m_segments; 175 176 #if !ASSERT_DISABLED 177 mutable bool m_hasBeenCombinedIntoOneSegment { false }; 178 bool internallyConsistent() const; 179 #endif 180 }; 181 182 class WEBCORE_EXPORT SharedBufferDataView { 183 public: 184 SharedBufferDataView(Ref<SharedBuffer::DataSegment>&&, size_t); 185 size_t size() const; 186 const char* data() const; 187 private: 188 size_t m_positionWithinSegment; 189 Ref<SharedBuffer::DataSegment> m_segment; 166 190 }; 167 191 -
trunk/Source/WebCore/platform/cf/SharedBufferCF.cpp
r215845 r217260 42 42 // so only use this version for non-Foundation. 43 43 #if !USE(FOUNDATION) 44 RetainPtr<CFDataRef> SharedBuffer::createCFData() 44 RetainPtr<CFDataRef> SharedBuffer::createCFData() const 45 45 { 46 46 if (m_segments.size() == 1) { 47 if (auto data = WTF::get_if<RetainPtr<CFDataRef>>(m_segments[0] ->m_immutableData))47 if (auto data = WTF::get_if<RetainPtr<CFDataRef>>(m_segments[0].segment->m_immutableData)) 48 48 return *data; 49 49 } … … 57 57 } 58 58 59 void SharedBuffer::hintMemoryNotNeededSoon() 59 void SharedBuffer::hintMemoryNotNeededSoon() const 60 60 { 61 for (const auto& segment: m_segments) {62 if ( segment->hasOneRef()) {63 if (auto data = WTF::get_if<RetainPtr<CFDataRef>>( segment->m_immutableData))61 for (const auto& entry : m_segments) { 62 if (entry.segment->hasOneRef()) { 63 if (auto data = WTF::get_if<RetainPtr<CFDataRef>>(entry.segment->m_immutableData)) 64 64 OSAllocator::hintMemoryNotNeededSoon(const_cast<UInt8*>(CFDataGetBytePtr(data->get())), CFDataGetLength(data->get())); 65 65 } … … 69 69 void SharedBuffer::append(CFDataRef data) 70 70 { 71 ASSERT(!m_hasBeenCombinedIntoOneSegment); 71 72 if (data) { 73 m_segments.append({m_size, DataSegment::create(data)}); 72 74 m_size += CFDataGetLength(data); 73 m_segments.append(DataSegment::create(data));74 75 } 76 ASSERT(internallyConsistent()); 75 77 } 76 78 -
trunk/Source/WebCore/platform/cocoa/SharedBufferCocoa.mm
r215686 r217260 89 89 } 90 90 91 RetainPtr<NSData> SharedBuffer::createNSData() 91 RetainPtr<NSData> SharedBuffer::createNSData() const 92 92 { 93 93 return adoptNS((NSData *)createCFData().leakRef()); 94 94 } 95 95 96 RetainPtr<CFDataRef> SharedBuffer::createCFData() 96 RetainPtr<CFDataRef> SharedBuffer::createCFData() const 97 97 { 98 98 combineIntoOneSegment(); … … 100 100 return adoptCF(CFDataCreate(nullptr, nullptr, 0)); 101 101 ASSERT(m_segments.size() == 1); 102 return adoptCF((CFDataRef)adoptNS([[WebCoreSharedBufferData alloc] initWithSharedBufferDataSegment:m_segments[0] ]).leakRef());102 return adoptCF((CFDataRef)adoptNS([[WebCoreSharedBufferData alloc] initWithSharedBufferDataSegment:m_segments[0].segment]).leakRef()); 103 103 } 104 104 … … 115 115 auto dataArray = adoptNS([[NSMutableArray alloc] initWithCapacity:m_segments.size()]); 116 116 for (const auto& segment : m_segments) 117 [dataArray addObject:adoptNS([[WebCoreSharedBufferData alloc] initWithSharedBufferDataSegment:segment ]).get()];117 [dataArray addObject:adoptNS([[WebCoreSharedBufferData alloc] initWithSharedBufferDataSegment:segment.segment]).get()]; 118 118 return WTFMove(dataArray); 119 119 } -
trunk/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp
r216067 r217260 1207 1207 return; 1208 1208 1209 for (const auto& segment : buffer.get())1210 handleDataReceived( segment->data(),segment->size());1209 for (const auto& element : buffer.get()) 1210 handleDataReceived(element.segment->data(), element.segment->size()); 1211 1211 } 1212 1212 -
trunk/Source/WebCore/platform/image-decoders/ImageDecoder.cpp
r217246 r217260 46 46 { 47 47 unsigned bytesExtracted = 0; 48 for (const auto& segment : sharedBuffer) {49 if (bytesExtracted + segment->size() <= bufferLength) {50 memcpy(buffer + bytesExtracted, segment->data(),segment->size());51 bytesExtracted += segment->size();48 for (const auto& element : sharedBuffer) { 49 if (bytesExtracted + element.segment->size() <= bufferLength) { 50 memcpy(buffer + bytesExtracted, element.segment->data(), element.segment->size()); 51 bytesExtracted += element.segment->size(); 52 52 } else { 53 ASSERT(bufferLength - bytesExtracted < segment->size());54 memcpy(buffer + bytesExtracted, segment->data(), bufferLength - bytesExtracted);53 ASSERT(bufferLength - bytesExtracted < element.segment->size()); 54 memcpy(buffer + bytesExtracted, element.segment->data(), bufferLength - bytesExtracted); 55 55 bytesExtracted = bufferLength; 56 56 break; -
trunk/Source/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp
r216882 r217260 159 159 160 160 auto bytesToSkip = m_readOffset; 161 for (const auto& segment : data) { 162 if (bytesToSkip > segment->size()) { 163 bytesToSkip -= segment->size(); 161 162 // FIXME: Use getSomeData which is O(log(n)) instead of skipping bytes which is O(n). 163 for (const auto& element : data) { 164 if (bytesToSkip > element.segment->size()) { 165 bytesToSkip -= element.segment->size(); 164 166 continue; 165 167 } 166 auto bytesToUse = segment->size() - bytesToSkip;168 auto bytesToUse = element.segment->size() - bytesToSkip; 167 169 m_readOffset += bytesToUse; 168 170 m_currentBufferSize = m_readOffset; 169 png_process_data(m_png, m_info, reinterpret_cast<png_bytep>(const_cast<char*>( segment->data() + bytesToSkip)), bytesToUse);171 png_process_data(m_png, m_info, reinterpret_cast<png_bytep>(const_cast<char*>(element.segment->data() + bytesToSkip)), bytesToUse); 170 172 bytesToSkip = 0; 171 173 // We explicitly specify the superclass encodedDataStatus() because we -
trunk/Source/WebCore/platform/soup/SharedBufferSoup.cpp
r215686 r217260 31 31 ASSERT(soupBuffer); 32 32 m_size = soupBuffer->length; 33 m_segments.append( DataSegment::create(GUniquePtr<SoupBuffer>(soupBuffer)));33 m_segments.append({0, DataSegment::create(GUniquePtr<SoupBuffer>(soupBuffer))}); 34 34 } 35 35 -
trunk/Source/WebKit2/ChangeLog
r217252 r217260 1 2017-05-20 Alex Christensen <achristensen@webkit.org> 2 3 REGRESSION(r215686): O(n^2) algorithm in CachedRawResource::addDataBuffer 4 https://bugs.webkit.org/show_bug.cgi?id=172406 5 <rdar://32109532> 6 7 Reviewed by Brady Eidson. 8 9 * Platform/IPC/DataReference.cpp: 10 (IPC::SharedBufferDataReference::encode): 11 * WebProcess/Plugins/PluginView.cpp: 12 (WebKit::PluginView::redeliverManualStream): 13 1 14 2017-05-22 Yongjun Zhang <yongjun_zhang@apple.com> 2 15 -
trunk/Source/WebKit2/Platform/IPC/DataReference.cpp
r215686 r217260 48 48 encoder << bufferSize; 49 49 50 for (const auto& segment : *m_buffer)51 encoder.encodeFixedLengthData(reinterpret_cast<const uint8_t*>( segment->data()),segment->size(), 1);50 for (const auto& element : *m_buffer) 51 encoder.encodeFixedLengthData(reinterpret_cast<const uint8_t*>(element.segment->data()), element.segment->size(), 1); 52 52 } 53 53 -
trunk/Source/WebKit2/WebProcess/Plugins/PluginView.cpp
r216541 r217260 1312 1312 // Deliver the data. 1313 1313 if (m_manualStreamData) { 1314 for (const auto& segment : *m_manualStreamData)1315 manualLoadDidReceiveData( segment->data(),segment->size());1314 for (const auto& element : *m_manualStreamData) 1315 manualLoadDidReceiveData(element.segment->data(), element.segment->size()); 1316 1316 m_manualStreamData = nullptr; 1317 1317 } -
trunk/Tools/ChangeLog
r217259 r217260 1 2017-05-20 Alex Christensen <achristensen@webkit.org> 2 3 REGRESSION(r215686): O(n^2) algorithm in CachedRawResource::addDataBuffer 4 https://bugs.webkit.org/show_bug.cgi?id=172406 5 <rdar://32109532> 6 7 Reviewed by Brady Eidson. 8 9 * TestWebKitAPI/Tests/WebCore/SharedBuffer.cpp: 10 (TestWebKitAPI::checkBuffer): 11 (TestWebKitAPI::TEST_F): 12 1 13 2017-05-22 Jason Marcell <jmarcell@apple.com> 2 14 -
trunk/Tools/TestWebKitAPI/Tests/WebCore/SharedBuffer.cpp
r215686 r217260 161 161 } 162 162 163 } 163 static void checkBuffer(const char* buffer, size_t bufferLength, const char* expected) 164 { 165 // expected is null terminated, buffer is not. 166 size_t length = strlen(expected); 167 EXPECT_EQ(length, bufferLength); 168 for (size_t i = 0; i < length; ++i) 169 EXPECT_EQ(buffer[i], expected[i]); 170 } 171 172 TEST_F(SharedBufferTest, getSomeData) 173 { 174 Vector<char> s1 = {'a', 'b', 'c', 'd'}; 175 Vector<char> s2 = {'e', 'f', 'g', 'h'}; 176 Vector<char> s3 = {'i', 'j', 'k', 'l'}; 177 178 auto buffer = SharedBuffer::create(); 179 buffer->append(WTFMove(s1)); 180 buffer->append(WTFMove(s2)); 181 buffer->append(WTFMove(s3)); 182 183 auto abcd = buffer->getSomeData(0); 184 auto gh = buffer->getSomeData(6); 185 auto h = buffer->getSomeData(7); 186 auto ijkl = buffer->getSomeData(8); 187 auto kl = buffer->getSomeData(10); 188 auto abcdefghijkl = buffer->data(); 189 auto ghijkl = buffer->getSomeData(6); 190 auto l = buffer->getSomeData(11); 191 checkBuffer(abcd.data(), abcd.size(), "abcd"); 192 checkBuffer(gh.data(), gh.size(), "gh"); 193 checkBuffer(h.data(), h.size(), "h"); 194 checkBuffer(ijkl.data(), ijkl.size(), "ijkl"); 195 checkBuffer(kl.data(), kl.size(), "kl"); 196 checkBuffer(abcdefghijkl, buffer->size(), "abcdefghijkl"); 197 checkBuffer(ghijkl.data(), ghijkl.size(), "ghijkl"); 198 checkBuffer(l.data(), l.size(), "l"); 199 } 200 201 }
Note: See TracChangeset
for help on using the changeset viewer.