|  | // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #ifndef QUICHE_COMMON_QUICHE_BUFFER_ALLOCATOR_H_ | 
|  | #define QUICHE_COMMON_QUICHE_BUFFER_ALLOCATOR_H_ | 
|  |  | 
|  | #include <stddef.h> | 
|  |  | 
|  | #include <memory> | 
|  |  | 
|  | #include "absl/strings/string_view.h" | 
|  | #include "common/platform/api/quiche_export.h" | 
|  | #include "common/platform/api/quiche_iovec.h" | 
|  |  | 
|  | namespace quiche { | 
|  |  | 
|  | // Abstract base class for classes which allocate and delete buffers. | 
|  | class QUICHE_EXPORT_PRIVATE QuicheBufferAllocator { | 
|  | public: | 
|  | virtual ~QuicheBufferAllocator() = default; | 
|  |  | 
|  | // Returns or allocates a new buffer of |size|. Never returns null. | 
|  | virtual char* New(size_t size) = 0; | 
|  |  | 
|  | // Returns or allocates a new buffer of |size| if |flag_enable| is true. | 
|  | // Otherwise, returns a buffer that is compatible with this class directly | 
|  | // with operator new. Never returns null. | 
|  | virtual char* New(size_t size, bool flag_enable) = 0; | 
|  |  | 
|  | // Releases a buffer. | 
|  | virtual void Delete(char* buffer) = 0; | 
|  |  | 
|  | // Marks the allocator as being idle. Serves as a hint to notify the allocator | 
|  | // that it should release any resources it's still holding on to. | 
|  | virtual void MarkAllocatorIdle() {} | 
|  | }; | 
|  |  | 
|  | // A deleter that can be used to manage ownership of buffers allocated via | 
|  | // QuicheBufferAllocator through std::unique_ptr. | 
|  | class QUICHE_EXPORT_PRIVATE QuicheBufferDeleter { | 
|  | public: | 
|  | explicit QuicheBufferDeleter(QuicheBufferAllocator* allocator) | 
|  | : allocator_(allocator) {} | 
|  |  | 
|  | QuicheBufferAllocator* allocator() { return allocator_; } | 
|  | void operator()(char* buffer) { allocator_->Delete(buffer); } | 
|  |  | 
|  | private: | 
|  | QuicheBufferAllocator* allocator_; | 
|  | }; | 
|  |  | 
|  | using QuicheUniqueBufferPtr = std::unique_ptr<char[], QuicheBufferDeleter>; | 
|  |  | 
|  | inline QuicheUniqueBufferPtr MakeUniqueBuffer(QuicheBufferAllocator* allocator, | 
|  | size_t size) { | 
|  | return QuicheUniqueBufferPtr(allocator->New(size), | 
|  | QuicheBufferDeleter(allocator)); | 
|  | } | 
|  |  | 
|  | // QuicheUniqueBufferPtr with a length attached to it.  Similar to | 
|  | // QuicheMemSlice, except unlike QuicheMemSlice, QuicheBuffer is mutable and is | 
|  | // not platform-specific.  Also unlike QuicheMemSlice, QuicheBuffer can be | 
|  | // empty. | 
|  | class QUICHE_EXPORT_PRIVATE QuicheBuffer { | 
|  | public: | 
|  | QuicheBuffer() : buffer_(nullptr, QuicheBufferDeleter(nullptr)), size_(0) {} | 
|  | QuicheBuffer(QuicheBufferAllocator* allocator, size_t size) | 
|  | : buffer_(MakeUniqueBuffer(allocator, size)), size_(size) {} | 
|  |  | 
|  | QuicheBuffer(QuicheUniqueBufferPtr buffer, size_t size) | 
|  | : buffer_(std::move(buffer)), size_(size) {} | 
|  |  | 
|  | // Make sure the move constructor zeroes out the size field. | 
|  | QuicheBuffer(QuicheBuffer&& other) | 
|  | : buffer_(std::move(other.buffer_)), size_(other.size_) { | 
|  | other.buffer_ = nullptr; | 
|  | other.size_ = 0; | 
|  | } | 
|  | QuicheBuffer& operator=(QuicheBuffer&& other) { | 
|  | buffer_ = std::move(other.buffer_); | 
|  | size_ = other.size_; | 
|  |  | 
|  | other.buffer_ = nullptr; | 
|  | other.size_ = 0; | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | // Factory method to create a QuicheBuffer that holds a copy of `data`. | 
|  | static QuicheBuffer Copy(QuicheBufferAllocator* allocator, | 
|  | absl::string_view data) { | 
|  | QuicheBuffer buffer(allocator, data.size()); | 
|  | memcpy(buffer.data(), data.data(), data.size()); | 
|  | return buffer; | 
|  | } | 
|  |  | 
|  | // Factory method to create a QuicheBuffer of length `buffer_length` that | 
|  | // holds a copy of `buffer_length` bytes from `iov` starting at offset | 
|  | // `iov_offset`.  `iov` must be at least `iov_offset + buffer_length` total | 
|  | // length. | 
|  | static QuicheBuffer CopyFromIovec(QuicheBufferAllocator* allocator, | 
|  | const struct iovec* iov, int iov_count, | 
|  | size_t iov_offset, size_t buffer_length); | 
|  |  | 
|  | const char* data() const { return buffer_.get(); } | 
|  | char* data() { return buffer_.get(); } | 
|  | size_t size() const { return size_; } | 
|  | bool empty() const { return size_ == 0; } | 
|  | absl::string_view AsStringView() const { | 
|  | return absl::string_view(data(), size()); | 
|  | } | 
|  |  | 
|  | // Releases the ownership of the underlying buffer. | 
|  | QuicheUniqueBufferPtr Release() { | 
|  | size_ = 0; | 
|  | return std::move(buffer_); | 
|  | } | 
|  |  | 
|  | private: | 
|  | QuicheUniqueBufferPtr buffer_; | 
|  | size_t size_; | 
|  | }; | 
|  |  | 
|  | }  // namespace quiche | 
|  |  | 
|  | #endif  // QUICHE_COMMON_QUICHE_BUFFER_ALLOCATOR_H_ |