24 #include <hicn/transport/portability/portability.h>
25 #include <hicn/transport/utils/branch_prediction.h>
36 #include <type_traits>
40 TRANSPORT_GNU_DISABLE_WARNING(
"-Wshadow")
47 enum CreateOp { CREATE };
48 enum WrapBufferOp { WRAP_BUFFER };
49 enum TakeOwnershipOp { TAKE_OWNERSHIP };
50 enum CopyBufferOp { COPY_BUFFER };
52 using Ptr = std::shared_ptr<MemBuf>;
54 typedef void (*FreeFunction)(
void* buf,
void* userData);
56 static std::unique_ptr<MemBuf> create(std::size_t capacity);
57 MemBuf(CreateOp, std::size_t capacity);
69 static std::unique_ptr<MemBuf>
createCombined(std::size_t capacity);
78 static std::unique_ptr<MemBuf>
createSeparate(std::size_t capacity);
84 static std::unique_ptr<MemBuf>
createChain(
size_t totalCapacity,
85 std::size_t maxBufCapacity);
87 static std::unique_ptr<MemBuf> takeOwnership(
void* buf, std::size_t capacity,
88 FreeFunction freeFn =
nullptr,
89 void* userData =
nullptr,
90 bool freeOnError =
true) {
91 return takeOwnership(buf, capacity, capacity, freeFn, userData,
95 MemBuf(TakeOwnershipOp op,
void* buf, std::size_t capacity,
96 FreeFunction freeFn =
nullptr,
void* userData =
nullptr,
97 bool freeOnError =
true)
98 :
MemBuf(op, buf, capacity, capacity, freeFn, userData, freeOnError) {}
100 static std::unique_ptr<MemBuf> takeOwnership(
void* buf, std::size_t capacity,
102 FreeFunction freeFn =
nullptr,
103 void* userData =
nullptr,
104 bool freeOnError =
true);
106 MemBuf(TakeOwnershipOp,
void* buf, std::size_t capacity, std::size_t length,
107 FreeFunction freeFn =
nullptr,
void* userData =
nullptr,
108 bool freeOnError =
true);
110 static std::unique_ptr<MemBuf> wrapBuffer(
const void* buf, std::size_t length,
111 std::size_t capacity);
113 static MemBuf wrapBufferAsValue(
const void* buf, std::size_t length,
114 std::size_t capacity) noexcept;
116 MemBuf(WrapBufferOp op,
const void* buf, std::size_t length,
117 std::size_t capacity) noexcept;
124 static std::unique_ptr<MemBuf>
copyBuffer(
const void* buf, std::size_t size,
125 std::size_t headroom = 0,
126 std::size_t minTailroom = 0);
128 MemBuf(CopyBufferOp op,
const void* buf, std::size_t size,
129 std::size_t headroom = 0, std::size_t minTailroom = 0);
134 static void destroy(std::unique_ptr<MemBuf>&& data) {
135 auto destroyer = std::move(data);
142 const uint8_t* data()
const {
return data_; }
144 uint8_t* writableData() {
return data_; }
146 const uint8_t* tail()
const {
return data_ + length_; }
148 uint8_t* writableTail() {
return data_ + length_; }
150 std::size_t length()
const {
return length_; }
152 void setLength(std::size_t length) { length_ = length; }
154 std::size_t headroom()
const {
return std::size_t(data_ - buffer()); }
156 std::size_t tailroom()
const {
return std::size_t(bufferEnd() - tail()); }
158 const uint8_t* buffer()
const {
return buf_; }
160 uint8_t* writableBuffer() {
return buf_; }
162 const uint8_t* bufferEnd()
const {
return buf_ + capacity_; }
164 std::size_t capacity()
const {
return capacity_; }
166 MemBuf* next() {
return next_; }
168 const MemBuf* next()
const {
return next_; }
170 MemBuf* prev() {
return prev_; }
172 const MemBuf* prev()
const {
return prev_; }
191 assert(amount <= tailroom());
194 memmove(data_ + amount, data_, length_);
212 assert(amount <= headroom());
215 memmove(data_ - amount, data_, length_);
220 void prepend(std::size_t amount) {
225 void append(std::size_t amount) { length_ += amount; }
227 void trimStart(std::size_t amount) {
232 void trimEnd(std::size_t amount) { length_ -= amount; }
238 data_ = writableBuffer();
242 void reserve(std::size_t minHeadroom, std::size_t minTailroom) {
244 if (headroom() >= minHeadroom && tailroom() >= minTailroom) {
249 if (length() == 0 && headroom() + tailroom() >= minHeadroom + minTailroom) {
250 data_ = writableBuffer() + minHeadroom;
254 reserveSlow(minHeadroom, minTailroom);
257 bool isChained()
const {
258 assert((next_ ==
this) == (prev_ ==
this));
259 return next_ !=
this;
262 size_t countChainElements()
const;
264 std::size_t computeChainDataLength()
const;
266 void prependChain(std::unique_ptr<MemBuf>&& iobuf);
268 void appendChain(std::unique_ptr<MemBuf>&& iobuf) {
270 next_->prependChain(std::move(iobuf));
273 std::unique_ptr<MemBuf> unlink() {
274 next_->prev_ = prev_;
275 prev_->next_ = next_;
278 return std::unique_ptr<MemBuf>(
this);
285 std::unique_ptr<MemBuf>
pop() {
287 next_->prev_ = prev_;
288 prev_->next_ = next_;
291 return std::unique_ptr<MemBuf>((next ==
this) ?
nullptr : next);
310 assert(head !=
this);
311 assert(tail !=
this);
313 head->prev_->next_ = tail->next_;
314 tail->next_->prev_ = head->prev_;
319 return std::unique_ptr<MemBuf>(head);
329 const MemBuf* current =
this;
334 current = current->next_;
335 if (current ==
this) {
347 const MemBuf* current =
this;
352 current = current->next_;
353 if (current ==
this) {
378 if ((TRANSPORT_EXPECT_FALSE(!sharedInfo()))) {
382 if ((TRANSPORT_EXPECT_FALSE(sharedInfo()->externallyShared))) {
386 if ((TRANSPORT_EXPECT_TRUE(!(flags() & flag_maybe_shared)))) {
393 bool shared = sharedInfo()->refcount.load(std::memory_order_acquire) > 1;
396 clearFlags(flag_maybe_shared);
463 SharedInfo* info = sharedInfo();
465 info->externallyShared =
true;
480 makeManagedChained();
562 if (!isChained() || length_ >= maxLength) {
565 coalesceSlow(maxLength);
576 std::unique_ptr<MemBuf>
clone()
const;
590 std::unique_ptr<MemBuf>
cloneOne()
const;
617 std::size_t newHeadroom, std::size_t newTailroom)
const;
630 std::size_t newHeadroom, std::size_t newTailroom)
const;
653 std::vector<struct iovec>
getIov()
const;
664 void appendToIov(std::vector<struct iovec>* iov)
const;
683 static std::unique_ptr<MemBuf>
wrapIov(
const iovec* vec,
size_t count);
692 FreeFunction freeFn =
nullptr,
693 void* userData =
nullptr,
694 bool freeOnError =
true);
714 void*
operator new(
size_t size);
715 void*
operator new(
size_t size,
void* ptr);
716 void operator delete(
void* ptr);
717 void operator delete(
void* ptr,
void* placement);
723 bool operator!=(
const MemBuf& other);
769 enum FlagsEnum : uintptr_t {
773 flag_free_shared_info = 0x1,
774 flag_maybe_shared = 0x2,
775 flag_mask = flag_free_shared_info | flag_maybe_shared
780 SharedInfo(FreeFunction fn,
void* arg);
786 std::atomic<uint32_t> refcount;
787 bool externallyShared{
false};
792 struct HeapFullStorage;
801 struct InternalConstructor {};
802 MemBuf(InternalConstructor, uintptr_t flagsAndSharedInfo, uint8_t* buf,
803 std::size_t capacity, uint8_t* data, std::size_t length) noexcept;
805 void unshareOneSlow();
806 void unshareChained();
807 void makeManagedChained();
809 void coalesceSlow(
size_t maxLength);
812 void coalesceAndReallocate(
size_t newHeadroom,
size_t newLength,
MemBuf* end,
814 void coalesceAndReallocate(
size_t newLength,
MemBuf* end) {
815 coalesceAndReallocate(headroom(), newLength, end, end->prev_->tailroom());
817 void decrementRefcount();
818 void reserveSlow(std::size_t minHeadroom, std::size_t minTailroom);
819 void freeExtBuffer();
821 static size_t goodExtBufferSize(std::size_t minCapacity);
822 static void initExtBuffer(uint8_t* buf,
size_t mallocSize,
823 SharedInfo** infoReturn,
824 std::size_t* capacityReturn);
825 static void allocExtBuffer(std::size_t minCapacity, uint8_t** bufReturn,
826 SharedInfo** infoReturn,
827 std::size_t* capacityReturn);
828 static void releaseStorage(HeapStorage* storage, uint16_t freeFlags);
829 static void freeInternalBuf(
void* buf,
void* userData);
851 uint8_t* data_{
nullptr};
852 uint8_t* buf_{
nullptr};
853 std::size_t length_{0};
854 std::size_t capacity_{0};
857 mutable uintptr_t flags_and_shared_info_{0};
859 static inline uintptr_t packFlagsAndSharedInfo(uintptr_t flags,
861 uintptr_t uinfo =
reinterpret_cast<uintptr_t
>(info);
862 return flags | uinfo;
865 inline SharedInfo* sharedInfo()
const {
866 return reinterpret_cast<SharedInfo*
>(flags_and_shared_info_ & ~flag_mask);
869 inline void setSharedInfo(SharedInfo* info) {
870 uintptr_t uinfo =
reinterpret_cast<uintptr_t
>(info);
871 flags_and_shared_info_ = (flags_and_shared_info_ & flag_mask) | uinfo;
874 inline uintptr_t flags()
const {
return flags_and_shared_info_ & flag_mask; }
877 inline void setFlags(uintptr_t flags)
const {
878 flags_and_shared_info_ |= flags;
881 inline void clearFlags(uintptr_t flags)
const {
882 flags_and_shared_info_ &= ~flags;
885 inline void setFlagsAndSharedInfo(uintptr_t flags, SharedInfo* info) {
886 flags_and_shared_info_ = packFlagsAndSharedInfo(flags, info);
890 virtual ~DeleterBase() {}
891 virtual void dispose(
void* p) = 0;
894 template <
class UniquePtr>
895 struct UniquePtrDeleter :
public DeleterBase {
896 typedef typename UniquePtr::pointer Pointer;
897 typedef typename UniquePtr::deleter_type Deleter;
899 explicit UniquePtrDeleter(Deleter deleter) : deleter_(std::move(deleter)) {}
900 void dispose(
void* p)
override {
902 deleter_(
static_cast<Pointer
>(p));
913 static void freeUniquePtrBuffer(
void* ptr,
void* userData) {
914 static_cast<DeleterBase*
>(userData)->dispose(ptr);
931 std::size_t headroom,
932 std::size_t minTailroom) {
933 std::size_t capacity = headroom + size + minTailroom;
934 std::unique_ptr<MemBuf> buf = MemBuf::create(capacity);
935 buf->advance(headroom);
937 memcpy(buf->writableData(), data, size);