// // Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BEAST_IMPL_FLAT_BUFFER_HPP #define BEAST_IMPL_FLAT_BUFFER_HPP #include #include #include namespace beast { /* Memory is laid out thusly: begin_ ..|.. in_ ..|.. out_ ..|.. last_ ..|.. end_ */ template basic_flat_buffer:: ~basic_flat_buffer() { if(begin_) alloc_traits::deallocate( this->member(), begin_, dist(begin_, end_)); } template basic_flat_buffer:: basic_flat_buffer() : begin_(nullptr) , in_(nullptr) , out_(nullptr) , last_(nullptr) , end_(nullptr) , max_((std::numeric_limits::max)()) { } template basic_flat_buffer:: basic_flat_buffer(std::size_t limit) : begin_(nullptr) , in_(nullptr) , out_(nullptr) , last_(nullptr) , end_(nullptr) , max_(limit) { } template basic_flat_buffer:: basic_flat_buffer(Allocator const& alloc) : detail::empty_base_optimization(alloc) , begin_(nullptr) , in_(nullptr) , out_(nullptr) , last_(nullptr) , end_(nullptr) , max_((std::numeric_limits::max)()) { } template basic_flat_buffer:: basic_flat_buffer(std::size_t limit, Allocator const& alloc) : detail::empty_base_optimization(alloc) , begin_(nullptr) , in_(nullptr) , out_(nullptr) , last_(nullptr) , end_(nullptr) , max_(limit) { } template basic_flat_buffer:: basic_flat_buffer(basic_flat_buffer&& other) : detail::empty_base_optimization( std::move(other.member())) , begin_(other.begin_) , in_(other.in_) , out_(other.out_) , last_(out_) , end_(other.end_) , max_(other.max_) { other.begin_ = nullptr; other.in_ = nullptr; other.out_ = nullptr; other.last_ = nullptr; other.end_ = nullptr; } template basic_flat_buffer:: basic_flat_buffer(basic_flat_buffer&& other, Allocator const& alloc) : detail::empty_base_optimization(alloc) { if(this->member() != other.member()) { begin_ = nullptr; in_ = nullptr; out_ = nullptr; last_ = nullptr; end_ = nullptr; max_ = other.max_; copy_from(other); other.reset(); } else { begin_ = other.begin_; in_ = other.in_; out_ = other.out_; last_ = out_; end_ = other.end_; max_ = other.max_; other.begin_ = nullptr; other.in_ = nullptr; other.out_ = nullptr; other.last_ = nullptr; other.end_ = nullptr; } } template basic_flat_buffer:: basic_flat_buffer(basic_flat_buffer const& other) : detail::empty_base_optimization( alloc_traits::select_on_container_copy_construction( other.member())) , begin_(nullptr) , in_(nullptr) , out_(nullptr) , last_(nullptr) , end_(nullptr) , max_(other.max_) { copy_from(other); } template basic_flat_buffer:: basic_flat_buffer(basic_flat_buffer const& other, Allocator const& alloc) : detail::empty_base_optimization(alloc) , begin_(nullptr) , in_(nullptr) , out_(nullptr) , last_(nullptr) , end_(nullptr) , max_(other.max_) { copy_from(other); } template template basic_flat_buffer:: basic_flat_buffer( basic_flat_buffer const& other) : begin_(nullptr) , in_(nullptr) , out_(nullptr) , last_(nullptr) , end_(nullptr) , max_(other.max_) { copy_from(other); } template template basic_flat_buffer:: basic_flat_buffer(basic_flat_buffer const& other, Allocator const& alloc) : detail::empty_base_optimization(alloc) , begin_(nullptr) , in_(nullptr) , out_(nullptr) , last_(nullptr) , end_(nullptr) , max_(other.max_) { copy_from(other); } template auto basic_flat_buffer:: operator=(basic_flat_buffer&& other) -> basic_flat_buffer& { if(this != &other) move_assign(other, typename alloc_traits::propagate_on_container_move_assignment{}); return *this; } template auto basic_flat_buffer:: operator=(basic_flat_buffer const& other) -> basic_flat_buffer& { if(this != &other) copy_assign(other, typename alloc_traits::propagate_on_container_copy_assignment{}); return *this; } template template auto basic_flat_buffer:: operator=(basic_flat_buffer const& other) -> basic_flat_buffer& { reset(); max_ = other.max_; copy_from(other); return *this; } //------------------------------------------------------------------------------ template auto basic_flat_buffer:: prepare(std::size_t n) -> mutable_buffers_type { if(n <= dist(out_, end_)) { // existing capacity is sufficient last_ = out_ + n; return{out_, n}; } auto const len = size(); if(n <= capacity() - len) { // after a memmove, // existing capacity is sufficient if(len > 0) std::memmove(begin_, in_, len); in_ = begin_; out_ = in_ + len; last_ = out_ + n; return {out_, n}; } // enforce maximum capacity if(n > max_ - len) BOOST_THROW_EXCEPTION(std::length_error{ "basic_flat_buffer overflow"}); // allocate a new buffer auto const new_size = std::min( max_, std::max(2 * len, len + n)); auto const p = alloc_traits::allocate( this->member(), new_size); if(begin_) { BOOST_ASSERT(p); BOOST_ASSERT(in_); std::memcpy(p, in_, len); alloc_traits::deallocate( this->member(), begin_, capacity()); } begin_ = p; in_ = begin_; out_ = in_ + len; last_ = out_ + n; end_ = begin_ + new_size; return {out_, n}; } template void basic_flat_buffer:: consume(std::size_t n) { if(n >= dist(in_, out_)) { in_ = begin_; out_ = begin_; return; } in_ += n; } template void basic_flat_buffer:: shrink_to_fit() { auto const len = size(); if(len == capacity()) return; char* p; if(len > 0) { BOOST_ASSERT(begin_); BOOST_ASSERT(in_); p = alloc_traits::allocate( this->member(), len); std::memcpy(p, in_, len); } else { p = nullptr; } alloc_traits::deallocate( this->member(), begin_, dist(begin_, end_)); begin_ = p; in_ = begin_; out_ = begin_ + len; last_ = out_; end_ = out_; } //------------------------------------------------------------------------------ template inline void basic_flat_buffer:: reset() { consume(size()); shrink_to_fit(); } template template inline void basic_flat_buffer:: copy_from(DynamicBuffer const& buffer) { if(buffer.size() == 0) return; using boost::asio::buffer_copy; commit(buffer_copy( prepare(buffer.size()), buffer.data())); } template inline void basic_flat_buffer:: move_assign(basic_flat_buffer& other, std::true_type) { reset(); this->member() = std::move(other.member()); begin_ = other.begin_; in_ = other.in_; out_ = other.out_; last_ = out_; end_ = other.end_; max_ = other.max_; other.begin_ = nullptr; other.in_ = nullptr; other.out_ = nullptr; other.last_ = nullptr; other.end_ = nullptr; } template inline void basic_flat_buffer:: move_assign(basic_flat_buffer& other, std::false_type) { reset(); if(this->member() != other.member()) { copy_from(other); other.reset(); } else { move_assign(other, std::true_type{}); } } template inline void basic_flat_buffer:: copy_assign(basic_flat_buffer const& other, std::true_type) { reset(); max_ = other.max_; this->member() = other.member(); copy_from(other); } template inline void basic_flat_buffer:: copy_assign(basic_flat_buffer const& other, std::false_type) { reset(); max_ = other.max_; copy_from(other); } template inline void basic_flat_buffer:: swap(basic_flat_buffer& other) { swap(other, typename alloc_traits::propagate_on_container_swap{}); } template inline void basic_flat_buffer:: swap(basic_flat_buffer& other, std::true_type) { using std::swap; swap(this->member(), other.member()); swap(max_, other.max_); swap(begin_, other.begin_); swap(in_, other.in_); swap(out_, other.out_); last_ = this->out_; other.last_ = other.out_; swap(end_, other.end_); } template inline void basic_flat_buffer:: swap(basic_flat_buffer& other, std::false_type) { BOOST_ASSERT(this->member() == other.member()); using std::swap; swap(max_, other.max_); swap(begin_, other.begin_); swap(in_, other.in_); swap(out_, other.out_); last_ = this->out_; other.last_ = other.out_; swap(end_, other.end_); } template void swap( basic_flat_buffer& lhs, basic_flat_buffer& rhs) { lhs.swap(rhs); } } // beast #endif