src/detail/workspace.cpp

55.1% Lines (49/0/89) 63.6% List of functions (7/0/11)
workspace.cpp
f(x) Functions (11)
Line TLA Hits 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 159x workspace::
23 any::
24 ~any() = default;
25
26 2333x workspace::
27 ~workspace()
28 {
29 2333x clear();
30 2333x delete[] begin_;
31 2333x }
32
33 2333x workspace::
34 workspace(
35 2333x std::size_t n)
36 2333x : begin_(new unsigned char[n])
37 2333x , front_(begin_)
38 2333x , head_(begin_ + n)
39 2333x , back_(head_)
40 2333x , end_(head_)
41 {
42 2333x }
43
44 workspace::
45 workspace(
46 workspace&& other) noexcept
47 : begin_(boost::exchange(other.begin_, nullptr))
48 , front_(boost::exchange(other.front_, nullptr))
49 , head_(boost::exchange(other.head_, nullptr))
50 , back_(boost::exchange(other.back_, nullptr))
51 , end_(boost::exchange(other.end_, nullptr))
52 {
53 }
54
55 workspace&
56 workspace::
57 operator=(
58 workspace&& other) noexcept
59 {
60 if(this != &other)
61 {
62 delete[] begin_;
63
64 begin_ = boost::exchange(other.begin_, nullptr);
65 front_ = boost::exchange(other.front_, nullptr);
66 head_ = boost::exchange(other.head_, nullptr);
67 back_ = boost::exchange(other.back_, nullptr);
68 end_ = boost::exchange(other.end_, nullptr);
69 }
70 return *this;
71 }
72
73 void
74 workspace::
75 allocate(
76 std::size_t n)
77 {
78 // Cannot be empty
79 if(n == 0)
80 detail::throw_invalid_argument();
81
82 // Already allocated
83 if(begin_ != nullptr)
84 detail::throw_logic_error();
85
86 begin_ = new unsigned char[n];
87 front_ = begin_;
88 head_ = begin_ + n;
89 back_ = head_;
90 end_ = head_;
91 }
92
93 void
94 23754x workspace::
95 clear() noexcept
96 {
97 23754x if(! begin_)
98 return;
99
100 23754x auto const end =
101 reinterpret_cast<
102 any const*>(back_);
103 23754x auto p =
104 reinterpret_cast<
105 any const*>(head_);
106 23913x while(p != end)
107 {
108 159x auto next = p->next;
109 159x p->~any();
110 159x p = next;
111 }
112 23754x front_ = begin_;
113 23754x head_ = end_;
114 23754x back_ = end_;
115 }
116
117 unsigned char*
118 19266x 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 19266x if(n >= size())
125 detail::throw_length_error();
126
127 19266x auto const p = front_;
128 19266x front_ += n ;
129 19266x return p;
130 }
131
132 unsigned char*
133 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 if(n >= size())
140 return nullptr;
141
142 auto const p = front_;
143 front_ += n ;
144 return p;
145 }
146
147 unsigned char*
148 9585x 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 9585x if(back_ != end_)
158 detail::throw_logic_error();
159
160 // over capacity
161 9585x std::size_t const lim =
162 9585x head_ - front_;
163 9585x if(n >= lim)
164 detail::throw_length_error();
165
166 9585x head_ -= n;
167 9585x back_ = head_;
168 9585x return back_;
169 }
170
171 // https://fitzgeraldnick.com/2019/11/01/always-bump-downwards.html
172 unsigned char*
173 159x workspace::
174 bump_down(
175 std::size_t size,
176 std::size_t align)
177 {
178 159x BOOST_ASSERT(align > 0);
179 159x BOOST_ASSERT(
180 (align & (align - 1)) == 0);
181
182 159x auto ip0 = reinterpret_cast<
183 159x std::uintptr_t>(front_);
184 159x auto ip = reinterpret_cast<
185 159x 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 159x if(size > ip - ip0)
192 detail::throw_length_error();
193
194 159x ip -= size;
195 159x 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 159x if(ip < ip0)
202 detail::throw_length_error();
203
204 return reinterpret_cast<
205 159x unsigned char*>(ip);
206 }
207
208 } // detail
209 } // http
210 } // boost
211