1//
2// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
3//
4// Distributed under the Boost Software License, Version 1.0. (See accompanying
5// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6//
7// Official repository: https://github.com/boostorg/beast
8//
9
10#ifndef BOOST_BEAST_IMPL_FLAT_BUFFER_HPP
11#define BOOST_BEAST_IMPL_FLAT_BUFFER_HPP
12
13#include <boost/core/exchange.hpp>
14#include <boost/assert.hpp>
15#include <boost/throw_exception.hpp>
16#include <memory>
17#include <stdexcept>
18
19namespace boost {
20namespace beast {
21
22/* Layout:
23
24 begin_ in_ out_ last_ end_
25 |<------->|<---------->|<---------->|<------->|
26 | readable | writable |
27*/
28
29template<class Allocator>
30basic_flat_buffer<Allocator>::
31~basic_flat_buffer()
32{
33 if(! begin_)
34 return;
35 alloc_traits::deallocate(
36 this->get(), begin_, capacity());
37}
38
39template<class Allocator>
40basic_flat_buffer<Allocator>::
41basic_flat_buffer() noexcept(default_nothrow)
42 : begin_(nullptr)
43 , in_(nullptr)
44 , out_(nullptr)
45 , last_(nullptr)
46 , end_(nullptr)
47 , max_(alloc_traits::max_size(
48 this->get()))
49{
50}
51
52template<class Allocator>
53basic_flat_buffer<Allocator>::
54basic_flat_buffer(
55 std::size_t limit) noexcept(default_nothrow)
56 : begin_(nullptr)
57 , in_(nullptr)
58 , out_(nullptr)
59 , last_(nullptr)
60 , end_(nullptr)
61 , max_(limit)
62{
63}
64
65template<class Allocator>
66basic_flat_buffer<Allocator>::
67basic_flat_buffer(Allocator const& alloc) noexcept
68 : boost::empty_value<base_alloc_type>(
69 boost::empty_init_t{}, alloc)
70 , begin_(nullptr)
71 , in_(nullptr)
72 , out_(nullptr)
73 , last_(nullptr)
74 , end_(nullptr)
75 , max_(alloc_traits::max_size(
76 this->get()))
77{
78}
79
80template<class Allocator>
81basic_flat_buffer<Allocator>::
82basic_flat_buffer(
83 std::size_t limit,
84 Allocator const& alloc) noexcept
85 : boost::empty_value<base_alloc_type>(
86 boost::empty_init_t{}, alloc)
87 , begin_(nullptr)
88 , in_(nullptr)
89 , out_(nullptr)
90 , last_(nullptr)
91 , end_(nullptr)
92 , max_(limit)
93{
94}
95
96template<class Allocator>
97basic_flat_buffer<Allocator>::
98basic_flat_buffer(basic_flat_buffer&& other) noexcept
99 : boost::empty_value<base_alloc_type>(
100 boost::empty_init_t{}, std::move(other.get()))
101 , begin_(boost::exchange(t&: other.begin_, u: nullptr))
102 , in_(boost::exchange(t&: other.in_, u: nullptr))
103 , out_(boost::exchange(t&: other.out_, u: nullptr))
104 , last_(boost::exchange(t&: other.last_, u: nullptr))
105 , end_(boost::exchange(t&: other.end_, u: nullptr))
106 , max_(other.max_)
107{
108}
109
110template<class Allocator>
111basic_flat_buffer<Allocator>::
112basic_flat_buffer(
113 basic_flat_buffer&& other,
114 Allocator const& alloc)
115 : boost::empty_value<base_alloc_type>(
116 boost::empty_init_t{}, alloc)
117{
118 if(this->get() != other.get())
119 {
120 begin_ = nullptr;
121 in_ = nullptr;
122 out_ = nullptr;
123 last_ = nullptr;
124 end_ = nullptr;
125 max_ = other.max_;
126 copy_from(other);
127 return;
128 }
129
130 begin_ = other.begin_;
131 in_ = other.in_;
132 out_ = other.out_;
133 last_ = other.out_; // invalidate
134 end_ = other.end_;
135 max_ = other.max_;
136 BOOST_ASSERT(
137 alloc_traits::max_size(this->get()) ==
138 alloc_traits::max_size(other.get()));
139 other.begin_ = nullptr;
140 other.in_ = nullptr;
141 other.out_ = nullptr;
142 other.last_ = nullptr;
143 other.end_ = nullptr;
144}
145
146template<class Allocator>
147basic_flat_buffer<Allocator>::
148basic_flat_buffer(basic_flat_buffer const& other)
149 : boost::empty_value<base_alloc_type>(boost::empty_init_t{},
150 alloc_traits::select_on_container_copy_construction(
151 other.get()))
152 , begin_(nullptr)
153 , in_(nullptr)
154 , out_(nullptr)
155 , last_(nullptr)
156 , end_(nullptr)
157 , max_(other.max_)
158{
159 copy_from(other);
160}
161
162template<class Allocator>
163basic_flat_buffer<Allocator>::
164basic_flat_buffer(
165 basic_flat_buffer const& other,
166 Allocator const& alloc)
167 : boost::empty_value<base_alloc_type>(
168 boost::empty_init_t{}, alloc)
169 , begin_(nullptr)
170 , in_(nullptr)
171 , out_(nullptr)
172 , last_(nullptr)
173 , end_(nullptr)
174 , max_(other.max_)
175{
176 copy_from(other);
177}
178
179template<class Allocator>
180template<class OtherAlloc>
181basic_flat_buffer<Allocator>::
182basic_flat_buffer(
183 basic_flat_buffer<OtherAlloc> const& other)
184 noexcept(default_nothrow)
185 : begin_(nullptr)
186 , in_(nullptr)
187 , out_(nullptr)
188 , last_(nullptr)
189 , end_(nullptr)
190 , max_(other.max_)
191{
192 copy_from(other);
193}
194
195template<class Allocator>
196template<class OtherAlloc>
197basic_flat_buffer<Allocator>::
198basic_flat_buffer(
199 basic_flat_buffer<OtherAlloc> const& other,
200 Allocator const& alloc)
201 : boost::empty_value<base_alloc_type>(
202 boost::empty_init_t{}, alloc)
203 , begin_(nullptr)
204 , in_(nullptr)
205 , out_(nullptr)
206 , last_(nullptr)
207 , end_(nullptr)
208 , max_(other.max_)
209{
210 copy_from(other);
211}
212
213template<class Allocator>
214auto
215basic_flat_buffer<Allocator>::
216operator=(basic_flat_buffer&& other) noexcept ->
217 basic_flat_buffer&
218{
219 if(this == &other)
220 return *this;
221 move_assign(other, pocma{});
222 return *this;
223}
224
225template<class Allocator>
226auto
227basic_flat_buffer<Allocator>::
228operator=(basic_flat_buffer const& other) ->
229 basic_flat_buffer&
230{
231 if(this == &other)
232 return *this;
233 copy_assign(other, pocca{});
234 return *this;
235}
236
237template<class Allocator>
238template<class OtherAlloc>
239auto
240basic_flat_buffer<Allocator>::
241operator=(
242 basic_flat_buffer<OtherAlloc> const& other) ->
243 basic_flat_buffer&
244{
245 copy_from(other);
246 return *this;
247}
248
249template<class Allocator>
250void
251basic_flat_buffer<Allocator>::
252reserve(std::size_t n)
253{
254 if(max_ < n)
255 max_ = n;
256 if(n > capacity())
257 prepare(n: n - size());
258}
259
260template<class Allocator>
261void
262basic_flat_buffer<Allocator>::
263shrink_to_fit() noexcept
264{
265 auto const len = size();
266
267 if(len == capacity())
268 return;
269
270 char* p;
271 if(len > 0)
272 {
273 BOOST_ASSERT(begin_);
274 BOOST_ASSERT(in_);
275#ifndef BOOST_NO_EXCEPTIONS
276 try
277 {
278#endif
279 p = alloc(n: len);
280#ifndef BOOST_NO_EXCEPTIONS
281 }
282 catch(std::exception const&)
283 {
284 // request could not be fulfilled,
285 // squelch the exception
286 return;
287 }
288#endif
289 std::memcpy(dest: p, src: in_, n: len);
290 }
291 else
292 {
293 p = nullptr;
294 }
295 alloc_traits::deallocate(
296 this->get(), begin_, this->capacity());
297 begin_ = p;
298 in_ = begin_;
299 out_ = begin_ + len;
300 last_ = out_;
301 end_ = out_;
302}
303
304template<class Allocator>
305void
306basic_flat_buffer<Allocator>::
307clear() noexcept
308{
309 in_ = begin_;
310 out_ = begin_;
311 last_ = begin_;
312}
313
314//------------------------------------------------------------------------------
315
316template<class Allocator>
317auto
318basic_flat_buffer<Allocator>::
319prepare(std::size_t n) ->
320 mutable_buffers_type
321{
322 auto const len = size();
323 if(len > max_ || n > (max_ - len))
324 BOOST_THROW_EXCEPTION(std::length_error{
325 "basic_flat_buffer too long"});
326 if(n <= dist(first: out_, last: end_))
327 {
328 // existing capacity is sufficient
329 last_ = out_ + n;
330 return{out_, n};
331 }
332 if(n <= capacity() - len)
333 {
334 // after a memmove,
335 // existing capacity is sufficient
336 if(len > 0)
337 {
338 BOOST_ASSERT(begin_);
339 BOOST_ASSERT(in_);
340 std::memmove(dest: begin_, src: in_, n: len);
341 }
342 in_ = begin_;
343 out_ = in_ + len;
344 last_ = out_ + n;
345 return {out_, n};
346 }
347 // allocate a new buffer
348 auto const new_size = (std::min<std::size_t>)(
349 max_,
350 (std::max<std::size_t>)(2 * len, len + n));
351 auto const p = alloc(n: new_size);
352 if(begin_)
353 {
354 BOOST_ASSERT(p);
355 BOOST_ASSERT(in_);
356 std::memcpy(dest: p, src: in_, n: len);
357 alloc_traits::deallocate(
358 this->get(), begin_, capacity());
359 }
360 begin_ = p;
361 in_ = begin_;
362 out_ = in_ + len;
363 last_ = out_ + n;
364 end_ = begin_ + new_size;
365 return {out_, n};
366}
367
368template<class Allocator>
369void
370basic_flat_buffer<Allocator>::
371consume(std::size_t n) noexcept
372{
373 if(n >= dist(first: in_, last: out_))
374 {
375 in_ = begin_;
376 out_ = begin_;
377 return;
378 }
379 in_ += n;
380}
381
382//------------------------------------------------------------------------------
383
384template<class Allocator>
385template<class OtherAlloc>
386void
387basic_flat_buffer<Allocator>::
388copy_from(
389 basic_flat_buffer<OtherAlloc> const& other)
390{
391 std::size_t const n = other.size();
392 if(n == 0 || n > capacity())
393 {
394 if(begin_ != nullptr)
395 {
396 alloc_traits::deallocate(
397 this->get(), begin_,
398 this->capacity());
399 begin_ = nullptr;
400 in_ = nullptr;
401 out_ = nullptr;
402 last_ = nullptr;
403 end_ = nullptr;
404 }
405 if(n == 0)
406 return;
407 begin_ = alloc(n);
408 in_ = begin_;
409 out_ = begin_ + n;
410 last_ = begin_ + n;
411 end_ = begin_ + n;
412 }
413 in_ = begin_;
414 out_ = begin_ + n;
415 last_ = begin_ + n;
416 if(begin_)
417 {
418 BOOST_ASSERT(other.begin_);
419 std::memcpy(dest: begin_, src: other.in_, n: n);
420 }
421}
422
423template<class Allocator>
424void
425basic_flat_buffer<Allocator>::
426move_assign(basic_flat_buffer& other, std::true_type)
427{
428 clear();
429 shrink_to_fit();
430 this->get() = std::move(other.get());
431 begin_ = other.begin_;
432 in_ = other.in_;
433 out_ = other.out_;
434 last_ = out_;
435 end_ = other.end_;
436 max_ = other.max_;
437 other.begin_ = nullptr;
438 other.in_ = nullptr;
439 other.out_ = nullptr;
440 other.last_ = nullptr;
441 other.end_ = nullptr;
442}
443
444template<class Allocator>
445void
446basic_flat_buffer<Allocator>::
447move_assign(basic_flat_buffer& other, std::false_type)
448{
449 if(this->get() != other.get())
450 {
451 copy_from(other);
452 }
453 else
454 {
455 move_assign(other, std::true_type{});
456 }
457}
458
459template<class Allocator>
460void
461basic_flat_buffer<Allocator>::
462copy_assign(basic_flat_buffer const& other, std::true_type)
463{
464 max_ = other.max_;
465 this->get() = other.get();
466 copy_from(other);
467}
468
469template<class Allocator>
470void
471basic_flat_buffer<Allocator>::
472copy_assign(basic_flat_buffer const& other, std::false_type)
473{
474 clear();
475 shrink_to_fit();
476 max_ = other.max_;
477 copy_from(other);
478}
479
480template<class Allocator>
481void
482basic_flat_buffer<Allocator>::
483swap(basic_flat_buffer& other)
484{
485 swap(other, typename
486 alloc_traits::propagate_on_container_swap{});
487}
488
489template<class Allocator>
490void
491basic_flat_buffer<Allocator>::
492swap(basic_flat_buffer& other, std::true_type)
493{
494 using std::swap;
495 swap(this->get(), other.get());
496 swap(max_, other.max_);
497 swap(begin_, other.begin_);
498 swap(in_, other.in_);
499 swap(out_, other.out_);
500 last_ = this->out_;
501 other.last_ = other.out_;
502 swap(end_, other.end_);
503}
504
505template<class Allocator>
506void
507basic_flat_buffer<Allocator>::
508swap(basic_flat_buffer& other, std::false_type)
509{
510 BOOST_ASSERT(this->get() == other.get());
511 using std::swap;
512 swap(max_, other.max_);
513 swap(begin_, other.begin_);
514 swap(in_, other.in_);
515 swap(out_, other.out_);
516 last_ = this->out_;
517 other.last_ = other.out_;
518 swap(end_, other.end_);
519}
520
521template<class Allocator>
522void
523swap(
524 basic_flat_buffer<Allocator>& lhs,
525 basic_flat_buffer<Allocator>& rhs)
526{
527 lhs.swap(rhs);
528}
529
530template<class Allocator>
531char*
532basic_flat_buffer<Allocator>::
533alloc(std::size_t n)
534{
535 if(n > alloc_traits::max_size(this->get()))
536 BOOST_THROW_EXCEPTION(std::length_error(
537 "A basic_flat_buffer exceeded the allocator's maximum size"));
538 return alloc_traits::allocate(this->get(), n);
539}
540
541} // beast
542} // boost
543
544#endif
545

source code of boost/libs/beast/include/boost/beast/core/impl/flat_buffer.hpp