CARLA
carla/Buffer.h
Go to the documentation of this file.
1 // Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
2 // de Barcelona (UAB).
3 //
4 // This work is licensed under the terms of the MIT license.
5 // For a copy, see <https://opensource.org/licenses/MIT>.
6 
7 #pragma once
8 
9 #include "carla/Debug.h"
10 #include "carla/Exception.h"
11 #include "carla/Logging.h"
12 
13 #include <boost/asio/buffer.hpp>
14 
15 #include <cstdint>
16 #include <limits>
17 #include <memory>
18 #include <type_traits>
19 
20 #ifdef LIBCARLA_INCLUDED_FROM_UE4
22 #include "Containers/Array.h"
24 #endif // LIBCARLA_INCLUDED_FROM_UE4
25 
26 namespace carla {
27 
28  class BufferPool;
29  class BufferView;
30 
31  /// A piece of raw data.
32  ///
33  /// Note that if more capacity is needed, a new memory block is allocated and
34  /// the old one is deleted. This means that by default the buffer can only
35  /// grow. To release the memory use `clear` or `pop`.
36  ///
37  /// This is a move-only type, meant to be cheap to pass by value. If the
38  /// buffer is retrieved from a BufferPool, the memory is automatically pushed
39  /// back to the pool on destruction.
40  ///
41  /// @warning Creating a buffer bigger than max_size() is undefined.
42  class Buffer {
43 
44  // =========================================================================
45  /// @name Member types
46  // =========================================================================
47  /// @{
48 
49  public:
50 
51  using value_type = unsigned char;
52 
53  using size_type = uint32_t;
54 
55  using iterator = value_type *;
56 
57  using const_iterator = const value_type *;
58 
59  /// @}
60  // =========================================================================
61  /// @name Construction and destruction
62  // =========================================================================
63  /// @{
64 
65  public:
66 
67  /// Create an empty buffer.
68  Buffer() = default;
69 
70  /// Create a buffer with @a size bytes allocated.
71  explicit Buffer(size_type size)
72  : _size(size),
73  _capacity(size),
74  _data(std::make_unique<value_type[]>(size)) {}
75 
76  /// @copydoc Buffer(size_type)
77  explicit Buffer(uint64_t size)
78  : Buffer([size]() {
79  if (size > max_size()) {
80  throw_exception(std::invalid_argument("message size too big"));
81  }
82  return static_cast<size_type>(size);
83  } ()) {}
84 
85  /// Copy @a source into this buffer. Allocates the necessary memory.
86  template <typename T>
87  explicit Buffer(const T &source) {
88  copy_from(source);
89  }
90 
91  explicit Buffer(const value_type *data, size_type size) {
92  copy_from(data, size);
93  }
94 
95  /// @copydoc Buffer(size_type)
96  explicit Buffer(const value_type *data, uint64_t size)
97  : Buffer(data, [size]() {
98  if (size > max_size()) {
99  throw_exception(std::invalid_argument("message size too big"));
100  }
101  return static_cast<size_type>(size);
102  } ()) {}
103 
104  Buffer(const Buffer &) = delete;
105 
106  Buffer(Buffer &&rhs) noexcept
107  : _parent_pool(std::move(rhs._parent_pool)),
108  _size(rhs._size),
109  _capacity(rhs._capacity),
110  _data(rhs.pop()) {}
111 
113  if (_capacity > 0u) {
114  ReuseThisBuffer();
115  }
116  }
117 
118  /// @}
119  // =========================================================================
120  /// @name Assignment
121  // =========================================================================
122  /// @{
123 
124  public:
125 
126  Buffer &operator=(const Buffer &) = delete;
127 
128  Buffer &operator=(Buffer &&rhs) noexcept {
129  _parent_pool = std::move(rhs._parent_pool);
130  _size = rhs._size;
131  _capacity = rhs._capacity;
132  _data = rhs.pop();
133  return *this;
134  }
135 
136  /// @}
137  // =========================================================================
138  /// @name Data access
139  // =========================================================================
140  /// @{
141 
142  public:
143 
144  /// Access the byte at position @a i.
145  const value_type &operator[](size_t i) const {
146  return _data[i];
147  }
148 
149  /// Access the byte at position @a i.
150  value_type &operator[](size_t i) {
151  return _data[i];
152  }
153 
154  /// Direct access to the allocated memory or nullptr if no memory is
155  /// allocated.
156  const value_type *data() const noexcept {
157  return _data.get();
158  }
159 
160  /// Direct access to the allocated memory or nullptr if no memory is
161  /// allocated.
162  value_type *data() noexcept {
163  return _data.get();
164  }
165 
166  /// Make a boost::asio::buffer from this buffer.
167  ///
168  /// @warning Boost.Asio buffers do not own the data, it's up to the caller
169  /// to not delete the memory that this buffer holds until the asio buffer is
170  /// no longer used.
171  boost::asio::const_buffer cbuffer() const noexcept {
172  return {data(), size()};
173  }
174 
175  /// @copydoc cbuffer()
176  boost::asio::const_buffer buffer() const noexcept {
177  return cbuffer();
178  }
179 
180  /// @copydoc cbuffer()
181  boost::asio::mutable_buffer buffer() noexcept {
182  return {data(), size()};
183  }
184 
185  /// @}
186  // =========================================================================
187  /// @name Capacity
188  // =========================================================================
189  /// @{
190 
191  public:
192 
193  bool empty() const noexcept {
194  return _size == 0u;
195  }
196 
197  size_type size() const noexcept {
198  return _size;
199  }
200 
201  static constexpr size_type max_size() noexcept {
202  return (std::numeric_limits<size_type>::max)();
203  }
204 
205  size_type capacity() const noexcept {
206  return _capacity;
207  }
208 
209  /// @}
210  // =========================================================================
211  /// @name Iterators
212  // =========================================================================
213  /// @{
214 
215  public:
216 
217  const_iterator cbegin() const noexcept {
218  return _data.get();
219  }
220 
221  const_iterator begin() const noexcept {
222  return cbegin();
223  }
224 
225  iterator begin() noexcept {
226  return _data.get();
227  }
228 
229  const_iterator cend() const noexcept {
230  return cbegin() + size();
231  }
232 
233  const_iterator end() const noexcept {
234  return cend();
235  }
236 
237  iterator end() noexcept {
238  return begin() + size();
239  }
240 
241  /// @}
242  // =========================================================================
243  /// @name Modifiers
244  // =========================================================================
245  /// @{
246 
247  public:
248 
249  /// Reset the size of this buffer. If the capacity is not enough, the
250  /// current memory is discarded and a new block of size @a size is
251  /// allocated.
253  if (_capacity < size) {
254  log_debug("allocating buffer of", size, "bytes");
255  _data = std::make_unique<value_type[]>(size);
256  _capacity = size;
257  }
258  _size = size;
259  }
260 
261  /// @copydoc reset(size_type)
262  void reset(uint64_t size) {
263  if (size > max_size()) {
264  throw_exception(std::invalid_argument("message size too big"));
265  }
266  reset(static_cast<size_type>(size));
267  }
268 
269  /// Resize the buffer, a new block of size @a size is
270  /// allocated if the capacity is not enough and the data is copied.
271  void resize(uint64_t size) {
272  if(_capacity < size) {
273  std::unique_ptr<value_type[]> data = std::move(_data);
274  uint64_t old_size = size;
275  reset(size);
276  copy_from(data.get(), static_cast<size_type>(old_size));
277  }
278  _size = static_cast<size_type>(size);
279  }
280 
281  /// Release the contents of this buffer and set its size and capacity to
282  /// zero.
283  std::unique_ptr<value_type[]> pop() noexcept {
284  _size = 0u;
285  _capacity = 0u;
286  return std::move(_data);
287  }
288 
289  /// Clear the contents of this buffer and set its size and capacity to zero.
290  /// Deletes allocated memory.
291  void clear() noexcept {
292  pop();
293  }
294 
295  /// @}
296  // =========================================================================
297  /// @name copy_from
298  // =========================================================================
299  /// @{
300 
301  public:
302 
303  /// Copy @a source into this buffer. Allocates memory if necessary.
304  template <typename T>
305  void copy_from(const T &source) {
306  copy_from(0u, source);
307  }
308 
309  /// Copy @a size bytes of the memory pointed by @a data into this buffer.
310  /// Allocates memory if necessary.
312  copy_from(0u, data, size);
313  }
314 
315  /// Copy @a source into this buffer leaving at the front an offset of @a
316  /// offset bytes uninitialized. Allocates memory if necessary.
317  void copy_from(size_type offset, const Buffer &rhs) {
318  copy_from(offset, rhs.buffer());
319  }
320 
321  /// @copydoc copy_from(size_type, const Buffer &)
322  template <typename T>
323  typename std::enable_if<boost::asio::is_const_buffer_sequence<T>::value>::type
324  copy_from(size_type offset, const T &source) {
325  reset(boost::asio::buffer_size(source) + offset);
326  DEBUG_ASSERT(boost::asio::buffer_size(source) == size() - offset);
327  DEBUG_ONLY(auto bytes_copied = )
328  boost::asio::buffer_copy(buffer() + offset, source);
329  DEBUG_ASSERT(bytes_copied == size() - offset);
330  }
331 
332  /// @copydoc copy_from(size_type, const Buffer &)
333  template <typename T>
334  typename std::enable_if<!boost::asio::is_const_buffer_sequence<T>::value>::type
335  copy_from(size_type offset, const T &source) {
336  copy_from(offset, boost::asio::buffer(source));
337  }
338 
339 #ifdef LIBCARLA_INCLUDED_FROM_UE4
340  /// @copydoc copy_from(size_type, const Buffer &)
341  template <typename T>
342  void copy_from(size_type offset, const TArray<T> &source) {
343  copy_from(
344  offset,
345  reinterpret_cast<const value_type *>(source.GetData()),
346  sizeof(T) * source.Num());
347  }
348 #endif // LIBCARLA_INCLUDED_FROM_UE4
349 
350  /// Copy @a size bytes of the memory pointed by @a data into this buffer,
351  /// leaving at the front an offset of @a offset bytes uninitialized.
352  /// Allocates memory if necessary.
354  copy_from(offset, boost::asio::buffer(data, size));
355  }
356 
357  /// @}
358 
359  private:
360 
361  void ReuseThisBuffer();
362 
363  friend class BufferPool;
364  friend class BufferView;
365 
366  std::weak_ptr<BufferPool> _parent_pool;
367 
369 
371 
372  std::unique_ptr<value_type[]> _data = nullptr;
373  };
374 
375 } // namespace carla
const value_type * const_iterator
Definition: carla/Buffer.h:57
const value_type * data() const noexcept
Direct access to the allocated memory or nullptr if no memory is allocated.
Definition: carla/Buffer.h:156
Buffer(Buffer &&rhs) noexcept
Definition: carla/Buffer.h:106
void clear() noexcept
Clear the contents of this buffer and set its size and capacity to zero.
Definition: carla/Buffer.h:291
value_type & operator[](size_t i)
Access the byte at position i.
Definition: carla/Buffer.h:150
void throw_exception(const std::exception &e)
Definition: Carla.cpp:135
Buffer(const value_type *data, uint64_t size)
Create a buffer with size bytes allocated.
Definition: carla/Buffer.h:96
Creating a constant view from an existing buffer.
Definition: BufferView.h:32
void ReuseThisBuffer()
Definition: carla/Buffer.cpp:7
uint32_t size_type
Definition: carla/Buffer.h:53
This file contains definitions of common data structures used in traffic manager. ...
Definition: Carla.cpp:133
boost::asio::mutable_buffer buffer() noexcept
Make a boost::asio::buffer from this buffer.
Definition: carla/Buffer.h:181
Buffer(uint64_t size)
Create a buffer with size bytes allocated.
Definition: carla/Buffer.h:77
bool empty() const noexcept
Definition: carla/Buffer.h:193
value_type * data() noexcept
Direct access to the allocated memory or nullptr if no memory is allocated.
Definition: carla/Buffer.h:162
std::unique_ptr< value_type[]> pop() noexcept
Release the contents of this buffer and set its size and capacity to zero.
Definition: carla/Buffer.h:283
static void log_debug(Args &&...)
Definition: Logging.h:75
Buffer(const value_type *data, size_type size)
Definition: carla/Buffer.h:91
#define DEBUG_ASSERT(predicate)
Definition: Debug.h:66
void reset(size_type size)
Reset the size of this buffer.
Definition: carla/Buffer.h:252
size_type _capacity
Definition: carla/Buffer.h:370
iterator begin() noexcept
Definition: carla/Buffer.h:225
std::enable_if<!boost::asio::is_const_buffer_sequence< T >::value >::type copy_from(size_type offset, const T &source)
Copy source into this buffer leaving at the front an offset of offset bytes uninitialized.
Definition: carla/Buffer.h:335
const_iterator cend() const noexcept
Definition: carla/Buffer.h:229
boost::asio::const_buffer buffer() const noexcept
Make a boost::asio::buffer from this buffer.
Definition: carla/Buffer.h:176
value_type * iterator
Definition: carla/Buffer.h:55
void resize(uint64_t size)
Resize the buffer, a new block of size size is allocated if the capacity is not enough and the data i...
Definition: carla/Buffer.h:271
const_iterator end() const noexcept
Definition: carla/Buffer.h:233
Buffer & operator=(const Buffer &)=delete
std::weak_ptr< BufferPool > _parent_pool
Definition: carla/Buffer.h:366
size_type capacity() const noexcept
Definition: carla/Buffer.h:205
unsigned char value_type
Definition: carla/Buffer.h:51
iterator end() noexcept
Definition: carla/Buffer.h:237
const_iterator begin() const noexcept
Definition: carla/Buffer.h:221
const_iterator cbegin() const noexcept
Definition: carla/Buffer.h:217
A pool of Buffer.
Definition: BufferPool.h:30
void reset(uint64_t size)
Reset the size of this buffer.
Definition: carla/Buffer.h:262
void copy_from(size_type offset, const value_type *data, size_type size)
Copy size bytes of the memory pointed by data into this buffer, leaving at the front an offset of off...
Definition: carla/Buffer.h:353
std::enable_if< boost::asio::is_const_buffer_sequence< T >::value >::type copy_from(size_type offset, const T &source)
Copy source into this buffer leaving at the front an offset of offset bytes uninitialized.
Definition: carla/Buffer.h:324
Buffer()=default
Create an empty buffer.
A piece of raw data.
Definition: carla/Buffer.h:42
const value_type & operator[](size_t i) const
Access the byte at position i.
Definition: carla/Buffer.h:145
size_type _size
Definition: carla/Buffer.h:368
void copy_from(const value_type *data, size_type size)
Copy size bytes of the memory pointed by data into this buffer.
Definition: carla/Buffer.h:311
static constexpr size_type max_size() noexcept
Definition: carla/Buffer.h:201
size_type size() const noexcept
Definition: carla/Buffer.h:197
boost::asio::const_buffer cbuffer() const noexcept
Make a boost::asio::buffer from this buffer.
Definition: carla/Buffer.h:171
void copy_from(const T &source)
Copy source into this buffer. Allocates memory if necessary.
Definition: carla/Buffer.h:305
#define DEBUG_ONLY(code)
Definition: Debug.h:55
void copy_from(size_type offset, const Buffer &rhs)
Copy source into this buffer leaving at the front an offset of offset bytes uninitialized.
Definition: carla/Buffer.h:317
std::unique_ptr< value_type[]> _data
Definition: carla/Buffer.h:372
Buffer(const T &source)
Copy source into this buffer. Allocates the necessary memory.
Definition: carla/Buffer.h:87
Buffer(size_type size)
Create a buffer with size bytes allocated.
Definition: carla/Buffer.h:71
Buffer & operator=(Buffer &&rhs) noexcept
Definition: carla/Buffer.h:128