]> git.proxmox.com Git - ceph.git/blob - ceph/src/seastar/include/seastar/core/temporary_buffer.hh
import 15.2.0 Octopus source
[ceph.git] / ceph / src / seastar / include / seastar / core / temporary_buffer.hh
1 /*
2 * This file is open source software, licensed to you under the terms
3 * of the Apache License, Version 2.0 (the "License"). See the NOTICE file
4 * distributed with this work for additional information regarding copyright
5 * ownership. You may not use this file except in compliance with the License.
6 *
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing,
12 * software distributed under the License is distributed on an
13 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 * KIND, either express or implied. See the License for the
15 * specific language governing permissions and limitations
16 * under the License.
17 */
18 /*
19 * Copyright (C) 2014 Cloudius Systems, Ltd.
20 */
21
22 #pragma once
23
24 #include <seastar/core/deleter.hh>
25 #include <seastar/util/eclipse.hh>
26 #include <malloc.h>
27 #include <algorithm>
28 #include <cstddef>
29
30 namespace seastar {
31
32 /// \addtogroup memory-module
33 /// @{
34
35 /// Temporary, self-managed byte buffer.
36 ///
37 /// A \c temporary_buffer is similar to an \c std::string or a \c std::unique_ptr<char[]>,
38 /// but provides more flexible memory management. A \c temporary_buffer can own the memory
39 /// it points to, or it can be shared with another \c temporary_buffer, or point at a substring
40 /// of a buffer. It uses a \ref deleter to manage its memory.
41 ///
42 /// A \c temporary_buffer should not be held indefinitely. It can be held while a request
43 /// is processed, or for a similar duration, but not longer, as it can tie up more memory
44 /// that its size indicates.
45 ///
46 /// A buffer can be shared: two \c temporary_buffer objects will point to the same data,
47 /// or a subset of it. See the \ref temporary_buffer::share() method.
48 ///
49 /// Unless you created a \c temporary_buffer yourself, do not modify its contents, as they
50 /// may be shared with another user that does not expect the data to change.
51 ///
52 /// Use cases for a \c temporary_buffer include:
53 /// - passing a substring of a tcp packet for the user to consume (zero-copy
54 /// tcp input)
55 /// - passing a refcounted blob held in memory to tcp, ensuring that when the TCP ACK
56 /// is received, the blob is released (by decrementing its reference count) (zero-copy
57 /// tcp output)
58 ///
59 /// \tparam CharType underlying character type (must be a variant of \c char).
60 template <typename CharType>
61 class temporary_buffer {
62 static_assert(sizeof(CharType) == 1, "must buffer stream of bytes");
63 CharType* _buffer;
64 size_t _size;
65 deleter _deleter;
66 public:
67 /// Creates a \c temporary_buffer of a specified size. The buffer is not shared
68 /// with anyone, and is not initialized.
69 ///
70 /// \param size buffer size, in bytes
71 explicit temporary_buffer(size_t size)
72 : _buffer(static_cast<CharType*>(malloc(size * sizeof(CharType)))), _size(size)
73 , _deleter(make_free_deleter(_buffer)) {
74 if (size && !_buffer) {
75 throw std::bad_alloc();
76 }
77 }
78 //explicit temporary_buffer(CharType* borrow, size_t size) : _buffer(borrow), _size(size) {}
79 /// Creates an empty \c temporary_buffer that does not point at anything.
80 temporary_buffer()
81 : _buffer(nullptr)
82 , _size(0) {}
83 temporary_buffer(const temporary_buffer&) = delete;
84
85 /// Moves a \c temporary_buffer.
86 temporary_buffer(temporary_buffer&& x) noexcept : _buffer(x._buffer), _size(x._size), _deleter(std::move(x._deleter)) {
87 x._buffer = nullptr;
88 x._size = 0;
89 }
90
91 /// Creates a \c temporary_buffer with a specific deleter.
92 ///
93 /// \param buf beginning of the buffer held by this \c temporary_buffer
94 /// \param size size of the buffer
95 /// \param d deleter controlling destruction of the buffer. The deleter
96 /// will be destroyed when there are no longer any users for the buffer.
97 temporary_buffer(CharType* buf, size_t size, deleter d)
98 : _buffer(buf), _size(size), _deleter(std::move(d)) {}
99 /// Creates a `temporary_buffer` containing a copy of the provided data
100 ///
101 /// \param src data buffer to be copied
102 /// \param size size of data buffer in `src`
103 temporary_buffer(const CharType* src, size_t size) : temporary_buffer(size) {
104 std::copy_n(src, size, _buffer);
105 }
106 void operator=(const temporary_buffer&) = delete;
107 /// Moves a \c temporary_buffer.
108 temporary_buffer& operator=(temporary_buffer&& x) noexcept {
109 if (this != &x) {
110 _buffer = x._buffer;
111 _size = x._size;
112 _deleter = std::move(x._deleter);
113 x._buffer = nullptr;
114 x._size = 0;
115 }
116 return *this;
117 }
118 /// Gets a pointer to the beginning of the buffer.
119 const CharType* get() const { return _buffer; }
120 /// Gets a writable pointer to the beginning of the buffer. Use only
121 /// when you are certain no user expects the buffer data not to change.
122 CharType* get_write() { return _buffer; }
123 /// Gets the buffer size.
124 size_t size() const { return _size; }
125 /// Gets a pointer to the beginning of the buffer.
126 const CharType* begin() const { return _buffer; }
127 /// Gets a pointer to the end of the buffer.
128 const CharType* end() const { return _buffer + _size; }
129 /// Returns the buffer, but with a reduced size. The original
130 /// buffer is consumed by this call and can no longer be used.
131 ///
132 /// \param size New size; must be smaller than current size.
133 /// \return the same buffer, with a prefix removed.
134 temporary_buffer prefix(size_t size) && {
135 auto ret = std::move(*this);
136 ret._size = size;
137 return ret;
138 }
139 /// Reads a character from a specific position in the buffer.
140 ///
141 /// \param pos position to read character from; must be less than size.
142 CharType operator[](size_t pos) const {
143 return _buffer[pos];
144 }
145 /// Checks whether the buffer is empty.
146 bool empty() const { return !size(); }
147 /// Checks whether the buffer is not empty.
148 explicit operator bool() const { return size(); }
149 /// Create a new \c temporary_buffer object referring to the same
150 /// underlying data. The underlying \ref deleter will not be destroyed
151 /// until both the original and the clone have been destroyed.
152 ///
153 /// \return a clone of the buffer object.
154 temporary_buffer share() {
155 return temporary_buffer(_buffer, _size, _deleter.share());
156 }
157 /// Create a new \c temporary_buffer object referring to a substring of the
158 /// same underlying data. The underlying \ref deleter will not be destroyed
159 /// until both the original and the clone have been destroyed.
160 ///
161 /// \param pos Position of the first character to share.
162 /// \param len Length of substring to share.
163 /// \return a clone of the buffer object, referring to a substring.
164 temporary_buffer share(size_t pos, size_t len) {
165 auto ret = share();
166 ret._buffer += pos;
167 ret._size = len;
168 return ret;
169 }
170 /// Clone the current \c temporary_buffer object into a new one.
171 /// This creates a temporary buffer with the same length and data but not
172 /// pointing to the memory of the original object.
173 temporary_buffer clone() const {
174 return {_buffer, _size};
175 }
176 /// Remove a prefix from the buffer. The underlying data
177 /// is not modified.
178 ///
179 /// \param pos Position of first character to retain.
180 void trim_front(size_t pos) {
181 _buffer += pos;
182 _size -= pos;
183 }
184 /// Remove a suffix from the buffer. The underlying data
185 /// is not modified.
186 ///
187 /// \param pos Position of first character to drop.
188 void trim(size_t pos) {
189 _size = pos;
190 }
191 /// Stops automatic memory management. When the \c temporary_buffer
192 /// object is destroyed, the underlying \ref deleter will not be called.
193 /// Instead, it is the caller's responsibility to destroy the deleter object
194 /// when the data is no longer needed.
195 ///
196 /// \return \ref deleter object managing the data's lifetime.
197 deleter release() {
198 return std::move(_deleter);
199 }
200 /// Creates a \c temporary_buffer object with a specified size, with
201 /// memory aligned to a specific boundary.
202 ///
203 /// \param alignment Required alignment; must be a power of two and a multiple of sizeof(void *).
204 /// \param size Required size; must be a multiple of alignment.
205 /// \return a new \c temporary_buffer object.
206 static temporary_buffer aligned(size_t alignment, size_t size) {
207 void *ptr = nullptr;
208 auto ret = ::posix_memalign(&ptr, alignment, size * sizeof(CharType));
209 auto buf = static_cast<CharType*>(ptr);
210 if (ret) {
211 throw std::bad_alloc();
212 }
213 return temporary_buffer(buf, size, make_free_deleter(buf));
214 }
215
216 /// Compare contents of this buffer with another buffer for equality
217 ///
218 /// \param o buffer to compare with
219 /// \return true if and only if contents are the same
220 bool operator==(const temporary_buffer<char>& o) const {
221 return size() == o.size() && std::equal(begin(), end(), o.begin());
222 }
223
224 /// Compare contents of this buffer with another buffer for inequality
225 ///
226 /// \param o buffer to compare with
227 /// \return true if and only if contents are not the same
228 bool operator!=(const temporary_buffer<char>& o) const {
229 return !(*this == o);
230 }
231 };
232
233 /// @}
234
235 }