+void IOBuf::freeInternalBuf(void* buf, void* userData) {
+ auto* storage = static_cast<HeapStorage*>(userData);
+ releaseStorage(storage, kDataInUse);
+}
+
+IOBuf::IOBuf(CreateOp, uint64_t capacity)
+ : next_(this),
+ prev_(this),
+ data_(nullptr),
+ length_(0),
+ flagsAndSharedInfo_(0) {
+ SharedInfo* info;
+ allocExtBuffer(capacity, &buf_, &info, &capacity_);
+ setSharedInfo(info);
+ data_ = buf_;
+}
+
+IOBuf::IOBuf(CopyBufferOp op, const void* buf, uint64_t size,
+ uint64_t headroom, uint64_t minTailroom)
+ : IOBuf(CREATE, headroom + size + minTailroom) {
+ advance(headroom);
+ memcpy(writableData(), buf, size);
+ append(size);
+}
+
+IOBuf::IOBuf(CopyBufferOp op, ByteRange br,
+ uint64_t headroom, uint64_t minTailroom)
+ : IOBuf(op, br.data(), br.size(), headroom, minTailroom) {
+}
+
+unique_ptr<IOBuf> IOBuf::create(uint64_t capacity) {
+ // For smaller-sized buffers, allocate the IOBuf, SharedInfo, and the buffer
+ // all with a single allocation.
+ //
+ // We don't do this for larger buffers since it can be wasteful if the user
+ // needs to reallocate the buffer but keeps using the same IOBuf object.
+ // In this case we can't free the data space until the IOBuf is also
+ // destroyed. Callers can explicitly call createCombined() or
+ // createSeparate() if they know their use case better, and know if they are
+ // likely to reallocate the buffer later.
+ if (capacity <= kDefaultCombinedBufSize) {
+ return createCombined(capacity);
+ }
+ return createSeparate(capacity);
+}
+
+unique_ptr<IOBuf> IOBuf::createCombined(uint64_t capacity) {
+ // To save a memory allocation, allocate space for the IOBuf object, the
+ // SharedInfo struct, and the data itself all with a single call to malloc().
+ size_t requiredStorage = offsetof(HeapFullStorage, align) + capacity;
+ size_t mallocSize = goodMallocSize(requiredStorage);
+ auto* storage = static_cast<HeapFullStorage*>(malloc(mallocSize));
+
+ new (&storage->hs.prefix) HeapPrefix(kIOBufInUse | kDataInUse);
+ new (&storage->shared) SharedInfo(freeInternalBuf, storage);
+
+ uint8_t* bufAddr = reinterpret_cast<uint8_t*>(&storage->align);
+ uint8_t* storageEnd = reinterpret_cast<uint8_t*>(storage) + mallocSize;
+ size_t actualCapacity = storageEnd - bufAddr;
+ unique_ptr<IOBuf> ret(new (&storage->hs.buf) IOBuf(
+ InternalConstructor(), packFlagsAndSharedInfo(0, &storage->shared),
+ bufAddr, actualCapacity, bufAddr, 0));
+ return ret;
+}
+
+unique_ptr<IOBuf> IOBuf::createSeparate(uint64_t capacity) {
+ return make_unique<IOBuf>(CREATE, capacity);
+}