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