2 // Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
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)
7 // Official repository: https://github.com/boostorg/beast
10 #ifndef BOOST_BEAST_IMPL_FLAT_BUFFER_HPP
11 #define BOOST_BEAST_IMPL_FLAT_BUFFER_HPP
13 #include <boost/assert.hpp>
14 #include <boost/throw_exception.hpp>
20 /* Memory is laid out thusly:
22 begin_ ..|.. in_ ..|.. out_ ..|.. last_ ..|.. end_
25 template<class Allocator>
26 basic_flat_buffer<Allocator>::
30 alloc_traits::deallocate(
31 this->member(), begin_, dist(begin_, end_));
34 template<class Allocator>
35 basic_flat_buffer<Allocator>::
42 , max_((std::numeric_limits<std::size_t>::max)())
46 template<class Allocator>
47 basic_flat_buffer<Allocator>::
48 basic_flat_buffer(std::size_t limit)
58 template<class Allocator>
59 basic_flat_buffer<Allocator>::
60 basic_flat_buffer(Allocator const& alloc)
61 : detail::empty_base_optimization<base_alloc_type>(alloc)
67 , max_((std::numeric_limits<std::size_t>::max)())
71 template<class Allocator>
72 basic_flat_buffer<Allocator>::
73 basic_flat_buffer(std::size_t limit, Allocator const& alloc)
74 : detail::empty_base_optimization<base_alloc_type>(alloc)
84 template<class Allocator>
85 basic_flat_buffer<Allocator>::
86 basic_flat_buffer(basic_flat_buffer&& other)
87 : detail::empty_base_optimization<base_alloc_type>(
88 std::move(other.member()))
89 , begin_(other.begin_)
96 other.begin_ = nullptr;
99 other.last_ = nullptr;
100 other.end_ = nullptr;
103 template<class Allocator>
104 basic_flat_buffer<Allocator>::
105 basic_flat_buffer(basic_flat_buffer&& other,
106 Allocator const& alloc)
107 : detail::empty_base_optimization<base_alloc_type>(alloc)
109 if(this->member() != other.member())
122 begin_ = other.begin_;
128 other.begin_ = nullptr;
130 other.out_ = nullptr;
131 other.last_ = nullptr;
132 other.end_ = nullptr;
136 template<class Allocator>
137 basic_flat_buffer<Allocator>::
138 basic_flat_buffer(basic_flat_buffer const& other)
139 : detail::empty_base_optimization<base_alloc_type>(
140 alloc_traits::select_on_container_copy_construction(
152 template<class Allocator>
153 basic_flat_buffer<Allocator>::
154 basic_flat_buffer(basic_flat_buffer const& other,
155 Allocator const& alloc)
156 : detail::empty_base_optimization<base_alloc_type>(alloc)
167 template<class Allocator>
168 template<class OtherAlloc>
169 basic_flat_buffer<Allocator>::
171 basic_flat_buffer<OtherAlloc> const& other)
182 template<class Allocator>
183 template<class OtherAlloc>
184 basic_flat_buffer<Allocator>::
185 basic_flat_buffer(basic_flat_buffer<OtherAlloc> const& other,
186 Allocator const& alloc)
187 : detail::empty_base_optimization<base_alloc_type>(alloc)
198 template<class Allocator>
200 basic_flat_buffer<Allocator>::
201 operator=(basic_flat_buffer&& other) ->
205 move_assign(other, std::integral_constant<bool,
206 alloc_traits::propagate_on_container_move_assignment::value>{});
210 template<class Allocator>
212 basic_flat_buffer<Allocator>::
213 operator=(basic_flat_buffer const& other) ->
217 copy_assign(other, std::integral_constant<bool,
218 alloc_traits::propagate_on_container_copy_assignment::value>{});
222 template<class Allocator>
223 template<class OtherAlloc>
225 basic_flat_buffer<Allocator>::
226 operator=(basic_flat_buffer<OtherAlloc> const& other) ->
235 //------------------------------------------------------------------------------
237 template<class Allocator>
239 basic_flat_buffer<Allocator>::
240 prepare(std::size_t n) ->
243 if(n <= dist(out_, end_))
245 // existing capacity is sufficient
249 auto const len = size();
250 if(n <= capacity() - len)
253 // existing capacity is sufficient
255 std::memmove(begin_, in_, len);
261 // enforce maximum capacity
263 BOOST_THROW_EXCEPTION(std::length_error{
264 "basic_flat_buffer overflow"});
265 // allocate a new buffer
266 auto const new_size = (std::min<std::size_t>)(
268 (std::max<std::size_t>)(2 * len, len + n));
269 auto const p = alloc_traits::allocate(
270 this->member(), new_size);
275 std::memcpy(p, in_, len);
276 alloc_traits::deallocate(
277 this->member(), begin_, capacity());
283 end_ = begin_ + new_size;
287 template<class Allocator>
289 basic_flat_buffer<Allocator>::
290 consume(std::size_t n)
292 if(n >= dist(in_, out_))
301 template<class Allocator>
303 basic_flat_buffer<Allocator>::
306 auto const len = size();
307 if(len == capacity())
312 BOOST_ASSERT(begin_);
314 p = alloc_traits::allocate(
315 this->member(), len);
316 std::memcpy(p, in_, len);
322 alloc_traits::deallocate(
323 this->member(), begin_, dist(begin_, end_));
331 //------------------------------------------------------------------------------
333 template<class Allocator>
336 basic_flat_buffer<Allocator>::
343 template<class Allocator>
344 template<class DynamicBuffer>
347 basic_flat_buffer<Allocator>::
348 copy_from(DynamicBuffer const& buffer)
350 if(buffer.size() == 0)
352 using boost::asio::buffer_copy;
354 prepare(buffer.size()), buffer.data()));
357 template<class Allocator>
360 basic_flat_buffer<Allocator>::
361 move_assign(basic_flat_buffer& other, std::true_type)
364 this->member() = std::move(other.member());
365 begin_ = other.begin_;
371 other.begin_ = nullptr;
373 other.out_ = nullptr;
374 other.last_ = nullptr;
375 other.end_ = nullptr;
378 template<class Allocator>
381 basic_flat_buffer<Allocator>::
382 move_assign(basic_flat_buffer& other, std::false_type)
385 if(this->member() != other.member())
392 move_assign(other, std::true_type{});
396 template<class Allocator>
399 basic_flat_buffer<Allocator>::
400 copy_assign(basic_flat_buffer const& other, std::true_type)
404 this->member() = other.member();
408 template<class Allocator>
411 basic_flat_buffer<Allocator>::
412 copy_assign(basic_flat_buffer const& other, std::false_type)
419 template<class Allocator>
422 basic_flat_buffer<Allocator>::
423 swap(basic_flat_buffer& other)
426 alloc_traits::propagate_on_container_swap{});
429 template<class Allocator>
432 basic_flat_buffer<Allocator>::
433 swap(basic_flat_buffer& other, std::true_type)
436 swap(this->member(), other.member());
437 swap(max_, other.max_);
438 swap(begin_, other.begin_);
439 swap(in_, other.in_);
440 swap(out_, other.out_);
442 other.last_ = other.out_;
443 swap(end_, other.end_);
446 template<class Allocator>
449 basic_flat_buffer<Allocator>::
450 swap(basic_flat_buffer& other, std::false_type)
452 BOOST_ASSERT(this->member() == other.member());
454 swap(max_, other.max_);
455 swap(begin_, other.begin_);
456 swap(in_, other.in_);
457 swap(out_, other.out_);
459 other.last_ = other.out_;
460 swap(end_, other.end_);
463 template<class Allocator>
466 basic_flat_buffer<Allocator>& lhs,
467 basic_flat_buffer<Allocator>& rhs)