2 * Copyright 2013 Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "folly/io/IOBuf.h"
18 #include "folly/io/TypedIOBuf.h"
20 // googletest requires std::tr1::tuple, not std::tuple
23 #include <gflags/gflags.h>
24 #include <boost/random.hpp>
25 #include <gtest/gtest.h>
27 #include "folly/Malloc.h"
28 #include "folly/Range.h"
30 using folly::fbstring;
32 using folly::TypedIOBuf;
33 using folly::StringPiece;
34 using folly::ByteRange;
35 using std::unique_ptr;
37 void append(std::unique_ptr<IOBuf>& buf, StringPiece str) {
38 EXPECT_LE(str.size(), buf->tailroom());
39 memcpy(buf->writableData(), str.data(), str.size());
40 buf->append(str.size());
43 void prepend(std::unique_ptr<IOBuf>& buf, StringPiece str) {
44 EXPECT_LE(str.size(), buf->headroom());
45 memcpy(buf->writableData() - str.size(), str.data(), str.size());
46 buf->prepend(str.size());
50 unique_ptr<IOBuf> buf(IOBuf::create(100));
51 uint32_t cap = buf->capacity();
53 EXPECT_EQ(0, buf->headroom());
54 EXPECT_EQ(0, buf->length());
55 EXPECT_EQ(cap, buf->tailroom());
59 EXPECT_EQ(10, buf->headroom());
60 EXPECT_EQ(5, buf->length());
61 EXPECT_EQ(cap - 15, buf->tailroom());
63 prepend(buf, "hello ");
64 EXPECT_EQ(4, buf->headroom());
65 EXPECT_EQ(11, buf->length());
66 EXPECT_EQ(cap - 15, buf->tailroom());
68 const char* p = reinterpret_cast<const char*>(buf->data());
69 EXPECT_EQ("hello world", std::string(p, buf->length()));
72 EXPECT_EQ(0, buf->headroom());
73 EXPECT_EQ(0, buf->length());
74 EXPECT_EQ(cap, buf->tailroom());
78 void testAllocSize(uint32_t requestedCapacity) {
79 unique_ptr<IOBuf> iobuf(IOBuf::create(requestedCapacity));
80 EXPECT_GE(iobuf->capacity(), requestedCapacity);
83 TEST(IOBuf, AllocSizes) {
84 // Try with a small allocation size that should fit in the internal buffer
87 // Try with a large allocation size that will require an external buffer.
90 // 220 bytes is currently the cutoff
91 // (It would be nice to use the IOBuf::kMaxInternalDataSize constant,
92 // but it's private and it doesn't seem worth making it public just for this
99 void deleteArrayBuffer(void *buf, void* arg) {
100 uint32_t* deleteCount = static_cast<uint32_t*>(arg);
102 uint8_t* bufPtr = static_cast<uint8_t*>(buf);
106 TEST(IOBuf, TakeOwnership) {
108 uint8_t *buf1 = static_cast<uint8_t*>(malloc(size1));
109 unique_ptr<IOBuf> iobuf1(IOBuf::takeOwnership(buf1, size1));
110 EXPECT_EQ(buf1, iobuf1->data());
111 EXPECT_EQ(size1, iobuf1->length());
112 EXPECT_EQ(buf1, iobuf1->buffer());
113 EXPECT_EQ(size1, iobuf1->capacity());
115 uint32_t deleteCount = 0;
116 uint32_t size2 = 4321;
117 uint8_t *buf2 = new uint8_t[size2];
118 unique_ptr<IOBuf> iobuf2(IOBuf::takeOwnership(buf2, size2,
121 EXPECT_EQ(buf2, iobuf2->data());
122 EXPECT_EQ(size2, iobuf2->length());
123 EXPECT_EQ(buf2, iobuf2->buffer());
124 EXPECT_EQ(size2, iobuf2->capacity());
125 EXPECT_EQ(0, deleteCount);
127 EXPECT_EQ(1, deleteCount);
130 uint32_t size3 = 3456;
131 uint8_t *buf3 = new uint8_t[size3];
132 uint32_t length3 = 48;
133 unique_ptr<IOBuf> iobuf3(IOBuf::takeOwnership(buf3, size3, length3,
136 EXPECT_EQ(buf3, iobuf3->data());
137 EXPECT_EQ(length3, iobuf3->length());
138 EXPECT_EQ(buf3, iobuf3->buffer());
139 EXPECT_EQ(size3, iobuf3->capacity());
140 EXPECT_EQ(0, deleteCount);
142 EXPECT_EQ(1, deleteCount);
147 TEST(IOBuf, WrapBuffer) {
148 const uint32_t size1 = 1234;
150 unique_ptr<IOBuf> iobuf1(IOBuf::wrapBuffer(buf1, size1));
151 EXPECT_EQ(buf1, iobuf1->data());
152 EXPECT_EQ(size1, iobuf1->length());
153 EXPECT_EQ(buf1, iobuf1->buffer());
154 EXPECT_EQ(size1, iobuf1->capacity());
156 uint32_t size2 = 0x1234;
157 unique_ptr<uint8_t[]> buf2(new uint8_t[size2]);
158 unique_ptr<IOBuf> iobuf2(IOBuf::wrapBuffer(buf2.get(), size2));
159 EXPECT_EQ(buf2.get(), iobuf2->data());
160 EXPECT_EQ(size2, iobuf2->length());
161 EXPECT_EQ(buf2.get(), iobuf2->buffer());
162 EXPECT_EQ(size2, iobuf2->capacity());
165 void fillBuf(uint8_t* buf, uint32_t length, boost::mt19937& gen) {
166 for (uint32_t n = 0; n < length; ++n) {
167 buf[n] = static_cast<uint8_t>(gen() & 0xff);
171 void fillBuf(IOBuf* buf, boost::mt19937& gen) {
173 fillBuf(buf->writableData(), buf->length(), gen);
176 void checkBuf(const uint8_t* buf, uint32_t length, boost::mt19937& gen) {
177 // Rather than using EXPECT_EQ() to check each character,
178 // count the number of differences and the first character that differs.
179 // This way on error we'll report just that information, rather than tons of
180 // failed checks for each byte in the buffer.
181 uint32_t numDifferences = 0;
182 uint32_t firstDiffIndex = 0;
183 uint8_t firstDiffExpected = 0;
184 for (uint32_t n = 0; n < length; ++n) {
185 uint8_t expected = static_cast<uint8_t>(gen() & 0xff);
186 if (buf[n] == expected) {
190 if (numDifferences == 0) {
192 firstDiffExpected = expected;
197 EXPECT_EQ(0, numDifferences);
198 if (numDifferences > 0) {
199 // Cast to int so it will be printed numerically
200 // rather than as a char if the check fails
201 EXPECT_EQ(static_cast<int>(buf[firstDiffIndex]),
202 static_cast<int>(firstDiffExpected));
206 void checkBuf(IOBuf* buf, boost::mt19937& gen) {
207 checkBuf(buf->data(), buf->length(), gen);
210 void checkBuf(ByteRange buf, boost::mt19937& gen) {
211 checkBuf(buf.data(), buf.size(), gen);
214 void checkChain(IOBuf* buf, boost::mt19937& gen) {
215 IOBuf *current = buf;
217 checkBuf(current->data(), current->length(), gen);
218 current = current->next();
219 } while (current != buf);
222 TEST(IOBuf, Chaining) {
223 uint32_t fillSeed = 0x12345678;
224 boost::mt19937 gen(fillSeed);
226 // An IOBuf with external storage
227 uint32_t headroom = 123;
228 unique_ptr<IOBuf> iob1(IOBuf::create(2048));
229 iob1->advance(headroom);
231 fillBuf(iob1.get(), gen);
233 // An IOBuf with internal storage
234 unique_ptr<IOBuf> iob2(IOBuf::create(20));
236 fillBuf(iob2.get(), gen);
238 // An IOBuf around a buffer it doesn't own
239 uint8_t localbuf[1234];
240 fillBuf(localbuf, 1234, gen);
241 unique_ptr<IOBuf> iob3(IOBuf::wrapBuffer(localbuf, sizeof(localbuf)));
243 // An IOBuf taking ownership of a user-supplied buffer
244 uint32_t heapBufSize = 900;
245 uint8_t* heapBuf = static_cast<uint8_t*>(malloc(heapBufSize));
246 fillBuf(heapBuf, heapBufSize, gen);
247 unique_ptr<IOBuf> iob4(IOBuf::takeOwnership(heapBuf, heapBufSize));
249 // An IOBuf taking ownership of a user-supplied buffer with
250 // a custom free function
251 uint32_t arrayBufSize = 321;
252 uint8_t* arrayBuf = new uint8_t[arrayBufSize];
253 fillBuf(arrayBuf, arrayBufSize, gen);
254 uint32_t arrayBufFreeCount = 0;
255 unique_ptr<IOBuf> iob5(IOBuf::takeOwnership(arrayBuf, arrayBufSize,
257 &arrayBufFreeCount));
259 EXPECT_FALSE(iob1->isChained());
260 EXPECT_FALSE(iob2->isChained());
261 EXPECT_FALSE(iob3->isChained());
262 EXPECT_FALSE(iob4->isChained());
263 EXPECT_FALSE(iob5->isChained());
265 EXPECT_FALSE(iob1->isSharedOne());
266 EXPECT_FALSE(iob2->isSharedOne());
267 EXPECT_TRUE(iob3->isSharedOne()); // since we own the buffer
268 EXPECT_FALSE(iob4->isSharedOne());
269 EXPECT_FALSE(iob5->isSharedOne());
271 // Chain the buffers all together
272 // Since we are going to relinquish ownership of iob2-5 to the chain,
273 // store raw pointers to them so we can reference them later.
274 IOBuf* iob2ptr = iob2.get();
275 IOBuf* iob3ptr = iob3.get();
276 IOBuf* iob4ptr = iob4.get();
277 IOBuf* iob5ptr = iob5.get();
279 iob1->prependChain(std::move(iob2));
280 iob1->prependChain(std::move(iob4));
281 iob2ptr->appendChain(std::move(iob3));
282 iob1->prependChain(std::move(iob5));
284 EXPECT_EQ(iob2ptr, iob1->next());
285 EXPECT_EQ(iob3ptr, iob2ptr->next());
286 EXPECT_EQ(iob4ptr, iob3ptr->next());
287 EXPECT_EQ(iob5ptr, iob4ptr->next());
288 EXPECT_EQ(iob1.get(), iob5ptr->next());
290 EXPECT_EQ(iob5ptr, iob1->prev());
291 EXPECT_EQ(iob1.get(), iob2ptr->prev());
292 EXPECT_EQ(iob2ptr, iob3ptr->prev());
293 EXPECT_EQ(iob3ptr, iob4ptr->prev());
294 EXPECT_EQ(iob4ptr, iob5ptr->prev());
296 EXPECT_TRUE(iob1->isChained());
297 EXPECT_TRUE(iob2ptr->isChained());
298 EXPECT_TRUE(iob3ptr->isChained());
299 EXPECT_TRUE(iob4ptr->isChained());
300 EXPECT_TRUE(iob5ptr->isChained());
302 uint64_t fullLength = (iob1->length() + iob2ptr->length() +
303 iob3ptr->length() + iob4ptr->length() +
305 EXPECT_EQ(5, iob1->countChainElements());
306 EXPECT_EQ(fullLength, iob1->computeChainDataLength());
308 // Since iob3 is shared, the entire buffer should report itself as shared
309 EXPECT_TRUE(iob1->isShared());
311 iob3ptr->unshareOne();
312 EXPECT_FALSE(iob3ptr->isSharedOne());
313 // Now everything in the chain should be unshared.
314 // Check on all members of the chain just for good measure
315 EXPECT_FALSE(iob1->isShared());
316 EXPECT_FALSE(iob2ptr->isShared());
317 EXPECT_FALSE(iob3ptr->isShared());
318 EXPECT_FALSE(iob4ptr->isShared());
319 EXPECT_FALSE(iob5ptr->isShared());
324 for (auto buf : *iob1) {
330 // Clone one of the IOBufs in the chain
331 unique_ptr<IOBuf> iob4clone = iob4ptr->cloneOne();
333 checkBuf(iob1.get(), gen);
334 checkBuf(iob2ptr, gen);
335 checkBuf(iob3ptr, gen);
336 checkBuf(iob4clone.get(), gen);
337 checkBuf(iob5ptr, gen);
339 EXPECT_TRUE(iob1->isShared());
340 EXPECT_TRUE(iob2ptr->isShared());
341 EXPECT_TRUE(iob3ptr->isShared());
342 EXPECT_TRUE(iob4ptr->isShared());
343 EXPECT_TRUE(iob5ptr->isShared());
345 EXPECT_FALSE(iob1->isSharedOne());
346 EXPECT_FALSE(iob2ptr->isSharedOne());
347 EXPECT_FALSE(iob3ptr->isSharedOne());
348 EXPECT_TRUE(iob4ptr->isSharedOne());
349 EXPECT_FALSE(iob5ptr->isSharedOne());
351 // Unshare that clone
352 EXPECT_TRUE(iob4clone->isSharedOne());
353 iob4clone->unshare();
354 EXPECT_FALSE(iob4clone->isSharedOne());
355 EXPECT_FALSE(iob4ptr->isSharedOne());
356 EXPECT_FALSE(iob1->isShared());
360 // Create a clone of a different IOBuf
361 EXPECT_FALSE(iob1->isShared());
362 EXPECT_FALSE(iob3ptr->isSharedOne());
364 unique_ptr<IOBuf> iob3clone = iob3ptr->cloneOne();
366 checkBuf(iob1.get(), gen);
367 checkBuf(iob2ptr, gen);
368 checkBuf(iob3clone.get(), gen);
369 checkBuf(iob4ptr, gen);
370 checkBuf(iob5ptr, gen);
372 EXPECT_TRUE(iob1->isShared());
373 EXPECT_TRUE(iob3ptr->isSharedOne());
374 EXPECT_FALSE(iob1->isSharedOne());
376 // Delete the clone and make sure the original is unshared
378 EXPECT_FALSE(iob1->isShared());
379 EXPECT_FALSE(iob3ptr->isSharedOne());
382 // Clone the entire chain
383 unique_ptr<IOBuf> chainClone = iob1->clone();
384 // Verify that the data is correct.
385 EXPECT_EQ(fullLength, chainClone->computeChainDataLength());
387 checkChain(chainClone.get(), gen);
389 // Check that the buffers report sharing correctly
390 EXPECT_TRUE(chainClone->isShared());
391 EXPECT_TRUE(iob1->isShared());
393 EXPECT_TRUE(iob1->isSharedOne());
394 // since iob2 has a small internal buffer, it will never be shared
395 EXPECT_FALSE(iob2ptr->isSharedOne());
396 EXPECT_TRUE(iob3ptr->isSharedOne());
397 EXPECT_TRUE(iob4ptr->isSharedOne());
398 EXPECT_TRUE(iob5ptr->isSharedOne());
400 // Unshare the cloned chain
401 chainClone->unshare();
402 EXPECT_FALSE(chainClone->isShared());
403 EXPECT_FALSE(iob1->isShared());
405 // Make sure the unshared result still has the same data
406 EXPECT_EQ(fullLength, chainClone->computeChainDataLength());
408 checkChain(chainClone.get(), gen);
410 // Destroy this chain
415 EXPECT_FALSE(iob1->isShared());
416 chainClone = iob1->clone();
417 EXPECT_TRUE(iob1->isShared());
418 EXPECT_TRUE(chainClone->isShared());
420 // Delete the original chain
422 EXPECT_FALSE(chainClone->isShared());
424 // Coalesce the chain
426 // Coalescing this chain will create a new buffer and release the last
427 // refcount on the original buffers we created. Also make sure
428 // that arrayBufFreeCount increases to one to indicate that arrayBuf was
430 EXPECT_EQ(5, chainClone->countChainElements());
431 EXPECT_EQ(0, arrayBufFreeCount);
433 // Buffer lengths: 1500 20 1234 900 321
434 // Coalesce the first 3 buffers
435 chainClone->gather(1521);
436 EXPECT_EQ(3, chainClone->countChainElements());
437 EXPECT_EQ(0, arrayBufFreeCount);
439 // Make sure the data is still the same after coalescing
440 EXPECT_EQ(fullLength, chainClone->computeChainDataLength());
442 checkChain(chainClone.get(), gen);
444 // Coalesce the entire chain
445 chainClone->coalesce();
446 EXPECT_EQ(1, chainClone->countChainElements());
447 EXPECT_EQ(1, arrayBufFreeCount);
449 // Make sure the data is still the same after coalescing
450 EXPECT_EQ(fullLength, chainClone->computeChainDataLength());
452 checkChain(chainClone.get(), gen);
454 // Make a new chain to test the unlink and pop operations
455 iob1 = IOBuf::create(1);
457 IOBuf *iob1ptr = iob1.get();
458 iob2 = IOBuf::create(3);
460 iob2ptr = iob2.get();
461 iob3 = IOBuf::create(5);
463 iob3ptr = iob3.get();
464 iob4 = IOBuf::create(7);
466 iob4ptr = iob4.get();
467 iob1->appendChain(std::move(iob2));
468 iob1->prev()->appendChain(std::move(iob3));
469 iob1->prev()->appendChain(std::move(iob4));
470 EXPECT_EQ(4, iob1->countChainElements());
471 EXPECT_EQ(16, iob1->computeChainDataLength());
473 // Unlink from the middle of the chain
474 iob3 = iob3ptr->unlink();
475 EXPECT_TRUE(iob3.get() == iob3ptr);
476 EXPECT_EQ(3, iob1->countChainElements());
477 EXPECT_EQ(11, iob1->computeChainDataLength());
479 // Unlink from the end of the chain
480 iob4 = iob1->prev()->unlink();
481 EXPECT_TRUE(iob4.get() == iob4ptr);
482 EXPECT_EQ(2, iob1->countChainElements());
483 EXPECT_TRUE(iob1->next() == iob2ptr);
484 EXPECT_EQ(4, iob1->computeChainDataLength());
486 // Pop from the front of the chain
488 EXPECT_TRUE(iob1.get() == iob1ptr);
489 EXPECT_EQ(1, iob1->countChainElements());
490 EXPECT_EQ(1, iob1->computeChainDataLength());
491 EXPECT_TRUE(iob2.get() == iob2ptr);
492 EXPECT_EQ(1, iob2->countChainElements());
493 EXPECT_EQ(3, iob2->computeChainDataLength());
496 TEST(IOBuf, Reserve) {
497 uint32_t fillSeed = 0x23456789;
498 boost::mt19937 gen(fillSeed);
500 // Reserve does nothing if empty and doesn't have to grow the buffer
503 unique_ptr<IOBuf> iob(IOBuf::create(2000));
504 EXPECT_EQ(0, iob->headroom());
505 const void* p1 = iob->buffer();
507 EXPECT_LE(5, iob->headroom());
508 EXPECT_EQ(p1, iob->buffer());
511 // Reserve doesn't reallocate if we have enough total room
514 unique_ptr<IOBuf> iob(IOBuf::create(2000));
516 fillBuf(iob.get(), gen);
517 EXPECT_EQ(0, iob->headroom());
518 EXPECT_EQ(100, iob->length());
519 const void* p1 = iob->buffer();
520 const uint8_t* d1 = iob->data();
521 iob->reserve(100, 1800);
522 EXPECT_LE(100, iob->headroom());
523 EXPECT_EQ(p1, iob->buffer());
524 EXPECT_EQ(d1 + 100, iob->data());
526 checkBuf(iob.get(), gen);
529 // Reserve reallocates if we don't have enough total room.
530 // NOTE that, with jemalloc, we know that this won't reallocate in place
531 // as the size is less than jemallocMinInPlaceExpanadable
534 unique_ptr<IOBuf> iob(IOBuf::create(2000));
536 fillBuf(iob.get(), gen);
537 EXPECT_EQ(0, iob->headroom());
538 EXPECT_EQ(100, iob->length());
539 const void* p1 = iob->buffer();
540 const uint8_t* d1 = iob->data();
541 iob->reserve(100, 2512); // allocation sizes are multiples of 256
542 EXPECT_LE(100, iob->headroom());
543 if (folly::usingJEMalloc()) {
544 EXPECT_NE(p1, iob->buffer());
547 checkBuf(iob.get(), gen);
550 // Test reserve from internal buffer, this used to segfault
552 unique_ptr<IOBuf> iob(IOBuf::create(0));
553 iob->reserve(0, 2000);
554 EXPECT_EQ(0, iob->headroom());
555 EXPECT_LE(2000, iob->tailroom());
559 TEST(IOBuf, copyBuffer) {
560 std::string s("hello");
561 auto buf = IOBuf::copyBuffer(s.data(), s.size(), 1, 2);
562 EXPECT_EQ(1, buf->headroom());
563 EXPECT_EQ(s, std::string(reinterpret_cast<const char*>(buf->data()),
565 EXPECT_LE(2, buf->tailroom());
567 buf = IOBuf::copyBuffer(s, 5, 7);
568 EXPECT_EQ(5, buf->headroom());
569 EXPECT_EQ(s, std::string(reinterpret_cast<const char*>(buf->data()),
571 EXPECT_LE(7, buf->tailroom());
574 buf = IOBuf::copyBuffer(empty, 3, 6);
575 EXPECT_EQ(3, buf->headroom());
576 EXPECT_EQ(0, buf->length());
577 EXPECT_LE(6, buf->tailroom());
580 TEST(IOBuf, maybeCopyBuffer) {
581 std::string s("this is a test");
582 auto buf = IOBuf::maybeCopyBuffer(s, 1, 2);
583 EXPECT_EQ(1, buf->headroom());
584 EXPECT_EQ(s, std::string(reinterpret_cast<const char*>(buf->data()),
586 EXPECT_LE(2, buf->tailroom());
589 buf = IOBuf::maybeCopyBuffer("", 5, 7);
590 EXPECT_EQ(nullptr, buf.get());
592 buf = IOBuf::maybeCopyBuffer("");
593 EXPECT_EQ(nullptr, buf.get());
598 int customDeleterCount = 0;
599 int destructorCount = 0;
600 struct OwnershipTestClass {
601 explicit OwnershipTestClass(int v = 0) : val(v) { }
602 ~OwnershipTestClass() {
608 typedef std::function<void(OwnershipTestClass*)> CustomDeleter;
610 void customDelete(OwnershipTestClass* p) {
611 ++customDeleterCount;
615 void customDeleteArray(OwnershipTestClass* p) {
616 ++customDeleterCount;
622 TEST(IOBuf, takeOwnershipUniquePtr) {
625 std::unique_ptr<OwnershipTestClass> p(new OwnershipTestClass());
627 EXPECT_EQ(1, destructorCount);
631 std::unique_ptr<OwnershipTestClass[]> p(new OwnershipTestClass[2]);
633 EXPECT_EQ(2, destructorCount);
637 std::unique_ptr<OwnershipTestClass> p(new OwnershipTestClass());
638 std::unique_ptr<IOBuf> buf(IOBuf::takeOwnership(std::move(p)));
639 EXPECT_EQ(sizeof(OwnershipTestClass), buf->length());
640 EXPECT_EQ(0, destructorCount);
642 EXPECT_EQ(1, destructorCount);
646 std::unique_ptr<OwnershipTestClass[]> p(new OwnershipTestClass[2]);
647 std::unique_ptr<IOBuf> buf(IOBuf::takeOwnership(std::move(p), 2));
648 EXPECT_EQ(2 * sizeof(OwnershipTestClass), buf->length());
649 EXPECT_EQ(0, destructorCount);
651 EXPECT_EQ(2, destructorCount);
653 customDeleterCount = 0;
656 std::unique_ptr<OwnershipTestClass, CustomDeleter>
657 p(new OwnershipTestClass(), customDelete);
658 std::unique_ptr<IOBuf> buf(IOBuf::takeOwnership(std::move(p)));
659 EXPECT_EQ(sizeof(OwnershipTestClass), buf->length());
660 EXPECT_EQ(0, destructorCount);
662 EXPECT_EQ(1, destructorCount);
663 EXPECT_EQ(1, customDeleterCount);
665 customDeleterCount = 0;
668 std::unique_ptr<OwnershipTestClass[], CustomDeleter>
669 p(new OwnershipTestClass[2], customDeleteArray);
670 std::unique_ptr<IOBuf> buf(IOBuf::takeOwnership(std::move(p), 2));
671 EXPECT_EQ(2 * sizeof(OwnershipTestClass), buf->length());
672 EXPECT_EQ(0, destructorCount);
674 EXPECT_EQ(2, destructorCount);
675 EXPECT_EQ(1, customDeleterCount);
678 TEST(IOBuf, Alignment) {
679 // max_align_t doesn't exist in gcc 4.6.2
682 } __attribute__((aligned));
683 size_t alignment = alignof(MaxAlign);
685 std::vector<size_t> sizes {0, 1, 64, 256, 1024, 1 << 10};
686 for (size_t size : sizes) {
687 auto buf = IOBuf::create(size);
688 uintptr_t p = reinterpret_cast<uintptr_t>(buf->data());
689 EXPECT_EQ(0, p & (alignment - 1)) << "size=" << size;
693 TEST(TypedIOBuf, Simple) {
694 auto buf = IOBuf::create(0);
695 TypedIOBuf<uint64_t> typed(buf.get());
696 const uint64_t n = 10000;
698 EXPECT_LE(n, typed.capacity());
699 for (uint64_t i = 0; i < n; i++) {
700 *typed.writableTail() = i;
703 EXPECT_EQ(n, typed.length());
704 for (uint64_t i = 0; i < n; i++) {
705 EXPECT_EQ(i, typed.data()[i]);
709 // chain element size, number of elements in chain, shared
710 class MoveToFbStringTest
711 : public ::testing::TestWithParam<std::tr1::tuple<int, int, bool>> {
714 std::tr1::tie(elementSize_, elementCount_, shared_) = GetParam();
716 for (int i = 0; i < elementCount_ - 1; ++i) {
717 buf_->prependChain(makeBuf());
719 EXPECT_EQ(elementCount_, buf_->countChainElements());
720 EXPECT_EQ(elementCount_ * elementSize_, buf_->computeChainDataLength());
722 buf2_ = buf_->clone();
723 EXPECT_EQ(elementCount_, buf2_->countChainElements());
724 EXPECT_EQ(elementCount_ * elementSize_, buf2_->computeChainDataLength());
728 std::unique_ptr<IOBuf> makeBuf() {
729 auto buf = IOBuf::create(elementSize_);
730 memset(buf->writableTail(), 'x', elementSize_);
731 buf->append(elementSize_);
735 void check(std::unique_ptr<IOBuf>& buf) {
736 fbstring str = buf->moveToFbString();
737 EXPECT_EQ(elementCount_ * elementSize_, str.size());
738 EXPECT_EQ(elementCount_ * elementSize_, strspn(str.c_str(), "x"));
739 EXPECT_EQ(0, buf->length());
740 EXPECT_EQ(1, buf->countChainElements());
741 EXPECT_EQ(0, buf->computeChainDataLength());
742 EXPECT_FALSE(buf->isChained());
748 std::unique_ptr<IOBuf> buf_;
749 std::unique_ptr<IOBuf> buf2_;
752 TEST_P(MoveToFbStringTest, Simple) {
759 INSTANTIATE_TEST_CASE_P(
763 ::testing::Values(0, 1, 24, 256, 1 << 10, 1 << 20), // element size
764 ::testing::Values(1, 2, 10), // element count
765 ::testing::Bool())); // shared
767 int main(int argc, char** argv) {
768 testing::InitGoogleTest(&argc, argv);
769 google::ParseCommandLineFlags(&argc, &argv, true);
771 return RUN_ALL_TESTS();