/*
- * Copyright 2016 Facebook, Inc.
+ * Copyright 2013-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <folly/io/IOBuf.h>
+#include <cassert>
+#include <cstdint>
+#include <cstdlib>
+#include <stdexcept>
+
#include <folly/Conv.h>
#include <folly/Likely.h>
-#include <folly/Malloc.h>
#include <folly/Memory.h>
#include <folly/ScopeGuard.h>
-#include <folly/SpookyHashV2.h>
+#include <folly/hash/SpookyHashV2.h>
#include <folly/io/Cursor.h>
-
-#include <stdexcept>
-#include <assert.h>
-#include <stdint.h>
-#include <stdlib.h>
+#include <folly/lang/Align.h>
+#include <folly/memory/Malloc.h>
using std::unique_ptr;
}
}
-} // unnamed namespace
+} // namespace
namespace folly {
struct IOBuf::HeapPrefix {
- HeapPrefix(uint16_t flg)
- : magic(kHeapMagic),
- flags(flg) {}
+ explicit HeapPrefix(uint16_t flg) : magic(kHeapMagic), flags(flg) {}
~HeapPrefix() {
// Reset magic to 0 on destruction. This is solely for debugging purposes
// to help catch bugs where someone tries to use HeapStorage after it has
HeapStorage hs;
SharedInfo shared;
- std::max_align_t align;
+ folly::max_align_t align;
};
IOBuf::SharedInfo::SharedInfo()
void* IOBuf::operator new(size_t size) {
size_t fullSize = offsetof(HeapStorage, buf) + size;
auto* storage = static_cast<HeapStorage*>(malloc(fullSize));
- // operator new is not allowed to return NULL
+ // operator new is not allowed to return nullptr
if (UNLIKELY(storage == nullptr)) {
throw std::bad_alloc();
}
DCHECK_EQ((flags & freeFlags), freeFlags);
while (true) {
- uint16_t newFlags = (flags & ~freeFlags);
+ uint16_t newFlags = uint16_t(flags & ~freeFlags);
if (newFlags == 0) {
// The storage space is now unused. Free it.
storage->prefix.HeapPrefix::~HeapPrefix();
uint64_t minTailroom)
: IOBuf(CREATE, headroom + size + minTailroom) {
advance(headroom);
- memcpy(writableData(), buf, size);
- append(size);
+ if (size > 0) {
+ assert(buf != nullptr);
+ memcpy(writableData(), buf, size);
+ append(size);
+ }
}
IOBuf::IOBuf(CopyBufferOp op, ByteRange br,
uint8_t* bufAddr = reinterpret_cast<uint8_t*>(&storage->align);
uint8_t* storageEnd = reinterpret_cast<uint8_t*>(storage) + mallocSize;
- size_t actualCapacity = storageEnd - bufAddr;
+ size_t actualCapacity = size_t(storageEnd - bufAddr);
unique_ptr<IOBuf> ret(new (&storage->hs.buf) IOBuf(
InternalConstructor(), packFlagsAndSharedInfo(0, &storage->shared),
bufAddr, actualCapacity, bufAddr, 0));
}
unique_ptr<IOBuf> IOBuf::createSeparate(uint64_t capacity) {
- return make_unique<IOBuf>(CREATE, capacity);
+ return std::make_unique<IOBuf>(CREATE, capacity);
}
unique_ptr<IOBuf> IOBuf::createChain(
//
// Note that we always pass freeOnError as false to the constructor.
// If the constructor throws we'll handle it below. (We have to handle
- // allocation failures from make_unique too.)
- return make_unique<IOBuf>(TAKE_OWNERSHIP, buf, capacity, length,
- freeFn, userData, false);
+ // allocation failures from std::make_unique too.)
+ return std::make_unique<IOBuf>(
+ TAKE_OWNERSHIP, buf, capacity, length, freeFn, userData, false);
} catch (...) {
takeOwnershipError(freeOnError, buf, freeFn, userData);
throw;
}
unique_ptr<IOBuf> IOBuf::wrapBuffer(const void* buf, uint64_t capacity) {
- return make_unique<IOBuf>(WRAP_BUFFER, buf, capacity);
+ return std::make_unique<IOBuf>(WRAP_BUFFER, buf, capacity);
}
IOBuf IOBuf::wrapBufferAsValue(const void* buf, uint64_t capacity) {
}
unique_ptr<IOBuf> IOBuf::clone() const {
- return make_unique<IOBuf>(cloneAsValue());
+ return std::make_unique<IOBuf>(cloneAsValue());
}
unique_ptr<IOBuf> IOBuf::cloneOne() const {
- return make_unique<IOBuf>(cloneOneAsValue());
+ return std::make_unique<IOBuf>(cloneOneAsValue());
+}
+
+unique_ptr<IOBuf> IOBuf::cloneCoalesced() const {
+ return std::make_unique<IOBuf>(cloneCoalescedAsValue());
}
IOBuf IOBuf::cloneAsValue() const {
length_);
}
+IOBuf IOBuf::cloneCoalescedAsValue() const {
+ if (!isChained()) {
+ return cloneOneAsValue();
+ }
+ // Coalesce into newBuf
+ const uint64_t newLength = computeChainDataLength();
+ const uint64_t newHeadroom = headroom();
+ const uint64_t newTailroom = prev()->tailroom();
+ const uint64_t newCapacity = newLength + newHeadroom + newTailroom;
+ IOBuf newBuf{CREATE, newCapacity};
+ newBuf.advance(newHeadroom);
+
+ auto current = this;
+ do {
+ if (current->length() > 0) {
+ DCHECK_NOTNULL(current->data());
+ DCHECK_LE(current->length(), newBuf.tailroom());
+ memcpy(newBuf.writableTail(), current->data(), current->length());
+ newBuf.append(current->length());
+ }
+ current = current->next();
+ } while (current != this);
+
+ DCHECK_EQ(newLength, newBuf.length());
+ DCHECK_EQ(newHeadroom, newBuf.headroom());
+ DCHECK_LE(newTailroom, newBuf.tailroom());
+
+ return newBuf;
+}
+
void IOBuf::unshareOneSlow() {
// Allocate a new buffer for the data
uint8_t* buf;
// Maintain the same amount of headroom. Since we maintained the same
// minimum capacity we also maintain at least the same amount of tailroom.
uint64_t headlen = headroom();
- memcpy(buf + headlen, data_, length_);
+ if (length_ > 0) {
+ assert(data_ != nullptr);
+ memcpy(buf + headlen, data_, length_);
+ }
// Release our reference on the old buffer
decrementRefcount();
coalesceSlow();
}
+void IOBuf::markExternallyShared() {
+ IOBuf* current = this;
+ do {
+ current->markExternallySharedOne();
+ current = current->next_;
+ } while (current != this);
+}
+
void IOBuf::makeManagedChained() {
assert(isChained());
IOBuf* current = this;
size_t remaining = newLength;
do {
- assert(current->length_ <= remaining);
- remaining -= current->length_;
- memcpy(p, current->data_, current->length_);
- p += current->length_;
+ if (current->length_ > 0) {
+ assert(current->length_ <= remaining);
+ assert(current->data_ != nullptr);
+ remaining -= current->length_;
+ memcpy(p, current->data_, current->length_);
+ p += current->length_;
+ }
current = current->next_;
} while (current != end);
assert(remaining == 0);
// - If using jemalloc, we can try to expand in place, avoiding a memcpy()
// - If not using jemalloc and we don't have too much to copy,
// we'll use realloc() (note that realloc might have to copy
- // headroom + data + tailroom, see smartRealloc in folly/Malloc.h)
+ // headroom + data + tailroom, see smartRealloc in folly/memory/Malloc.h)
// - Otherwise, bite the bullet and reallocate.
if (headroom() + tailroom() >= minHeadroom + minTailroom) {
uint8_t* newData = writableBuffer() + minHeadroom;
throw std::bad_alloc();
}
newBuffer = static_cast<uint8_t*>(p);
- memcpy(newBuffer + minHeadroom, data_, length_);
+ if (length_ > 0) {
+ assert(data_ != nullptr);
+ memcpy(newBuffer + minHeadroom, data_, length_);
+ }
if (sharedInfo()) {
freeExtBuffer();
}
uint8_t* infoStart = (buf + mallocSize) - sizeof(SharedInfo);
SharedInfo* sharedInfo = new(infoStart) SharedInfo;
- *capacityReturn = infoStart - buf;
+ *capacityReturn = uint64_t(infoStart - buf);
*infoReturn = sharedInfo;
}
hasher.Init(0, 0);
io::Cursor cursor(&buf);
for (;;) {
- auto p = cursor.peek();
- if (p.second == 0) {
+ auto b = cursor.peekBytes();
+ if (b.empty()) {
break;
}
- hasher.Update(p.first, p.second);
- cursor.skip(p.second);
+ hasher.Update(b.data(), b.size());
+ cursor.skip(b.size());
}
uint64_t h1;
uint64_t h2;
io::Cursor ca(&a);
io::Cursor cb(&b);
for (;;) {
- auto pa = ca.peek();
- auto pb = cb.peek();
- if (pa.second == 0 && pb.second == 0) {
+ auto ba = ca.peekBytes();
+ auto bb = cb.peekBytes();
+ if (ba.empty() && bb.empty()) {
return true;
- } else if (pa.second == 0 || pb.second == 0) {
+ } else if (ba.empty() || bb.empty()) {
return false;
}
- size_t n = std::min(pa.second, pb.second);
- DCHECK_GT(n, 0);
- if (memcmp(pa.first, pb.first, n)) {
+ size_t n = std::min(ba.size(), bb.size());
+ DCHECK_GT(n, 0u);
+ if (memcmp(ba.data(), bb.data(), n)) {
return false;
}
ca.skip(n);
}
}
-} // folly
+} // namespace folly