19 #include <glog/logging.h> 28 #include <type_traits> 215 template <
typename T>
217 template <
typename T,
typename D>
234 typedef void (*FreeFunction)(
void* buf,
void* userData);
248 static std::unique_ptr<IOBuf> create(std::size_t capacity);
261 static std::unique_ptr<IOBuf> createCombined(std::size_t capacity);
270 static std::unique_ptr<IOBuf> createSeparate(std::size_t capacity);
276 static std::unique_ptr<IOBuf> createChain(
277 size_t totalCapacity,
278 std::size_t maxBufCapacity);
306 std::size_t capacity,
307 FreeFunction freeFn =
nullptr,
308 void* userData =
nullptr,
309 bool freeOnError =
true) {
310 return takeOwnership(
311 buf, capacity, capacity, freeFn, userData, freeOnError);
316 std::size_t capacity,
317 FreeFunction freeFn =
nullptr,
318 void* userData =
nullptr,
319 bool freeOnError =
true)
320 :
IOBuf(op, buf, capacity, capacity, freeFn, userData, freeOnError) {}
322 static std::unique_ptr<IOBuf> takeOwnership(
324 std::size_t capacity,
326 FreeFunction freeFn =
nullptr,
327 void* userData =
nullptr,
328 bool freeOnError =
true);
332 std::size_t capacity,
334 FreeFunction freeFn =
nullptr,
335 void* userData =
nullptr,
336 bool freeOnError =
true);
359 template <
class UniquePtr>
360 static typename std::enable_if<
362 std::unique_ptr<IOBuf>>
::type 363 takeOwnership(UniquePtr&& buf,
size_t count = 1);
384 static std::unique_ptr<IOBuf> wrapBuffer(
386 std::size_t capacity);
388 return wrapBuffer(br.
data(), br.
size());
395 static IOBuf wrapBufferAsValue(
399 return wrapBufferAsValue(br.data(), br.size());
413 std::size_t headroom = 0,
414 std::size_t minTailroom = 0);
417 std::size_t headroom = 0,
418 std::size_t minTailroom = 0) {
425 std::size_t headroom = 0,
426 std::size_t minTailroom = 0);
430 std::size_t headroom = 0,
431 std::size_t minTailroom = 0);
446 std::size_t headroom = 0,
447 std::size_t minTailroom = 0);
451 std::size_t headroom = 0,
452 std::size_t minTailroom = 0)
453 : IOBuf(op, buf.
data(), buf.size(), headroom, minTailroom) {}
459 static std::unique_ptr<IOBuf> maybeCopyBuffer(
461 std::size_t headroom = 0,
462 std::size_t minTailroom = 0);
552 return std::size_t(bufferEnd() - tail());
584 return buf_ + capacity_;
634 assert(amount <= tailroom());
655 assert(amount <= headroom());
674 DCHECK_LE(amount, headroom());
690 DCHECK_LE(amount, tailroom());
729 data_ = writableBuffer();
741 void reserve(std::size_t minHeadroom, std::size_t minTailroom) {
743 if (headroom() >= minHeadroom && tailroom() >= minTailroom) {
748 if (length() == 0 && headroom() + tailroom() >= minHeadroom + minTailroom) {
749 data_ = writableBuffer() + minHeadroom;
753 reserveSlow(minHeadroom, minTailroom);
761 assert((next_ ==
this) == (prev_ ==
this));
762 return next_ !=
this;
772 size_t countChainElements()
const;
779 std::size_t computeChainDataLength()
const;
806 void prependChain(std::unique_ptr<IOBuf>&& iobuf);
848 next_->prev_ = prev_;
849 prev_->next_ = next_;
852 return std::unique_ptr<IOBuf>(
this);
859 std::unique_ptr<IOBuf>
pop() {
861 next_->prev_ = prev_;
862 prev_->next_ = next_;
865 return std::unique_ptr<IOBuf>((next ==
this) ?
nullptr : next);
884 assert(head !=
this);
885 assert(tail !=
this);
893 return std::unique_ptr<IOBuf>(head);
908 current = current->
next_;
909 if (current ==
this) {
926 current = current->
next_;
927 if (current ==
this) {
958 if (
UNLIKELY(sharedInfo()->externallyShared)) {
969 bool shared = sharedInfo()->refcount.load(std::memory_order_acquire) > 1;
972 clearFlags(kFlagMaybeShared);
1016 if (isSharedOne()) {
1028 void markExternallyShared();
1056 makeManagedChained();
1072 if (!isManagedOne()) {
1096 const std::size_t newHeadroom = headroom();
1097 const std::size_t newTailroom = prev()->tailroom();
1098 return coalesceWithHeadroomTailroom(newHeadroom, newTailroom);
1108 std::size_t newHeadroom,
1109 std::size_t newTailroom) {
1111 coalesceAndReallocate(
1112 newHeadroom, computeChainDataLength(),
this, newTailroom);
1137 if (!isChained() ||
length_ >= maxLength) {
1140 coalesceSlow(maxLength);
1151 std::unique_ptr<IOBuf> clone()
const;
1157 IOBuf cloneAsValue()
const;
1165 std::unique_ptr<IOBuf> cloneOne()
const;
1171 IOBuf cloneOneAsValue()
const;
1185 std::unique_ptr<IOBuf> cloneCoalesced()
const;
1191 std::unique_ptr<IOBuf> cloneCoalescedWithHeadroomTailroom(
1192 std::size_t newHeadroom,
1193 std::size_t newTailroom)
const;
1199 IOBuf cloneCoalescedAsValue()
const;
1205 IOBuf cloneCoalescedAsValueWithHeadroomTailroom(
1206 std::size_t newHeadroom,
1207 std::size_t newTailroom)
const;
1214 other = cloneAsValue();
1222 other = cloneOneAsValue();
1257 size_t fillIov(
struct iovec* iov,
size_t len)
const;
1263 static std::unique_ptr<IOBuf> wrapIov(
const iovec*
vec,
size_t count);
1270 static std::unique_ptr<IOBuf> takeOwnershipIov(
1273 FreeFunction freeFn =
nullptr,
1274 void* userData =
nullptr,
1275 bool freeOnError =
true);
1283 void*
operator new(
size_t size);
1284 void*
operator new(
size_t size,
void*
ptr);
1285 void operator delete(
void*
ptr);
1286 void operator delete(
void*
ptr,
void* placement);
1332 IOBuf& operator=(IOBuf&& other)
noexcept;
1334 IOBuf(
const IOBuf& other);
1335 IOBuf& operator=(
const IOBuf& other);
1342 kFlagFreeSharedInfo = 0x1,
1343 kFlagMaybeShared = 0x2,
1344 kFlagMask = kFlagFreeSharedInfo | kFlagMaybeShared
1356 bool externallyShared{
false};
1373 uintptr_t flagsAndSharedInfo,
1375 std::size_t capacity,
1379 void unshareOneSlow();
1380 void unshareChained();
1381 void makeManagedChained();
1382 void coalesceSlow();
1383 void coalesceSlow(
size_t maxLength);
1386 void coalesceAndReallocate(
1390 size_t newTailroom);
1392 coalesceAndReallocate(headroom(), newLength, end, end->
prev_->
tailroom());
1394 void decrementRefcount();
1395 void reserveSlow(std::size_t minHeadroom, std::size_t minTailroom);
1396 void freeExtBuffer();
1398 static size_t goodExtBufferSize(std::size_t minCapacity);
1399 static void initExtBuffer(
1403 std::size_t* capacityReturn);
1404 static void allocExtBuffer(
1405 std::size_t minCapacity,
1408 std::size_t* capacityReturn);
1410 static void freeInternalBuf(
void* buf,
void* userData);
1435 std::size_t capacity_{0};
1438 mutable uintptr_t flagsAndSharedInfo_{0};
1443 uintptr_t uinfo =
reinterpret_cast<uintptr_t
>(
info);
1444 DCHECK_EQ(flags & ~kFlagMask, 0u);
1445 DCHECK_EQ(uinfo & kFlagMask, 0u);
1446 return flags | uinfo;
1450 return reinterpret_cast<SharedInfo*
>(flagsAndSharedInfo_ & ~kFlagMask);
1454 uintptr_t uinfo =
reinterpret_cast<uintptr_t
>(
info);
1455 DCHECK_EQ(uinfo & kFlagMask, 0u);
1456 flagsAndSharedInfo_ = (flagsAndSharedInfo_ & kFlagMask) | uinfo;
1460 return flagsAndSharedInfo_ & kFlagMask;
1465 DCHECK_EQ(flags & ~kFlagMask, 0u);
1466 flagsAndSharedInfo_ |=
flags;
1470 DCHECK_EQ(flags & ~kFlagMask, 0u);
1471 flagsAndSharedInfo_ &= ~flags;
1475 flagsAndSharedInfo_ = packFlagsAndSharedInfo(flags, info);
1480 virtual void dispose(
void* p) = 0;
1483 template <
class UniquePtr>
1491 deleter_(static_cast<Pointer>(p));
1503 static_cast<DeleterBase*
>(userData)->dispose(ptr);
1512 size_t operator()(
const std::unique_ptr<IOBuf>& buf)
const noexcept {
1513 return operator()(buf.get());
1516 return buf ? (*this)(*buf) : 0;
1525 return &a == &b ? ordering::eq : impl(a, b);
1528 const std::unique_ptr<IOBuf>&
a,
1529 const std::unique_ptr<IOBuf>&
b)
const {
1530 return operator()(a.get(), b.get());
1535 !a && !b ? ordering::eq :
1536 !a && b ? ordering::lt :
1537 a && !b ? ordering::gt :
1576 template <
class UniquePtr>
1577 typename std::enable_if<
1579 std::unique_ptr<IOBuf>>
::type 1580 IOBuf::takeOwnership(UniquePtr&& buf,
size_t count) {
1581 size_t size = count *
sizeof(
typename UniquePtr::element_type);
1583 return takeOwnership(
1584 buf.release(),
size, &IOBuf::freeUniquePtrBuffer, deleter);
1590 std::size_t headroom,
1591 std::size_t minTailroom) {
1592 std::size_t capacity = headroom + size + minTailroom;
1593 std::unique_ptr<IOBuf> buf = create(capacity);
1594 buf->advance(headroom);
1596 memcpy(buf->writableData(),
data,
size);
1604 std::size_t headroom,
1605 std::size_t minTailroom) {
1606 return copyBuffer(buf.data(), buf.size(), headroom, minTailroom);
1609 inline std::unique_ptr<IOBuf> IOBuf::maybeCopyBuffer(
1611 std::size_t headroom,
1612 std::size_t minTailroom) {
1616 return copyBuffer(buf.data(), buf.size(), headroom, minTailroom);
1622 std::forward_iterator_tag> {
1661 pos_ = pos_->next();
1667 val_ =
ByteRange(pos_->data(), pos_->tail());
1672 pos_ =
end_ =
nullptr;
std::vector< uint8_t > buffer(kBufferSize+16)
#define FOLLY_GNU_DISABLE_WARNING(warningName)
#define FOLLY_POP_WARNING
bool equal(const Iterator &other) const
Iterator(Iterator const &rhs)
size_t operator()(const IOBuf *buf) const noexcept
UniquePtr::pointer Pointer
#define FOLLY_PUSH_WARNING
Iterator(const IOBuf *pos, const IOBuf *end)
IOBuf(CopyBufferOp op, const std::string &buf, std::size_t headroom=0, std::size_t minTailroom=0)
Iterator & operator=(Iterator const &rhs)
void appendChain(std::unique_ptr< IOBuf > &&iobuf)
constexpr detail::Map< Move > move
const uint8_t * tail() const
void cloneOneInto(IOBuf &other) const
constexpr size_type size() const
auto begin(TestAdlIterable &instance)
void advance(std::size_t amount)
const uint8_t * data() const
void reserve(std::size_t minHeadroom, std::size_t minTailroom)
—— Concurrent Priority Queue Implementation ——
void cloneInto(IOBuf &other) const
IOBuf(TakeOwnershipOp op, void *buf, std::size_t capacity, FreeFunction freeFn=nullptr, void *userData=nullptr, bool freeOnError=true)
requires E e noexcept(noexcept(s.error(std::move(e))))
const uint8_t * bufferEnd() const
std::unique_ptr< IOBuf > separateChain(IOBuf *head, IOBuf *tail)
std::size_t capacity() const
std::size_t tailroom() const
UniquePtr::deleter_type Deleter
FOLLY_PUSH_WARNING RHS rhs
uint8_t * writableBuffer()
ordering operator()(const std::unique_ptr< IOBuf > &a, const std::unique_ptr< IOBuf > &b) const
constexpr auto size(C const &c) -> decltype(c.size())
static void destroy(std::unique_ptr< IOBuf > &&data)
UniquePtrDeleter(Deleter deleter)
constexpr auto empty(C const &c) -> decltype(c.empty())
std::unique_ptr< IOBuf > pop()
void prepend(std::size_t amount)
void setSharedInfo(SharedInfo *info)
std::size_t headroom() const
auto end(TestAdlIterable &instance)
static void freeUniquePtrBuffer(void *ptr, void *userData)
constexpr Iter data() const
std::size_t length() const
static std::unique_ptr< IOBuf > wrapBuffer(ByteRange br)
static uintptr_t packFlagsAndSharedInfo(uintptr_t flags, SharedInfo *info)
void retreat(std::size_t amount)
const IOBuf * next() const
std::unique_ptr< IOBuf > unlink()
ordering operator()(const IOBuf &a, const IOBuf &b) const
void markExternallySharedOne()
std::unique_ptr< IOBuf > copyBuffer(const folly::IOBuf &buf)
const IOBuf * prev() const
static std::unique_ptr< IOBuf > takeOwnership(void *buf, std::size_t capacity, FreeFunction freeFn=nullptr, void *userData=nullptr, bool freeOnError=true)
SharedInfo * sharedInfo() const
Range< const unsigned char * > ByteRange
size_t operator()(const std::unique_ptr< IOBuf > &buf) const noexcept
static IOBuf wrapBufferAsValue(ByteRange br) noexcept
bool_constant< false > false_type
static std::unique_ptr< IOBuf > copyBuffer(ByteRange br, std::size_t headroom=0, std::size_t minTailroom=0)
void trimStart(std::size_t amount)
std::atomic< uint32_t > refcount
ordering operator()(const IOBuf *a, const IOBuf *b) const
void setFlagsAndSharedInfo(uintptr_t flags, SharedInfo *info)
void clearFlags(uintptr_t flags) const
void trimEnd(std::size_t amount)
const ByteRange & dereference() const
const uint8_t * buffer() const
ByteRange coalesceWithHeadroomTailroom(std::size_t newHeadroom, std::size_t newTailroom)
void setFlags(uintptr_t flags) const
void gather(std::size_t maxLength)
static constexpr uint64_t data[1]
void dispose(void *p) override
Iterator< typename Container::const_iterator > cbegin(const Container &c)
bool isManagedOne() const
Iterator< typename Container::const_iterator > cend(const Container &c)
void append(std::size_t amount)
void coalesceAndReallocate(size_t newLength, IOBuf *end)