libs/http/src/detail/workspace.cpp

55.1% Lines (49/89) 63.6% Functions (7/11) 36.7% Branches (11/30)
libs/http/src/detail/workspace.cpp
Line Branch 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 <utility>
16
17 namespace boost {
18 namespace http {
19 namespace detail {
20
21 101 workspace::
22 any::
23 ~any() = default;
24
25 1776 workspace::
26 ~workspace()
27 {
28 1776 clear();
29
1/2
✓ Branch 0 taken 1776 times.
✗ Branch 1 not taken.
1776 delete[] begin_;
30 1776 }
31
32 1776 workspace::
33 workspace(
34 1776 std::size_t n)
35 1776 : begin_(new unsigned char[n])
36 1776 , front_(begin_)
37 1776 , head_(begin_ + n)
38 1776 , back_(head_)
39 1776 , end_(head_)
40 {
41 1776 }
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 22212 workspace::
94 clear() noexcept
95 {
96
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22212 times.
22212 if(! begin_)
97 return;
98
99 22212 auto const end =
100 reinterpret_cast<
101 any const*>(back_);
102 22212 auto p =
103 reinterpret_cast<
104 any const*>(head_);
105
2/2
✓ Branch 0 taken 101 times.
✓ Branch 1 taken 22212 times.
22313 while(p != end)
106 {
107 101 auto next = p->next;
108 101 p->~any();
109 101 p = next;
110 }
111 22212 front_ = begin_;
112 22212 head_ = end_;
113 22212 back_ = end_;
114 }
115
116 unsigned char*
117 18921 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
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 18921 times.
18921 if(n >= size())
124 detail::throw_length_error();
125
126 18921 auto const p = front_;
127 18921 front_ += n ;
128 18921 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 9451 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
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9451 times.
9451 if(back_ != end_)
157 detail::throw_logic_error();
158
159 // over capacity
160 9451 std::size_t const lim =
161 9451 head_ - front_;
162
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9451 times.
9451 if(n >= lim)
163 detail::throw_length_error();
164
165 9451 head_ -= n;
166 9451 back_ = head_;
167 9451 return back_;
168 }
169
170 // https://fitzgeraldnick.com/2019/11/01/always-bump-downwards.html
171 unsigned char*
172 101 workspace::
173 bump_down(
174 std::size_t size,
175 std::size_t align)
176 {
177
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 101 times.
101 BOOST_ASSERT(align > 0);
178
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 101 times.
101 BOOST_ASSERT(
179 (align & (align - 1)) == 0);
180
181 101 auto ip0 = reinterpret_cast<
182 101 std::uintptr_t>(front_);
183 101 auto ip = reinterpret_cast<
184 101 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
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 101 times.
101 if(size > ip - ip0)
191 detail::throw_length_error();
192
193 101 ip -= size;
194 101 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
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 101 times.
101 if(ip < ip0)
201 detail::throw_length_error();
202
203 return reinterpret_cast<
204 101 unsigned char*>(ip);
205 }
206
207 } // detail
208 } // http
209 } // boost
210