HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
placement.hpp
1// Copyright Take Vos 2019, 2021-2022.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "utility/module.hpp"
8#include <span>
9
10hi_warning_push();
11// C26492: Don't use const_cast to cast away const or volatile (type.3).
12// placement new requires non-const pointer, even if the non-constructor initializer doesn't
13// modify the memory.
14hi_warning_ignore_msvc(26492);
15// We are going to remove placement.hpp anyway.
16hi_warning_ignore_msvc(26403);
17hi_warning_ignore_msvc(26460);
18
19namespace hi::inline v1 {
20template<typename T>
21inline bool check_alignment(void const *ptr) noexcept
22{
23 return std::bit_cast<uintptr_t>(ptr) % alignof(T) == 0;
24}
25
26template<typename T>
28public:
29 static_assert(std::is_trivially_default_constructible_v<T>);
30 static_assert(std::is_trivially_destructible_v<T>);
31
32 using value_type = T;
33
34 template<byte_like Byte>
35 placement_ptr(std::span<Byte> bytes, std::size_t& offset)
36 {
37 if (offset + sizeof(value_type) > bytes.size()) {
38 throw std::bad_alloc();
39 }
40
41 auto ptr = bytes.data() + offset;
42 offset += sizeof(value_type);
43 std::uninitialized_default_construct_n(reinterpret_cast<value_type *>(ptr), 1);
44 _ptr = std::launder(reinterpret_cast<value_type *>(ptr));
45 }
46
48 {
49 std::destroy_at(_ptr);
50 }
51
52 placement_ptr() = delete;
53 placement_ptr(placement_ptr const&) = delete;
54 placement_ptr(placement_ptr&&) = delete;
55 placement_ptr& operator=(placement_ptr const&) = delete;
56 placement_ptr& operator=(placement_ptr&&) = delete;
57
58 value_type *operator->() const noexcept
59 {
60 return _ptr;
61 }
62
63 value_type& operator*() const noexcept
64 {
65 return *_ptr;
66 }
67
68private:
69 value_type *_ptr;
70};
71
72template<typename T, typename Byte>
73[[nodiscard]] auto make_placement_ptr(std::span<Byte> bytes, std::size_t& offset)
74{
75 return placement_ptr<copy_cv_t<T, Byte>>(bytes, offset);
76}
77
78template<typename T, typename Byte>
79[[nodiscard]] auto make_placement_ptr(std::span<Byte> bytes, std::size_t&& offset = 0)
80{
81 std::size_t _offset = offset;
82 return make_placement_ptr<T>(bytes, _offset);
83}
84
85template<typename T>
87public:
88 static_assert(std::is_trivially_default_constructible_v<T>);
89 static_assert(std::is_trivially_destructible_v<T>);
90
91 using value_type = T;
92 using container_type = std::span<value_type>;
93 using iterator = container_type::iterator;
94 using reference = container_type::reference;
95 using pointer = container_type::pointer;
96
97 template<byte_like Byte>
98 placement_array(std::span<Byte> bytes, std::size_t& offset, std::size_t n)
99 {
100 if (offset + n * sizeof(T) > bytes.size()) {
101 throw std::bad_alloc();
102 }
103
104 hilet ptr = bytes.data() + offset;
105 offset += sizeof(T) * n;
106
107 std::uninitialized_default_construct_n(reinterpret_cast<value_type *>(ptr), n);
108 _items = {std::launder(reinterpret_cast<value_type *>(ptr)), n};
109 }
110
111 placement_array(placement_array const&) = delete;
113 placement_array& operator=(placement_array const&) = delete;
114 placement_array& operator=(placement_array&&) = delete;
115
117 {
118 std::destroy(begin(), end());
119 }
120
121 operator std::span<value_type>() const noexcept
122 {
123 return _items;
124 }
125
126 std::size_t size() const noexcept
127 {
128 return std::distance(begin(), end());
129 }
130
131 iterator begin() const noexcept
132 {
133 return _items.begin();
134 }
135
136 iterator end() const noexcept
137 {
138 return _items.end();
139 }
140
141 reference operator[](ssize_t offset) const noexcept
142 {
143 return _items[offset];
144 }
145
146private:
147 std::span<value_type> _items;
148};
149
150template<typename T, byte_like Byte>
151[[nodiscard]] auto make_placement_array(std::span<Byte> bytes, std::size_t& offset, std::size_t n)
152{
153 return placement_array<copy_cv_t<T, Byte>>(bytes, offset, n);
154}
155
156template<typename T, byte_like Byte>
157[[nodiscard]] auto make_placement_array(std::span<Byte> bytes, std::size_t&& offset, std::size_t n)
158{
159 std::size_t _offset = offset;
160 return make_placement_array<T>(bytes, _offset, n);
161}
162
163template<typename T, byte_like Byte>
164[[nodiscard]] auto make_placement_array(std::span<Byte> bytes, std::size_t& offset)
165{
166 hilet n = bytes.size() / ssizeof(T);
167 return make_placement_array<T>(bytes, offset, n);
168}
169
170template<typename T, byte_like Byte>
171[[nodiscard]] auto make_placement_array(std::span<Byte> bytes, std::size_t&& offset = 0)
172{
173 std::size_t _offset = offset;
174 return make_placement_array<T>(bytes, _offset);
175}
176
177} // namespace hi::inline v1
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
DOXYGEN BUG.
Definition algorithm.hpp:13
Definition placement.hpp:27
Definition placement.hpp:86
Definition concepts.hpp:36
Definition concepts.hpp:39
T distance(T... args)