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