proxygen
IOBuf.h
Go to the documentation of this file.
1 /*
2  * Copyright 2013-present Facebook, Inc.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 
17 #pragma once
18 
19 #include <glog/logging.h>
20 #include <atomic>
21 #include <cassert>
22 #include <cinttypes>
23 #include <cstddef>
24 #include <cstring>
25 #include <iterator>
26 #include <limits>
27 #include <memory>
28 #include <type_traits>
29 
30 #include <folly/FBString.h>
31 #include <folly/FBVector.h>
32 #include <folly/Portability.h>
33 #include <folly/Range.h>
34 #include <folly/detail/Iterators.h>
35 #include <folly/lang/Ordering.h>
37 
38 // Ignore shadowing warnings within this file, so includers can use -Wshadow.
40 FOLLY_GNU_DISABLE_WARNING("-Wshadow")
41 
42 namespace folly {
43 
213 namespace detail {
214 // Is T a unique_ptr<> to a standard-layout type?
215 template <typename T>
217 template <typename T, typename D>
218 struct IsUniquePtrToSL<std::unique_ptr<T, D>> : std::is_standard_layout<T> {};
219 } // namespace detail
220 
221 class IOBuf {
222  public:
223  class Iterator;
224 
225  enum CreateOp { CREATE };
226  enum WrapBufferOp { WRAP_BUFFER };
227  enum TakeOwnershipOp { TAKE_OWNERSHIP };
228  enum CopyBufferOp { COPY_BUFFER };
229 
233 
234  typedef void (*FreeFunction)(void* buf, void* userData);
235 
248  static std::unique_ptr<IOBuf> create(std::size_t capacity);
249  IOBuf(CreateOp, std::size_t capacity);
250 
261  static std::unique_ptr<IOBuf> createCombined(std::size_t capacity);
262 
270  static std::unique_ptr<IOBuf> createSeparate(std::size_t capacity);
271 
276  static std::unique_ptr<IOBuf> createChain(
277  size_t totalCapacity,
278  std::size_t maxBufCapacity);
279 
304  static std::unique_ptr<IOBuf> takeOwnership(
305  void* buf,
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);
312  }
315  void* buf,
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) {}
321 
322  static std::unique_ptr<IOBuf> takeOwnership(
323  void* buf,
324  std::size_t capacity,
325  std::size_t length,
326  FreeFunction freeFn = nullptr,
327  void* userData = nullptr,
328  bool freeOnError = true);
329  IOBuf(
331  void* buf,
332  std::size_t capacity,
333  std::size_t length,
334  FreeFunction freeFn = nullptr,
335  void* userData = nullptr,
336  bool freeOnError = true);
337 
359  template <class UniquePtr>
360  static typename std::enable_if<
362  std::unique_ptr<IOBuf>>::type
363  takeOwnership(UniquePtr&& buf, size_t count = 1);
364 
384  static std::unique_ptr<IOBuf> wrapBuffer(
385  const void* buf,
386  std::size_t capacity);
387  static std::unique_ptr<IOBuf> wrapBuffer(ByteRange br) {
388  return wrapBuffer(br.data(), br.size());
389  }
390 
395  static IOBuf wrapBufferAsValue(
396  const void* buf,
397  std::size_t capacity) noexcept;
398  static IOBuf wrapBufferAsValue(ByteRange br) noexcept {
399  return wrapBufferAsValue(br.data(), br.size());
400  }
401 
402  IOBuf(WrapBufferOp op, const void* buf, std::size_t capacity) noexcept;
404 
410  static std::unique_ptr<IOBuf> copyBuffer(
411  const void* buf,
412  std::size_t size,
413  std::size_t headroom = 0,
414  std::size_t minTailroom = 0);
415  static std::unique_ptr<IOBuf> copyBuffer(
416  ByteRange br,
417  std::size_t headroom = 0,
418  std::size_t minTailroom = 0) {
419  return copyBuffer(br.data(), br.size(), headroom, minTailroom);
420  }
421  IOBuf(
422  CopyBufferOp op,
423  const void* buf,
424  std::size_t size,
425  std::size_t headroom = 0,
426  std::size_t minTailroom = 0);
427  IOBuf(
428  CopyBufferOp op,
429  ByteRange br,
430  std::size_t headroom = 0,
431  std::size_t minTailroom = 0);
432 
444  static std::unique_ptr<IOBuf> copyBuffer(
445  const std::string& buf,
446  std::size_t headroom = 0,
447  std::size_t minTailroom = 0);
449  CopyBufferOp op,
450  const std::string& buf,
451  std::size_t headroom = 0,
452  std::size_t minTailroom = 0)
453  : IOBuf(op, buf.data(), buf.size(), headroom, minTailroom) {}
454 
459  static std::unique_ptr<IOBuf> maybeCopyBuffer(
460  const std::string& buf,
461  std::size_t headroom = 0,
462  std::size_t minTailroom = 0);
463 
467  static void destroy(std::unique_ptr<IOBuf>&& data) {
468  auto destroyer = std::move(data);
469  }
470 
483  ~IOBuf();
484 
494  bool empty() const;
495 
499  const uint8_t* data() const {
500  return data_;
501  }
502 
510  return data_;
511  }
512 
516  const uint8_t* tail() const {
517  return data_ + length_;
518  }
519 
527  return data_ + length_;
528  }
529 
533  std::size_t length() const {
534  return length_;
535  }
536 
542  std::size_t headroom() const {
543  return std::size_t(data_ - buffer());
544  }
545 
551  std::size_t tailroom() const {
552  return std::size_t(bufferEnd() - tail());
553  }
554 
562  const uint8_t* buffer() const {
563  return buf_;
564  }
565 
573  return buf_;
574  }
575 
583  const uint8_t* bufferEnd() const {
584  return buf_ + capacity_;
585  }
586 
593  std::size_t capacity() const {
594  return capacity_;
595  }
596 
600  IOBuf* next() {
601  return next_;
602  }
603  const IOBuf* next() const {
604  return next_;
605  }
606 
610  IOBuf* prev() {
611  return prev_;
612  }
613  const IOBuf* prev() const {
614  return prev_;
615  }
616 
632  void advance(std::size_t amount) {
633  // In debug builds, assert if there is a problem.
634  assert(amount <= tailroom());
635 
636  if (length_ > 0) {
637  memmove(data_ + amount, data_, length_);
638  }
639  data_ += amount;
640  }
641 
653  void retreat(std::size_t amount) {
654  // In debug builds, assert if there is a problem.
655  assert(amount <= headroom());
656 
657  if (length_ > 0) {
658  memmove(data_ - amount, data_, length_);
659  }
660  data_ -= amount;
661  }
662 
673  void prepend(std::size_t amount) {
674  DCHECK_LE(amount, headroom());
675  data_ -= amount;
676  length_ += amount;
677  }
678 
689  void append(std::size_t amount) {
690  DCHECK_LE(amount, tailroom());
691  length_ += amount;
692  }
693 
703  void trimStart(std::size_t amount) {
704  DCHECK_LE(amount, length_);
705  data_ += amount;
706  length_ -= amount;
707  }
708 
718  void trimEnd(std::size_t amount) {
719  DCHECK_LE(amount, length_);
720  length_ -= amount;
721  }
722 
728  void clear() {
729  data_ = writableBuffer();
730  length_ = 0;
731  }
732 
741  void reserve(std::size_t minHeadroom, std::size_t minTailroom) {
742  // Maybe we don't need to do anything.
743  if (headroom() >= minHeadroom && tailroom() >= minTailroom) {
744  return;
745  }
746  // If the buffer is empty but we have enough total room (head + tail),
747  // move the data_ pointer around.
748  if (length() == 0 && headroom() + tailroom() >= minHeadroom + minTailroom) {
749  data_ = writableBuffer() + minHeadroom;
750  return;
751  }
752  // Bah, we have to do actual work.
753  reserveSlow(minHeadroom, minTailroom);
754  }
755 
760  bool isChained() const {
761  assert((next_ == this) == (prev_ == this));
762  return next_ != this;
763  }
764 
772  size_t countChainElements() const;
773 
779  std::size_t computeChainDataLength() const;
780 
806  void prependChain(std::unique_ptr<IOBuf>&& iobuf);
807 
827  void appendChain(std::unique_ptr<IOBuf>&& iobuf) {
828  // Just use prependChain() on the next element in our chain
829  next_->prependChain(std::move(iobuf));
830  }
831 
847  std::unique_ptr<IOBuf> unlink() {
848  next_->prev_ = prev_;
849  prev_->next_ = next_;
850  prev_ = this;
851  next_ = this;
852  return std::unique_ptr<IOBuf>(this);
853  }
854 
859  std::unique_ptr<IOBuf> pop() {
860  IOBuf* next = next_;
861  next_->prev_ = prev_;
862  prev_->next_ = next_;
863  prev_ = this;
864  next_ = this;
865  return std::unique_ptr<IOBuf>((next == this) ? nullptr : next);
866  }
867 
883  std::unique_ptr<IOBuf> separateChain(IOBuf* head, IOBuf* tail) {
884  assert(head != this);
885  assert(tail != this);
886 
887  head->prev_->next_ = tail->next_;
888  tail->next_->prev_ = head->prev_;
889 
890  head->prev_ = tail;
891  tail->next_ = head;
892 
893  return std::unique_ptr<IOBuf>(head);
894  }
895 
902  bool isShared() const {
903  const IOBuf* current = this;
904  while (true) {
905  if (current->isSharedOne()) {
906  return true;
907  }
908  current = current->next_;
909  if (current == this) {
910  return false;
911  }
912  }
913  }
914 
920  bool isManaged() const {
921  const IOBuf* current = this;
922  while (true) {
923  if (!current->isManagedOne()) {
924  return false;
925  }
926  current = current->next_;
927  if (current == this) {
928  return true;
929  }
930  }
931  }
932 
938  bool isManagedOne() const {
939  return sharedInfo();
940  }
941 
952  bool isSharedOne() const {
953  // If this is a user-owned buffer, it is always considered shared
954  if (UNLIKELY(!sharedInfo())) {
955  return true;
956  }
957 
958  if (UNLIKELY(sharedInfo()->externallyShared)) {
959  return true;
960  }
961 
962  if (LIKELY(!(flags() & kFlagMaybeShared))) {
963  return false;
964  }
965 
966  // kFlagMaybeShared is set, so we need to check the reference count.
967  // (Checking the reference count requires an atomic operation, which is why
968  // we prefer to only check kFlagMaybeShared if possible.)
969  bool shared = sharedInfo()->refcount.load(std::memory_order_acquire) > 1;
970  if (!shared) {
971  // we're the last one left
972  clearFlags(kFlagMaybeShared);
973  }
974  return shared;
975  }
976 
997  void unshare() {
998  if (isChained()) {
999  unshareChained();
1000  } else {
1001  unshareOne();
1002  }
1003  }
1004 
1015  void unshareOne() {
1016  if (isSharedOne()) {
1017  unshareOneSlow();
1018  }
1019  }
1020 
1028  void markExternallyShared();
1029 
1039  SharedInfo* info = sharedInfo();
1040  if (info) {
1041  info->externallyShared = true;
1042  }
1043  }
1044 
1054  void makeManaged() {
1055  if (isChained()) {
1056  makeManagedChained();
1057  } else {
1058  makeManagedOne();
1059  }
1060  }
1061 
1072  if (!isManagedOne()) {
1073  // We can call the internal function directly; unmanaged implies shared.
1074  unshareOneSlow();
1075  }
1076  }
1077 
1096  const std::size_t newHeadroom = headroom();
1097  const std::size_t newTailroom = prev()->tailroom();
1098  return coalesceWithHeadroomTailroom(newHeadroom, newTailroom);
1099  }
1100 
1108  std::size_t newHeadroom,
1109  std::size_t newTailroom) {
1110  if (isChained()) {
1111  coalesceAndReallocate(
1112  newHeadroom, computeChainDataLength(), this, newTailroom);
1113  }
1114  return ByteRange(data_, length_);
1115  }
1116 
1136  void gather(std::size_t maxLength) {
1137  if (!isChained() || length_ >= maxLength) {
1138  return;
1139  }
1140  coalesceSlow(maxLength);
1141  }
1142 
1151  std::unique_ptr<IOBuf> clone() const;
1152 
1157  IOBuf cloneAsValue() const;
1158 
1165  std::unique_ptr<IOBuf> cloneOne() const;
1166 
1171  IOBuf cloneOneAsValue() const;
1172 
1185  std::unique_ptr<IOBuf> cloneCoalesced() const;
1186 
1191  std::unique_ptr<IOBuf> cloneCoalescedWithHeadroomTailroom(
1192  std::size_t newHeadroom,
1193  std::size_t newTailroom) const;
1194 
1199  IOBuf cloneCoalescedAsValue() const;
1200 
1205  IOBuf cloneCoalescedAsValueWithHeadroomTailroom(
1206  std::size_t newHeadroom,
1207  std::size_t newTailroom) const;
1208 
1213  void cloneInto(IOBuf& other) const {
1214  other = cloneAsValue();
1215  }
1216 
1221  void cloneOneInto(IOBuf& other) const {
1222  other = cloneOneAsValue();
1223  }
1224 
1234  folly::fbvector<struct iovec> getIov() const;
1235 
1245  void appendToIov(folly::fbvector<struct iovec>* iov) const;
1246 
1257  size_t fillIov(struct iovec* iov, size_t len) const;
1258 
1263  static std::unique_ptr<IOBuf> wrapIov(const iovec* vec, size_t count);
1264 
1270  static std::unique_ptr<IOBuf> takeOwnershipIov(
1271  const iovec* vec,
1272  size_t count,
1273  FreeFunction freeFn = nullptr,
1274  void* userData = nullptr,
1275  bool freeOnError = true);
1276 
1277  /*
1278  * Overridden operator new and delete.
1279  * These perform specialized memory management to help support
1280  * createCombined(), which allocates IOBuf objects together with the buffer
1281  * data.
1282  */
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);
1287 
1293  fbstring moveToFbString();
1294 
1300  Iterator cbegin() const;
1301  Iterator cend() const;
1302  Iterator begin() const;
1303  Iterator end() const;
1304 
1312  IOBuf() noexcept;
1313 
1331  IOBuf(IOBuf&& other) noexcept;
1332  IOBuf& operator=(IOBuf&& other) noexcept;
1333 
1334  IOBuf(const IOBuf& other);
1335  IOBuf& operator=(const IOBuf& other);
1336 
1337  private:
1338  enum FlagsEnum : uintptr_t {
1339  // Adding any more flags would not work on 32-bit architectures,
1340  // as these flags are stashed in the least significant 2 bits of a
1341  // max-align-aligned pointer.
1342  kFlagFreeSharedInfo = 0x1,
1343  kFlagMaybeShared = 0x2,
1344  kFlagMask = kFlagFreeSharedInfo | kFlagMaybeShared
1345  };
1346 
1347  struct SharedInfo {
1348  SharedInfo();
1349  SharedInfo(FreeFunction fn, void* arg);
1350 
1351  // A pointer to a function to call to free the buffer when the refcount
1352  // hits 0. If this is null, free() will be used instead.
1353  FreeFunction freeFn;
1354  void* userData;
1355  std::atomic<uint32_t> refcount;
1356  bool externallyShared{false};
1357  };
1358  // Helper structs for use by operator new and delete
1359  struct HeapPrefix;
1360  struct HeapStorage;
1361  struct HeapFullStorage;
1362 
1370  struct InternalConstructor {}; // avoid conflicts
1371  IOBuf(
1373  uintptr_t flagsAndSharedInfo,
1374  uint8_t* buf,
1375  std::size_t capacity,
1376  uint8_t* data,
1377  std::size_t length) noexcept;
1378 
1379  void unshareOneSlow();
1380  void unshareChained();
1381  void makeManagedChained();
1382  void coalesceSlow();
1383  void coalesceSlow(size_t maxLength);
1384  // newLength must be the entire length of the buffers between this and
1385  // end (no truncation)
1386  void coalesceAndReallocate(
1387  size_t newHeadroom,
1388  size_t newLength,
1389  IOBuf* end,
1390  size_t newTailroom);
1391  void coalesceAndReallocate(size_t newLength, IOBuf* end) {
1392  coalesceAndReallocate(headroom(), newLength, end, end->prev_->tailroom());
1393  }
1394  void decrementRefcount();
1395  void reserveSlow(std::size_t minHeadroom, std::size_t minTailroom);
1396  void freeExtBuffer();
1397 
1398  static size_t goodExtBufferSize(std::size_t minCapacity);
1399  static void initExtBuffer(
1400  uint8_t* buf,
1401  size_t mallocSize,
1402  SharedInfo** infoReturn,
1403  std::size_t* capacityReturn);
1404  static void allocExtBuffer(
1405  std::size_t minCapacity,
1406  uint8_t** bufReturn,
1407  SharedInfo** infoReturn,
1408  std::size_t* capacityReturn);
1409  static void releaseStorage(HeapStorage* storage, uint16_t freeFlags);
1410  static void freeInternalBuf(void* buf, void* userData);
1411 
1412  /*
1413  * Member variables
1414  */
1415 
1416  /*
1417  * Links to the next and the previous IOBuf in this chain.
1418  *
1419  * The chain is circularly linked (the last element in the chain points back
1420  * at the head), and next_ and prev_ can never be null. If this IOBuf is the
1421  * only element in the chain, next_ and prev_ will both point to this.
1422  */
1423  IOBuf* next_{this};
1424  IOBuf* prev_{this};
1425 
1426  /*
1427  * A pointer to the start of the data referenced by this IOBuf, and the
1428  * length of the data.
1429  *
1430  * This may refer to any subsection of the actual buffer capacity.
1431  */
1432  uint8_t* data_{nullptr};
1433  uint8_t* buf_{nullptr};
1434  std::size_t length_{0};
1435  std::size_t capacity_{0};
1436 
1437  // Pack flags in least significant 2 bits, sharedInfo in the rest
1438  mutable uintptr_t flagsAndSharedInfo_{0};
1439 
1440  static inline uintptr_t packFlagsAndSharedInfo(
1441  uintptr_t flags,
1442  SharedInfo* info) {
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;
1447  }
1448 
1449  inline SharedInfo* sharedInfo() const {
1450  return reinterpret_cast<SharedInfo*>(flagsAndSharedInfo_ & ~kFlagMask);
1451  }
1452 
1454  uintptr_t uinfo = reinterpret_cast<uintptr_t>(info);
1455  DCHECK_EQ(uinfo & kFlagMask, 0u);
1456  flagsAndSharedInfo_ = (flagsAndSharedInfo_ & kFlagMask) | uinfo;
1457  }
1458 
1459  inline uintptr_t flags() const {
1460  return flagsAndSharedInfo_ & kFlagMask;
1461  }
1462 
1463  // flags_ are changed from const methods
1464  inline void setFlags(uintptr_t flags) const {
1465  DCHECK_EQ(flags & ~kFlagMask, 0u);
1466  flagsAndSharedInfo_ |= flags;
1467  }
1468 
1469  inline void clearFlags(uintptr_t flags) const {
1470  DCHECK_EQ(flags & ~kFlagMask, 0u);
1471  flagsAndSharedInfo_ &= ~flags;
1472  }
1473 
1474  inline void setFlagsAndSharedInfo(uintptr_t flags, SharedInfo* info) {
1475  flagsAndSharedInfo_ = packFlagsAndSharedInfo(flags, info);
1476  }
1477 
1478  struct DeleterBase {
1479  virtual ~DeleterBase() {}
1480  virtual void dispose(void* p) = 0;
1481  };
1482 
1483  template <class UniquePtr>
1484  struct UniquePtrDeleter : public DeleterBase {
1485  typedef typename UniquePtr::pointer Pointer;
1486  typedef typename UniquePtr::deleter_type Deleter;
1487 
1488  explicit UniquePtrDeleter(Deleter deleter) : deleter_(std::move(deleter)) {}
1489  void dispose(void* p) override {
1490  try {
1491  deleter_(static_cast<Pointer>(p));
1492  delete this;
1493  } catch (...) {
1494  abort();
1495  }
1496  }
1497 
1498  private:
1499  Deleter deleter_;
1500  };
1501 
1502  static void freeUniquePtrBuffer(void* ptr, void* userData) {
1503  static_cast<DeleterBase*>(userData)->dispose(ptr);
1504  }
1505 };
1506 
1510 struct IOBufHash {
1511  size_t operator()(const IOBuf& buf) const noexcept;
1512  size_t operator()(const std::unique_ptr<IOBuf>& buf) const noexcept {
1513  return operator()(buf.get());
1514  }
1515  size_t operator()(const IOBuf* buf) const noexcept {
1516  return buf ? (*this)(*buf) : 0;
1517  }
1518 };
1519 
1524  ordering operator()(const IOBuf& a, const IOBuf& b) const {
1525  return &a == &b ? ordering::eq : impl(a, b);
1526  }
1528  const std::unique_ptr<IOBuf>& a,
1529  const std::unique_ptr<IOBuf>& b) const {
1530  return operator()(a.get(), b.get());
1531  }
1532  ordering operator()(const IOBuf* a, const IOBuf* b) const {
1533  // clang-format off
1534  return
1535  !a && !b ? ordering::eq :
1536  !a && b ? ordering::lt :
1537  a && !b ? ordering::gt :
1538  operator()(*a, *b);
1539  // clang-format on
1540  }
1541 
1542  private:
1543  ordering impl(IOBuf const& a, IOBuf const& b) const noexcept;
1544 };
1545 
1549 struct IOBufEqualTo : compare_equal_to<IOBufCompare> {};
1550 
1554 struct IOBufNotEqualTo : compare_not_equal_to<IOBufCompare> {};
1555 
1559 struct IOBufLess : compare_less<IOBufCompare> {};
1560 
1564 struct IOBufLessEqual : compare_less_equal<IOBufCompare> {};
1565 
1569 struct IOBufGreater : compare_greater<IOBufCompare> {};
1570 
1574 struct IOBufGreaterEqual : compare_greater_equal<IOBufCompare> {};
1575 
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);
1582  auto deleter = new UniquePtrDeleter<UniquePtr>(buf.get_deleter());
1583  return takeOwnership(
1584  buf.release(), size, &IOBuf::freeUniquePtrBuffer, deleter);
1585 }
1586 
1587 inline std::unique_ptr<IOBuf> IOBuf::copyBuffer(
1588  const void* data,
1589  std::size_t size,
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);
1595  if (size != 0) {
1596  memcpy(buf->writableData(), data, size);
1597  }
1598  buf->append(size);
1599  return buf;
1600 }
1601 
1602 inline std::unique_ptr<IOBuf> IOBuf::copyBuffer(
1603  const std::string& buf,
1604  std::size_t headroom,
1605  std::size_t minTailroom) {
1606  return copyBuffer(buf.data(), buf.size(), headroom, minTailroom);
1607 }
1608 
1609 inline std::unique_ptr<IOBuf> IOBuf::maybeCopyBuffer(
1610  const std::string& buf,
1611  std::size_t headroom,
1612  std::size_t minTailroom) {
1613  if (buf.empty()) {
1614  return nullptr;
1615  }
1616  return copyBuffer(buf.data(), buf.size(), headroom, minTailroom);
1617 }
1618 
1620  IOBuf::Iterator,
1621  ByteRange const,
1622  std::forward_iterator_tag> {
1623  public:
1624  // Note that IOBufs are stored as a circular list without a guard node,
1625  // so pos == end is ambiguous (it may mean "begin" or "end"). To solve
1626  // the ambiguity (at the cost of one extra comparison in the "increment"
1627  // code path), we define end iterators as having pos_ == end_ == nullptr
1628  // and we only allow forward iteration.
1629  explicit Iterator(const IOBuf* pos, const IOBuf* end) : pos_(pos), end_(end) {
1630  // Sadly, we must return by const reference, not by value.
1631  if (pos_) {
1632  setVal();
1633  }
1634  }
1635 
1637 
1638  Iterator(Iterator const& rhs) : Iterator(rhs.pos_, rhs.end_) {}
1639 
1641  pos_ = rhs.pos_;
1642  end_ = rhs.end_;
1643  if (pos_) {
1644  setVal();
1645  }
1646  return *this;
1647  }
1648 
1649  const ByteRange& dereference() const {
1650  return val_;
1651  }
1652 
1653  bool equal(const Iterator& other) const {
1654  // We must compare end_ in addition to pos_, because forward traversal
1655  // requires that if two iterators are equal (a == b) and dereferenceable,
1656  // then ++a == ++b.
1657  return pos_ == other.pos_ && end_ == other.end_;
1658  }
1659 
1660  void increment() {
1661  pos_ = pos_->next();
1662  adjustForEnd();
1663  }
1664 
1665  private:
1666  void setVal() {
1667  val_ = ByteRange(pos_->data(), pos_->tail());
1668  }
1669 
1670  void adjustForEnd() {
1671  if (pos_ == end_) {
1672  pos_ = end_ = nullptr;
1673  val_ = ByteRange();
1674  } else {
1675  setVal();
1676  }
1677  }
1678 
1679  const IOBuf* pos_{nullptr};
1680  const IOBuf* end_{nullptr};
1682 };
1683 
1685  return cbegin();
1686 }
1687 inline IOBuf::Iterator IOBuf::end() const {
1688  return cend();
1689 }
1690 
1691 } // namespace folly
1692 
void * ptr
std::vector< uint8_t > buffer(kBufferSize+16)
Iterator iterator
Definition: IOBuf.h:231
def info()
Definition: deadlock.py:447
#define FOLLY_GNU_DISABLE_WARNING(warningName)
Definition: Portability.h:180
int64_t length_
Definition: JSONSchema.cpp:233
#define FOLLY_POP_WARNING
Definition: Portability.h:179
bool equal(const Iterator &other) const
Definition: IOBuf.h:1653
flags
Definition: http_parser.h:127
void unshare()
Definition: IOBuf.h:997
Iterator(Iterator const &rhs)
Definition: IOBuf.h:1638
size_t operator()(const IOBuf *buf) const noexcept
Definition: IOBuf.h:1515
UniquePtr::pointer Pointer
Definition: IOBuf.h:1485
#define FOLLY_PUSH_WARNING
Definition: Portability.h:178
Iterator(const IOBuf *pos, const IOBuf *end)
Definition: IOBuf.h:1629
char b
uintptr_t flags() const
Definition: IOBuf.h:1459
IOBuf(CopyBufferOp op, const std::string &buf, std::size_t headroom=0, std::size_t minTailroom=0)
Definition: IOBuf.h:448
IOBuf * next_
Definition: IOBuf.h:1423
TakeOwnershipOp
Definition: IOBuf.h:227
ByteRange coalesce()
Definition: IOBuf.h:1095
Iterator & operator=(Iterator const &rhs)
Definition: IOBuf.h:1640
PskType type
void appendChain(std::unique_ptr< IOBuf > &&iobuf)
Definition: IOBuf.h:827
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
const uint8_t * tail() const
Definition: IOBuf.h:516
#define LIKELY(x)
Definition: Likely.h:47
bool isSharedOne() const
Definition: IOBuf.h:952
void cloneOneInto(IOBuf &other) const
Definition: IOBuf.h:1221
STL namespace.
constexpr size_type size() const
Definition: Range.h:431
auto begin(TestAdlIterable &instance)
Definition: ForeachTest.cpp:56
void advance(std::size_t amount)
Definition: IOBuf.h:632
const uint8_t * data() const
Definition: IOBuf.h:499
void reserve(std::size_t minHeadroom, std::size_t minTailroom)
Definition: IOBuf.h:741
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
bool isChained() const
Definition: IOBuf.h:760
IOBuf * prev_
Definition: IOBuf.h:1424
void cloneInto(IOBuf &other) const
Definition: IOBuf.h:1213
IOBuf(TakeOwnershipOp op, void *buf, std::size_t capacity, FreeFunction freeFn=nullptr, void *userData=nullptr, bool freeOnError=true)
Definition: IOBuf.h:313
requires E e noexcept(noexcept(s.error(std::move(e))))
const uint8_t * bufferEnd() const
Definition: IOBuf.h:583
void makeManaged()
Definition: IOBuf.h:1054
std::unique_ptr< IOBuf > separateChain(IOBuf *head, IOBuf *tail)
Definition: IOBuf.h:883
std::size_t capacity() const
Definition: IOBuf.h:593
void unshareOne()
Definition: IOBuf.h:1015
std::size_t tailroom() const
Definition: IOBuf.h:551
UniquePtr::deleter_type Deleter
Definition: IOBuf.h:1486
uint8_t * writableTail()
Definition: IOBuf.h:526
FOLLY_PUSH_WARNING RHS rhs
Definition: Traits.h:649
uint8_t * writableBuffer()
Definition: IOBuf.h:572
Iterator const_iterator
Definition: IOBuf.h:232
ordering operator()(const std::unique_ptr< IOBuf > &a, const std::unique_ptr< IOBuf > &b) const
Definition: IOBuf.h:1527
int current
constexpr auto size(C const &c) -> decltype(c.size())
Definition: Access.h:45
static void destroy(std::unique_ptr< IOBuf > &&data)
Definition: IOBuf.h:467
UniquePtrDeleter(Deleter deleter)
Definition: IOBuf.h:1488
FreeFunction freeFn
Definition: IOBuf.h:1353
constexpr auto empty(C const &c) -> decltype(c.empty())
Definition: Access.h:55
std::unique_ptr< IOBuf > pop()
Definition: IOBuf.h:859
ByteRange value_type
Definition: IOBuf.h:230
void prepend(std::size_t amount)
Definition: IOBuf.h:673
ordering
Definition: Ordering.h:21
void setSharedInfo(SharedInfo *info)
Definition: IOBuf.h:1453
bool isManaged() const
Definition: IOBuf.h:920
uint8_t * writableData()
Definition: IOBuf.h:509
std::size_t headroom() const
Definition: IOBuf.h:542
auto end(TestAdlIterable &instance)
Definition: ForeachTest.cpp:62
static void freeUniquePtrBuffer(void *ptr, void *userData)
Definition: IOBuf.h:1502
constexpr Iter data() const
Definition: Range.h:446
std::size_t length() const
Definition: IOBuf.h:533
static std::unique_ptr< IOBuf > wrapBuffer(ByteRange br)
Definition: IOBuf.h:387
char a
Definition: Traits.h:588
static uintptr_t packFlagsAndSharedInfo(uintptr_t flags, SharedInfo *info)
Definition: IOBuf.h:1440
void retreat(std::size_t amount)
Definition: IOBuf.h:653
const IOBuf * next() const
Definition: IOBuf.h:603
std::unique_ptr< IOBuf > unlink()
Definition: IOBuf.h:847
IOBuf * next()
Definition: IOBuf.h:600
ordering operator()(const IOBuf &a, const IOBuf &b) const
Definition: IOBuf.h:1524
bool isShared() const
Definition: IOBuf.h:902
IOBuf * prev()
Definition: IOBuf.h:610
void markExternallySharedOne()
Definition: IOBuf.h:1038
int * count
std::unique_ptr< IOBuf > copyBuffer(const folly::IOBuf &buf)
const IOBuf * prev() const
Definition: IOBuf.h:613
void clear()
Definition: IOBuf.h:728
static std::unique_ptr< IOBuf > takeOwnership(void *buf, std::size_t capacity, FreeFunction freeFn=nullptr, void *userData=nullptr, bool freeOnError=true)
Definition: IOBuf.h:304
SharedInfo * sharedInfo() const
Definition: IOBuf.h:1449
const char * string
Definition: Conv.cpp:212
Range< const unsigned char * > ByteRange
Definition: Range.h:1163
size_t operator()(const std::unique_ptr< IOBuf > &buf) const noexcept
Definition: IOBuf.h:1512
static IOBuf wrapBufferAsValue(ByteRange br) noexcept
Definition: IOBuf.h:398
bool_constant< false > false_type
Definition: gtest-port.h:2209
const IOBuf * pos_
Definition: IOBuf.h:1679
static std::unique_ptr< IOBuf > copyBuffer(ByteRange br, std::size_t headroom=0, std::size_t minTailroom=0)
Definition: IOBuf.h:415
void trimStart(std::size_t amount)
Definition: IOBuf.h:703
const IOBuf * end_
Definition: IOBuf.h:1680
std::atomic< uint32_t > refcount
Definition: IOBuf.h:1355
ordering operator()(const IOBuf *a, const IOBuf *b) const
Definition: IOBuf.h:1532
void setFlagsAndSharedInfo(uintptr_t flags, SharedInfo *info)
Definition: IOBuf.h:1474
#define UNLIKELY(x)
Definition: Likely.h:48
void clearFlags(uintptr_t flags) const
Definition: IOBuf.h:1469
void trimEnd(std::size_t amount)
Definition: IOBuf.h:718
const ByteRange & dereference() const
Definition: IOBuf.h:1649
const uint8_t * buffer() const
Definition: IOBuf.h:562
void makeManagedOne()
Definition: IOBuf.h:1071
ByteRange coalesceWithHeadroomTailroom(std::size_t newHeadroom, std::size_t newTailroom)
Definition: IOBuf.h:1107
void setFlags(uintptr_t flags) const
Definition: IOBuf.h:1464
void gather(std::size_t maxLength)
Definition: IOBuf.h:1136
static constexpr uint64_t data[1]
Definition: Fingerprint.cpp:43
void dispose(void *p) override
Definition: IOBuf.h:1489
virtual ~DeleterBase()
Definition: IOBuf.h:1479
StringPiece data_
Iterator< typename Container::const_iterator > cbegin(const Container &c)
Definition: Padded.h:319
bool isManagedOne() const
Definition: IOBuf.h:938
Iterator< typename Container::const_iterator > cend(const Container &c)
Definition: Padded.h:324
void append(std::size_t amount)
Definition: IOBuf.h:689
void coalesceAndReallocate(size_t newLength, IOBuf *end)
Definition: IOBuf.h:1391
uintptr_t end_
def next(obj)
Definition: ast.py:58