GCC Code Coverage Report


Directory: libs/http_proto/include/boost/http_proto/
File: boost/http_proto/detail/workspace.hpp
Date: 2023-01-09 16:11:13
Exec Total Coverage
Lines: 0 20 0.0%
Functions: 0 6 0.0%
Branches: 0 4 0.0%

Line Branch Exec Source
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 #ifndef BOOST_HTTP_PROTO_DETAIL_WORKSPACE_HPP
11 #define BOOST_HTTP_PROTO_DETAIL_WORKSPACE_HPP
12
13 #include <boost/http_proto/detail/except.hpp>
14 #include <boost/assert.hpp>
15 #include <cstdlib>
16 #include <new>
17 #include <utility>
18 #include <stddef.h> // ::max_align_t
19
20 namespace boost {
21 namespace http_proto {
22 namespace detail {
23
24 class workspace
25 {
26 struct any
27 {
28 any* next = nullptr;
29
30 virtual ~any() = 0;
31 };
32
33 template<class T>
34 struct alignas(alignof(::max_align_t))
35 any_t : any
36 {
37 T t_;
38
39 any_t() = delete;
40 any_t(any_t&&) = default;
41
42 explicit
43 any_t(
44 T&& t)
45 : t_(std::move(t))
46 {
47 }
48
49 explicit
50 any_t(
51 T const& t)
52 : t_(t)
53 {
54 }
55 };
56
57 template<class T>
58 struct alignas(alignof(::max_align_t))
59 any_n : any
60 {
61 std::size_t n_ = 0;
62
63 any_n() = default;
64
65 ~any_n()
66 {
67 for(std::size_t i = n_;
68 i-- > 0;)
69 data()[i].~T();
70 }
71
72 any_n(
73 std::size_t n,
74 T const& t)
75 : any_n()
76 {
77 while(n_ < n)
78 {
79 new(&data()[n_]) T(t);
80 ++n_;
81 }
82 }
83
84 T*
85 data() noexcept
86 {
87 return
88 reinterpret_cast<T*>(
89 this + 1);
90 }
91 };
92
93 unsigned char* begin_ = nullptr;
94 unsigned char* end_ = nullptr;
95 unsigned char* head_ = nullptr;
96
97 public:
98 workspace() = default;
99
100 ~workspace()
101 {
102 clear();
103 delete[] begin_;
104 }
105
106 explicit
107 workspace(
108 std::size_t n)
109 : begin_(new unsigned char[n])
110 , end_(begin_ + n)
111 , head_(end_)
112 {
113 }
114
115 void*
116 data() noexcept
117 {
118 return begin_;
119 }
120
121 std::size_t
122 size() const noexcept
123 {
124 return head_ - begin_;
125 }
126
127 void
128 clear()
129 {
130 auto const end =
131 reinterpret_cast<
132 any const*>(end_);
133 auto p =
134 reinterpret_cast<
135 any const*>(head_);
136 while(p != end)
137 {
138 auto next = p->next;
139 p->~any();
140 p = next;
141 }
142 head_ = end_;
143 }
144
145 template<class T>
146 T&
147 push(T&& t)
148 {
149 using U = any_t<T>;
150 auto p = ::new(bump_down(
151 sizeof(U), alignof(U))) U(
152 std::forward<T>(t));
153 p->next = reinterpret_cast<
154 any*>(head_);
155 head_ = reinterpret_cast<
156 unsigned char*>(p);
157 return p->t_;
158 }
159
160 template<class T>
161 T*
162 push_array(
163 std::size_t n,
164 T const& t)
165 {
166 using U = any_n<T>;
167 auto p = ::new(bump_down(
168 sizeof(U) + n * sizeof(T),
169 alignof(::max_align_t))) U(n, t);
170 p->next = reinterpret_cast<
171 any*>(head_);
172 head_ = reinterpret_cast<
173 unsigned char*>(p);
174 return p->data();
175 }
176
177 private:
178 // https://fitzgeraldnick.com/2019/11/01/always-bump-downwards.html
179 void*
180 bump_down(
181 std::size_t size,
182 std::size_t align)
183 {
184 BOOST_ASSERT(align > 0);
185 BOOST_ASSERT(
186 (align & (align - 1)) == 0);
187
188 auto ip0 = reinterpret_cast<
189 std::uintptr_t>(begin_);
190 auto ip = reinterpret_cast<
191 std::uintptr_t>(head_);
192 if(size > ip - ip0)
193 detail::throw_bad_alloc();
194 ip -= size;
195 ip &= ~(align - 1);
196 if(ip < ip0)
197 detail::throw_bad_alloc();
198 return reinterpret_cast<void*>(ip);
199 }
200 };
201
202 } // detail
203 } // http_proto
204 } // boost
205
206 #endif
207