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