Line data Source code
1 : //
2 : // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3 : // Copyright (c) 2025 Mohammad Nejati
4 : //
5 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
6 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 : //
8 : // Official repository: https://github.com/cppalliance/http_proto
9 : //
10 :
11 : #include <boost/http_proto/detail/workspace.hpp>
12 : #include <boost/http_proto/detail/except.hpp>
13 : #include <boost/assert.hpp>
14 : #include <boost/core/exchange.hpp>
15 : #include <utility>
16 :
17 : namespace boost {
18 : namespace http_proto {
19 : namespace detail {
20 :
21 1011 : workspace::
22 : any::
23 : ~any() = default;
24 :
25 1078 : workspace::
26 : ~workspace()
27 : {
28 1078 : clear();
29 1078 : delete[] begin_;
30 1078 : }
31 :
32 1078 : workspace::
33 : workspace(
34 1078 : std::size_t n)
35 1078 : : begin_(new unsigned char[n])
36 1078 : , front_(begin_)
37 1078 : , head_(begin_ + n)
38 1078 : , back_(head_)
39 1078 : , end_(head_)
40 : {
41 1078 : }
42 :
43 0 : workspace::
44 : workspace(
45 0 : workspace&& other) noexcept
46 0 : : begin_(boost::exchange(other.begin_, nullptr))
47 0 : , front_(boost::exchange(other.front_, nullptr))
48 0 : , head_(boost::exchange(other.head_, nullptr))
49 0 : , back_(boost::exchange(other.back_, nullptr))
50 0 : , end_(boost::exchange(other.end_, nullptr))
51 : {
52 0 : }
53 :
54 : workspace&
55 0 : workspace::
56 : operator=(
57 : workspace&& other) noexcept
58 : {
59 0 : if(this != &other)
60 : {
61 0 : delete[] begin_;
62 :
63 0 : begin_ = boost::exchange(other.begin_, nullptr);
64 0 : front_ = boost::exchange(other.front_, nullptr);
65 0 : head_ = boost::exchange(other.head_, nullptr);
66 0 : back_ = boost::exchange(other.back_, nullptr);
67 0 : end_ = boost::exchange(other.end_, nullptr);
68 : }
69 0 : return *this;
70 : }
71 :
72 : void
73 0 : workspace::
74 : allocate(
75 : std::size_t n)
76 : {
77 : // Cannot be empty
78 0 : if(n == 0)
79 0 : detail::throw_invalid_argument();
80 :
81 : // Already allocated
82 0 : if(begin_ != nullptr)
83 0 : detail::throw_logic_error();
84 :
85 0 : begin_ = new unsigned char[n];
86 0 : front_ = begin_;
87 0 : head_ = begin_ + n;
88 0 : back_ = head_;
89 0 : end_ = head_;
90 0 : }
91 :
92 : void
93 21990 : workspace::
94 : clear() noexcept
95 : {
96 21990 : if(! begin_)
97 0 : return;
98 :
99 21990 : auto const end =
100 : reinterpret_cast<
101 : any const*>(back_);
102 21990 : auto p =
103 : reinterpret_cast<
104 : any const*>(head_);
105 23001 : while(p != end)
106 : {
107 1011 : auto next = p->next;
108 1011 : p->~any();
109 1011 : p = next;
110 : }
111 21990 : front_ = begin_;
112 21990 : head_ = end_;
113 21990 : back_ = end_;
114 : }
115 :
116 : unsigned char*
117 28770 : workspace::
118 : reserve_front(
119 : std::size_t n)
120 : {
121 : // Requested size exceeds available space.
122 : // Note you can never reserve the last byte.
123 28770 : if(n >= size())
124 0 : detail::throw_length_error();
125 :
126 28770 : auto const p = front_;
127 28770 : front_ += n ;
128 28770 : return p;
129 : }
130 :
131 : unsigned char*
132 368 : workspace::
133 : try_reserve_front(
134 : std::size_t n) noexcept
135 : {
136 : // Requested size exceeds available space.
137 : // Note you can never reserve the last byte.
138 368 : if(n >= size())
139 0 : return nullptr;
140 :
141 368 : auto const p = front_;
142 368 : front_ += n ;
143 368 : return p;
144 : }
145 :
146 : unsigned char*
147 10006 : workspace::
148 : reserve_back(
149 : std::size_t n)
150 : {
151 : // // can't reserve after acquire
152 : // if(head_ != end_)
153 : // detail::throw_logic_error();
154 :
155 : // can't reserve twice
156 10006 : if(back_ != end_)
157 0 : detail::throw_logic_error();
158 :
159 : // over capacity
160 10006 : std::size_t const lim =
161 10006 : head_ - front_;
162 10006 : if(n >= lim)
163 0 : detail::throw_length_error();
164 :
165 10006 : head_ -= n;
166 10006 : back_ = head_;
167 10006 : return back_;
168 : }
169 :
170 : // https://fitzgeraldnick.com/2019/11/01/always-bump-downwards.html
171 : unsigned char*
172 1011 : workspace::
173 : bump_down(
174 : std::size_t size,
175 : std::size_t align)
176 : {
177 1011 : BOOST_ASSERT(align > 0);
178 1011 : BOOST_ASSERT(
179 : (align & (align - 1)) == 0);
180 :
181 1011 : auto ip0 = reinterpret_cast<
182 1011 : std::uintptr_t>(front_);
183 1011 : auto ip = reinterpret_cast<
184 1011 : std::uintptr_t>(head_);
185 :
186 : // If you get an exception here, it
187 : // means that a buffer was too small
188 : // for your workload. Increase the
189 : // buffer size.
190 1011 : if(size > ip - ip0)
191 0 : detail::throw_length_error();
192 :
193 1011 : ip -= size;
194 1011 : ip &= ~(align - 1);
195 :
196 : // If you get an exception here, it
197 : // means that a buffer was too small
198 : // for your workload. Increase the
199 : // buffer size.
200 1011 : if(ip < ip0)
201 0 : detail::throw_length_error();
202 :
203 : return reinterpret_cast<
204 1011 : unsigned char*>(ip);
205 : }
206 :
207 : } // detail
208 : } // http_proto
209 : } // boost
|