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