src/detail/workspace.cpp

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