2 // Copyright (c) 2013-2016 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)
8 #ifndef BEAST_IMPL_FLAT_STREAMBUF_HPP
9 #define BEAST_IMPL_FLAT_STREAMBUF_HPP
11 #include <boost/assert.hpp>
16 /* Memory is laid out thusly:
18 p_ ..|.. in_ ..|.. out_ ..|.. last_ ..|.. end_
25 next_pow2(std::size_t x)
33 return std::size_t{1} << n;
38 template<class Allocator>
40 basic_flat_streambuf<Allocator>::
41 move_from(basic_flat_streambuf& other)
52 other.last_ = nullptr;
56 template<class Allocator>
57 template<class OtherAlloc>
59 basic_flat_streambuf<Allocator>::
60 copy_from(basic_flat_streambuf<
61 OtherAlloc> const& other)
64 auto const n = other.size();
67 p_ = alloc_traits::allocate(
73 std::memcpy(in_, other.in_, n);
83 template<class Allocator>
84 basic_flat_streambuf<Allocator>::
85 ~basic_flat_streambuf()
88 alloc_traits::deallocate(
89 this->member(), p_, dist(p_, end_));
92 template<class Allocator>
93 basic_flat_streambuf<Allocator>::
94 basic_flat_streambuf(basic_flat_streambuf&& other)
95 : detail::empty_base_optimization<
96 allocator_type>(std::move(other.member()))
101 template<class Allocator>
102 basic_flat_streambuf<Allocator>::
103 basic_flat_streambuf(basic_flat_streambuf&& other,
104 Allocator const& alloc)
105 : detail::empty_base_optimization<
106 allocator_type>(alloc)
108 if(this->member() != other.member())
116 template<class Allocator>
117 basic_flat_streambuf<Allocator>::
118 basic_flat_streambuf(
119 basic_flat_streambuf const& other)
120 : detail::empty_base_optimization<allocator_type>(
121 alloc_traits::select_on_container_copy_construction(
127 template<class Allocator>
128 basic_flat_streambuf<Allocator>::
129 basic_flat_streambuf(
130 basic_flat_streambuf const& other,
131 Allocator const& alloc)
132 : detail::empty_base_optimization<
133 allocator_type>(alloc)
138 template<class Allocator>
139 template<class OtherAlloc>
140 basic_flat_streambuf<Allocator>::
141 basic_flat_streambuf(
142 basic_flat_streambuf<OtherAlloc> const& other)
147 template<class Allocator>
148 template<class OtherAlloc>
149 basic_flat_streambuf<Allocator>::
150 basic_flat_streambuf(
151 basic_flat_streambuf<OtherAlloc> const& other,
152 Allocator const& alloc)
153 : detail::empty_base_optimization<
154 allocator_type>(alloc)
159 template<class Allocator>
160 basic_flat_streambuf<Allocator>::
161 basic_flat_streambuf(std::size_t limit)
169 BOOST_ASSERT(limit >= 1);
172 template<class Allocator>
173 basic_flat_streambuf<Allocator>::
174 basic_flat_streambuf(Allocator const& alloc,
176 : detail::empty_base_optimization<
177 allocator_type>(alloc)
185 BOOST_ASSERT(limit >= 1);
188 template<class Allocator>
190 basic_flat_streambuf<Allocator>::
191 prepare(std::size_t n) ->
194 if(n <= dist(out_, end_))
199 auto const len = size();
200 if(n <= dist(p_, end_) - len)
203 std::memmove(p_, in_, len);
210 throw std::length_error{
211 "flat_streambuf overflow"};
212 auto const new_size = (std::min)(max_,
213 std::max<std::size_t>(
214 detail::next_pow2(len + n), min_size));
215 auto const p = alloc_traits::allocate(
216 this->member(), new_size);
217 std::memcpy(p, in_, len);
218 alloc_traits::deallocate(
219 this->member(), p_, dist(p_, end_));
224 end_ = p_ + new_size;
228 template<class Allocator>
230 basic_flat_streambuf<Allocator>::
231 consume(std::size_t n)
233 if(n >= dist(in_, out_))
242 template<class Allocator>
244 basic_flat_streambuf<Allocator>::
245 reserve(std::size_t n)
247 if(n <= dist(p_, end_))
250 throw std::length_error{
251 "flat_streambuf overflow"};
252 auto const new_size = (std::min)(max_,
253 std::max<std::size_t>(
254 detail::next_pow2(n), min_size));
255 auto const p = alloc_traits::allocate(
256 this->member(), new_size);
257 auto const len = size();
259 std::memcpy(p, in_, len);
260 alloc_traits::deallocate(
261 this->member(), p_, dist(p_, end_));
266 end_ = p_ + new_size;
269 template<class Allocator>
271 basic_flat_streambuf<Allocator>::
274 auto const len = size();
275 if(len == dist(p_, end_))
280 p = alloc_traits::allocate(
281 this->member(), len);
282 std::memcpy(p, in_, len);
288 alloc_traits::deallocate(
289 this->member(), p_, dist(p_, end_));
297 template<class Allocator>
299 read_size_helper(basic_flat_streambuf<
300 Allocator> const& fb, std::size_t max_size)
302 BOOST_ASSERT(max_size >= 1);
303 auto const len = fb.size();
304 auto const avail = fb.capacity() - len;
306 return (std::min)(avail, max_size);
307 auto size = (std::min)(
308 fb.capacity() * 2, fb.max_size()) - len;
311 return (std::min)(size, max_size);