proxsuite 0.6.7
The Advanced Proximal Optimization Toolbox
Loading...
Searching...
No Matches
dynamic_stack.hpp
Go to the documentation of this file.
1#ifndef VEG_DYNAMIC_STACK_DYNAMIC_STACK_HPP_UBOMZFTOS
2#define VEG_DYNAMIC_STACK_DYNAMIC_STACK_HPP_UBOMZFTOS
3
4#include "proxsuite/fwd.hpp"
15
16namespace proxsuite {
17namespace linalg {
18namespace veg {
19namespace _detail {
20namespace _dynstack {
21constexpr auto
22max2(isize a, isize b) noexcept -> isize
23{
24 return (a > b) ? a : b;
25}
26constexpr auto
27round_up_pow2(isize a, isize b) noexcept -> isize
28{
29 return isize((usize(a) + ~(0 - usize(b))) & (0 - usize(b)));
30}
31} // namespace _dynstack
32} // namespace _detail
33namespace dynstack {
35{
38
39 constexpr friend auto operator==(StackReq a, StackReq b) noexcept -> bool
40 {
41 return a.size_bytes == b.size_bytes && a.align == b.align;
42 }
43
44 constexpr friend auto operator&(StackReq a, StackReq b) noexcept -> StackReq
45 {
46 using namespace _detail::_dynstack;
47 return {
48 round_up_pow2( //
49 round_up_pow2( //
50 a.size_bytes,
51 b.align) +
52 b.size_bytes,
53 (max2)(a.align, b.align)),
54 (max2)(a.align, b.align),
55 };
56 }
57 constexpr friend auto operator|(StackReq a, StackReq b) noexcept -> StackReq
58 {
59 using namespace _detail::_dynstack;
60 return {
61 (max2)( //
62 round_up_pow2(a.size_bytes, max2(a.align, b.align)),
63 round_up_pow2(b.size_bytes, max2(a.align, b.align))),
64 (max2)(a.align, b.align),
65 };
66 }
67
68 constexpr auto alloc_req() const noexcept -> isize
69 {
70 return size_bytes + align - 1;
71 }
72
73 template<typename T>
74 static constexpr auto with_len(proxsuite::linalg::veg::Tag<T> /*tag*/,
75 isize len) noexcept -> StackReq
76 {
77 return {
78 isize{ sizeof(T) } * len,
79 isize{ alignof(T) },
80 };
81 }
82
84 -> StackReq
85 {
86 StackReq req{ 0, 1 };
87 for (isize i = 0; i < reqs.len(); ++i) {
88 req = req & reqs.ptr()[i];
89 }
90 return req;
91 }
92
94 -> StackReq
95 {
96 StackReq req{ 0, 1 };
97 for (isize i = 0; i < reqs.len(); ++i) {
98 req = req | reqs.ptr()[i];
99 }
100 return req;
101 }
102};
103
104template<typename T>
105struct DynStackArray;
106template<typename T>
107struct DynStackAlloc;
108} // namespace dynstack
109
110namespace _detail {
111// if possible:
112// aligns the pointer
113// then advances it by `size` bytes, and decreases `space` by `size`
114// returns the previous aligned value
115//
116// otherwise, if there is not enough space for aligning or advancing the
117// pointer, returns nullptr and the values are left unmodified
118inline auto
119align_next(isize alignment, isize size, void*& ptr, isize& space)
120 VEG_ALWAYS_NOEXCEPT -> void*
121{
122 static_assert(sizeof(std::uintptr_t) >= sizeof(void*),
123 "std::uintptr_t can't hold a pointer value");
124
125 using byte_ptr = unsigned char*;
126
127 // assert alignment is power of two
129 (alignment > isize{ 0 }),
130 ((u64(alignment) & (u64(alignment) - 1)) == u64(0)));
131
132 if (space < size) {
133 return nullptr;
134 }
135
136 std::uintptr_t lo_mask = usize(alignment) - 1;
137 std::uintptr_t hi_mask = ~lo_mask;
138
139 auto const intptr = reinterpret_cast<std::uintptr_t>(ptr);
140 auto* const byteptr = static_cast<byte_ptr>(ptr);
141
142 auto offset = ((intptr + usize(alignment) - 1) & hi_mask) - intptr;
143
144 if (usize(space) - usize(size) < offset) {
145 return nullptr;
146 }
147
148 void* const rv = byteptr + offset;
149
150 ptr = byteptr + (offset + usize(size));
151 space = space - (isize(offset) + (size));
152
153 return rv;
154}
155} // namespace _detail
156
157namespace _detail {
158namespace _dynstack {
159template<typename T, bool = VEG_CONCEPT(trivially_destructible<T>)>
161{};
162
163template<typename T>
183
184struct cleanup;
185struct DynAllocBase;
186
188{
189 template<typename T>
190 auto make(void* ptr, isize len) -> T*
191 {
192 return ::new (ptr) T[usize(len)];
193 }
194};
195
197{
198 template<typename T>
199 auto make(void* ptr, isize len) -> T*
200 {
201 return ::new (ptr) T[usize(len)]{};
202 }
203};
204
206{
207 template<typename T>
208 auto make(void* ptr, isize len) -> T*
209 {
210 return proxsuite::linalg::veg::mem::launder(static_cast<T*>(
211 static_cast<void*>(::new (ptr) unsigned char[usize(len) * sizeof(T)])));
212 }
213};
214
215} // namespace _dynstack
216} // namespace _detail
217
218namespace dynstack {
220{
221public:
223 : stack_data(s.ptr_mut())
224 , stack_bytes(s.len())
225 {
226 }
227
230 {
231 return isize(stack_bytes);
232 }
234 auto ptr_mut() const VEG_NOEXCEPT -> void* { return stack_data; }
236 auto ptr() const VEG_NOEXCEPT -> void const* { return stack_data; }
237
238private:
239 VEG_INLINE void assert_valid_len(PROXSUITE_MAYBE_UNUSED isize len)
241 {
243 }
244
245public:
246 VEG_TEMPLATE((typename T),
249 (/*unused*/, Tag<T>),
250 (len, isize),
251 (align = alignof(T), isize))
253 {
254 assert_valid_len(len);
256 *this, isize(len), align, _detail::_dynstack::zero_init_fn{}
257 };
258 VEG_ASSERT(get.ptr() != nullptr);
259 return VEG_FWD(get);
260 }
261
262 VEG_TEMPLATE((typename T),
265 (/*unused*/, Tag<T>),
266 (len, isize),
267 (align = alignof(T), isize))
268
270 {
271 assert_valid_len(len);
273 *this, isize(len), align, _detail::_dynstack::default_init_fn{}
274 };
275 VEG_ASSERT(get.ptr() != nullptr);
276 return VEG_FWD(get);
277 }
278
279 template<typename T>
281 isize len,
282 isize align = alignof(T))
284 {
285 assert_valid_len(len);
287 *this, isize(len), align, _detail::_dynstack::no_init_fn{}
288 };
289 VEG_ASSERT(get.ptr() != nullptr);
290 return VEG_FWD(get);
291 }
292
293private:
294 void* stack_data;
295 isize stack_bytes;
296
297 template<typename T>
298 friend struct DynStackAlloc;
299 template<typename T>
300 friend struct DynStackArray;
303};
304} // namespace dynstack
305
306namespace _detail {
307namespace _dynstack {
308
310{
311 bool const& success;
313 void* old_data;
315
317 {
318 if (!success) {
319 parent.stack_data = old_data;
320 parent.stack_bytes = old_rem_bytes;
321 }
322 }
323};
324
326{
328 void* old_pos;
329 void const volatile* data;
331
332 void destroy(void const volatile* void_data_end) VEG_NOEXCEPT
333 {
334 if (data != nullptr) {
335 // in case resource lifetimes are reodered by moving ownership
337 static_cast<unsigned char*>(parent->stack_data);
339 static_cast<unsigned char*>(old_pos);
341 static_cast<unsigned char*>(const_cast<void*>(void_data_end));
342
346
347 parent->stack_bytes +=
348 static_cast<isize>(static_cast<unsigned char*>(parent->stack_data) -
349 static_cast<unsigned char*>(old_pos));
350 parent->stack_data = old_pos;
351 }
352 }
353};
354} // namespace _dynstack
355} // namespace _detail
356
357namespace dynstack {
358template<typename T>
360{
361private:
363
364public:
369
370 DynStackAlloc(DynStackAlloc const&) = delete;
372 {
373 other.Base::len = 0;
374 other.Base::data = nullptr;
375 };
376
377 auto operator=(DynStackAlloc const&) -> DynStackAlloc& = delete;
378 auto operator=(DynStackAlloc&& rhs) VEG_NOEXCEPT->DynStackAlloc&
379 {
380 {
381 auto cleanup = static_cast<decltype(rhs)>(*this);
382 }
383 static_cast<Base&>(*this) = rhs;
384 static_cast<Base&>(rhs) = {};
385 return *this;
386 }
387
389 {
390 return {
391 unsafe,
392 FromRawParts{},
393 ptr_mut(),
394 len(),
395 };
396 }
397
399 {
400 return {
401 unsafe,
402 FromRawParts{},
403 ptr(),
404 len(),
405 };
406 }
407
409 {
410 return /* NOLINT(clang-analyzer-linalg.uninitialized.UndefReturn) */
411 static_cast<T*>(const_cast<void*>(Base::data));
412 }
414 {
415 return /* NOLINT(clang-analyzer-linalg.uninitialized.UndefReturn) */
416 static_cast<T const*>(const_cast<void const*>(Base::data));
417 }
419 {
420 return isize(Base::len);
421 }
422
423private:
424 friend struct DynStackArray<T>;
425 friend struct DynStackMut;
427
428 template<typename Fn>
431 : Base{
432 &parent_ref,
433 parent_ref.stack_data,
434 nullptr,
435 0,
436 }
437 {
438
439 void* const parent_data = parent_ref.stack_data;
440 isize const parent_bytes = parent_ref.stack_bytes;
441
442 void* const ptr = _detail::align_next(align,
443 alloc_size * isize(sizeof(T)),
444 parent_ref.stack_data,
445 parent_ref.stack_bytes);
446
447 if (ptr != nullptr) {
448 bool success = false;
449 auto&& cleanup = defer(_detail::_dynstack::cleanup{
450 success, *parent, parent_data, parent_bytes });
451 (void)cleanup;
452
454 Base::data = fn.template make<T>(ptr, alloc_size);
455
456 success = true;
457 }
458 }
459};
460
461template<typename T>
463 : private // destruction order matters
466{
467private:
469
470public:
471 using DynStackAlloc<T>::as_ref;
472 using DynStackAlloc<T>::as_mut;
473 using DynStackAlloc<T>::ptr;
474 using DynStackAlloc<T>::ptr_mut;
475 using DynStackAlloc<T>::len;
476
477 ~DynStackArray() = default;
478 DynStackArray(DynStackArray const&) = delete;
481
483 {
484 {
485 auto cleanup = static_cast<decltype(rhs)>(*this);
486 }
487 static_cast<Base&>(*this) = rhs;
488 static_cast<Base&>(rhs) = {};
489 return *this;
490 }
491
492private:
494 friend struct DynStackMut;
496};
497} // namespace dynstack
498} // namespace veg
499} // namespace linalg
500} // namespace proxsuite
501
503#endif /* end of include guard VEG_DYNAMIC_STACK_DYNAMIC_STACK_HPP_UBOMZFTOS \
504 */
#define VEG_ASSERT_ALL_OF(...)
#define VEG_ASSERT(...)
#define PROXSUITE_MAYBE_UNUSED
Definition fwd.hpp:20
#define VEG_CONCEPT(...)
Definition macros.hpp:1243
#define VEG_INLINE
Definition macros.hpp:118
#define VEG_FWD(X)
Definition macros.hpp:569
void backward_destroy(RefMut< A > alloc, RefMut< C > cloner, T *ptr, T *ptr_end)
constexpr auto round_up_pow2(isize a, isize b) noexcept -> isize
constexpr auto max2(isize a, isize b) noexcept -> isize
auto align_next(isize alignment, isize size, void *&ptr, isize &space) VEG_ALWAYS_NOEXCEPT -> void *
std::uint64_t u64
Definition typedefs.hpp:46
_detail::_meta::make_signed< usize >::Type isize
Definition typedefs.hpp:43
decltype(sizeof(0)) usize
Definition macros.hpp:702
#define VEG_NODISCARD
Definition prologue.hpp:97
#define VEG_NOEXCEPT
Definition prologue.hpp:30
#define VEG_ALWAYS_NOEXCEPT
Definition prologue.hpp:22
#define VEG_INTERNAL_ASSERT_PRECONDITIONS
Definition prologue.hpp:101
#define VEG_NOEXCEPT_IF(...)
Definition prologue.hpp:31
proxsuite::linalg::veg::dynstack::DynStackMut * parent
void destroy(void const volatile *void_data_end) VEG_NOEXCEPT
auto operator=(DynStackArrayDtor const &) -> DynStackArrayDtor &=default
auto operator=(DynStackArrayDtor &&) -> DynStackArrayDtor &=default
proxsuite::linalg::veg::dynstack::DynStackMut & parent
VEG_INLINE void operator()() const VEG_NOEXCEPT
VEG_NODISCARD auto as_mut() VEG_NOEXCEPT -> SliceMut< T >
DynStackAlloc(DynStackAlloc const &)=delete
VEG_NODISCARD auto ptr_mut() VEG_NOEXCEPT -> T *
auto operator=(DynStackAlloc const &) -> DynStackAlloc &=delete
DynStackAlloc(DynStackAlloc &&other) VEG_NOEXCEPT
auto operator=(DynStackAlloc &&rhs) VEG_NOEXCEPT -> DynStackAlloc &
VEG_NODISCARD auto as_ref() const VEG_NOEXCEPT -> Slice< T >
VEG_NODISCARD auto ptr() const VEG_NOEXCEPT -> T const *
VEG_NODISCARD auto len() const VEG_NOEXCEPT -> isize
DynStackArray(DynStackArray const &)=delete
DynStackArray(DynStackArray &&) VEG_NOEXCEPT=default
VEG_TEMPLATE((typename T), requires VEG_CONCEPT(constructible< T >), VEG_NODISCARD auto make_new_for_overwrite,(, Tag< T >),(len, isize),(align=alignof(T), isize)) VEG_NOEXCEPT_IF(VEG_CONCEPT(nothrow_constructible< T >)) -> DynStackArray< T >
VEG_NODISCARD auto ptr() const VEG_NOEXCEPT -> void const *
VEG_TEMPLATE((typename T), requires VEG_CONCEPT(constructible< T >), VEG_NODISCARD auto make_new,(, Tag< T >),(len, isize),(align=alignof(T), isize)) VEG_NOEXCEPT_IF(VEG_CONCEPT(nothrow_constructible< T >)) -> DynStackArray< T >
VEG_NODISCARD auto ptr_mut() const VEG_NOEXCEPT -> void *
VEG_NODISCARD auto make_alloc(Tag< T >, isize len, isize align=alignof(T)) VEG_NOEXCEPT -> DynStackAlloc< T >
DynStackMut(FromSliceMut, SliceMut< unsigned char > s) VEG_NOEXCEPT
VEG_NODISCARD auto remaining_bytes() const VEG_NOEXCEPT -> isize
constexpr friend auto operator&(StackReq a, StackReq b) noexcept -> StackReq
static VEG_CPP14(constexpr) auto and_(Slice< StackReq > reqs) noexcept -> StackReq
static constexpr auto with_len(proxsuite::linalg::veg::Tag< T >, isize len) noexcept -> StackReq
constexpr friend auto operator|(StackReq a, StackReq b) noexcept -> StackReq
constexpr auto alloc_req() const noexcept -> isize
constexpr friend auto operator==(StackReq a, StackReq b) noexcept -> bool
static VEG_CPP14(constexpr) auto or_(Slice< StackReq > reqs) noexcept -> StackReq