HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
placement.hpp
1// Copyright Take Vos 2019-2020.
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 "required.hpp"
8#include "type_traits.hpp"
9#include "cast.hpp"
10#include "exception.hpp"
11#include "check.hpp"
12#include <span>
13
14namespace hi::inline v1 {
15
16template<typename T>
17inline bool check_alignment(void const *ptr)
18{
19 return reinterpret_cast<ptrdiff_t>(ptr) % alignof(T) == 0;
20}
21
22template<typename T, typename Byte>
24 static_assert(
25 std::is_same_v<std::remove_cv_t<Byte>, std::byte> || std::is_same_v<std::remove_cv_t<Byte>, char> ||
26 std::is_same_v<std::remove_cv_t<Byte>, unsigned char> || std::is_same_v<std::remove_cv_t<Byte>, signed char>,
27 "Byte must be a byte type");
28 static_assert(std::is_trivially_constructible_v<T>);
29 static_assert(!std::is_const_v<Byte> || std::is_trivially_destructible_v<T>);
30
31 using value_type = copy_cv_t<T, Byte>;
32 value_type *ptr;
33
34public:
35 placement_ptr(std::span<Byte> bytes, std::size_t &offset)
36 {
37 Byte *_ptr = bytes.data() + offset;
38 offset += sizeof(T);
39 ptr = new (const_cast<std::remove_cv_t<Byte> *>(_ptr)) T;
40 }
41
43 {
44 std::destroy_at(ptr);
45 }
46
47 value_type *operator->() const noexcept
48 {
49 return ptr;
50 }
51
52 value_type &operator*() const noexcept
53 {
54 return *ptr;
55 }
56};
57
58template<typename T, typename Byte>
59placement_ptr<T, Byte> unsafe_make_placement_ptr(std::span<Byte> bytes, std::size_t &offset)
60{
61 return placement_ptr<T, Byte>(bytes, offset);
62}
63
64template<typename T, typename Byte>
65placement_ptr<T, Byte> unsafe_make_placement_ptr(std::span<Byte> bytes, std::size_t &&offset = 0)
66{
67 std::size_t _offset = offset;
68 return unsafe_make_placement_ptr<T>(bytes, _offset);
69}
70
71template<typename T, typename Byte>
72bool check_placement_ptr(std::span<Byte> bytes, std::size_t offset = 0)
73{
74 return check_alignment<T>(bytes.data()) && (offset + sizeof(T) <= size(bytes));
75}
76
77template<typename T, typename Byte>
78placement_ptr<T, Byte> make_placement_ptr(std::span<Byte> bytes, std::size_t &offset)
79{
80 hi_parse_check(check_placement_ptr<T>(bytes, offset), "Parsing beyond end of buffer");
81 return placement_ptr<T, Byte>(bytes, offset);
82}
83
84template<typename T, typename Byte>
85placement_ptr<T, Byte> make_placement_ptr(std::span<Byte> bytes, std::size_t &&offset = 0)
86{
87 std::size_t _offset = offset;
88 return make_placement_ptr<T>(bytes, _offset);
89}
90
91template<typename T, typename Byte>
93 static_assert(
94 std::is_same_v<std::remove_cv_t<Byte>, std::byte> || std::is_same_v<std::remove_cv_t<Byte>, char> ||
95 std::is_same_v<std::remove_cv_t<Byte>, unsigned char> || std::is_same_v<std::remove_cv_t<Byte>, signed char>,
96 "Byte must be a byte type");
97 static_assert(std::is_trivially_constructible_v<T>);
98 static_assert(!std::is_const_v<T> || std::is_trivially_destructible_v<T>);
99
100 using value_type = copy_cv_t<T, Byte>;
101
102 Byte *_begin;
103 Byte *_end;
104
105public:
106 placement_array(std::span<Byte> bytes, std::size_t &offset, std::size_t n)
107 {
108 hilet bytes_ = bytes.data();
109
110 _begin = bytes_ + offset;
111 offset += sizeof(T) * n;
112 _end = bytes_ + offset;
113
114 for (auto i = 0_uz; i < n; i++) {
115 [[maybe_unused]] auto *ptr = new (const_cast<std::remove_cv_t<Byte> *>(_begin + i * sizeof(T))) T;
116 }
117 }
118
119 placement_array(placement_array const &) = delete;
120 placement_array(placement_array &&) = delete;
121 placement_array &operator=(placement_array const &) = delete;
122 placement_array &operator=(placement_array &&) = delete;
123
125 {
126 std::destroy(begin(), end());
127 }
128
129 std::size_t size() const noexcept
130 {
131 return std::distance(begin(), end());
132 }
133
134 bool contains(std::size_t index) const noexcept
135 {
136 return index < size();
137 }
138
139 value_type *begin() const noexcept
140 {
141 return std::launder(reinterpret_cast<value_type *>(_begin));
142 }
143
144 value_type *end() const noexcept
145 {
146 return std::launder(reinterpret_cast<value_type *>(_end));
147 }
148
149 value_type &operator[](ssize_t offset) const noexcept
150 {
151 return *(begin() + offset);
152 }
153};
154
155template<typename T, typename Byte>
156placement_array<T, Byte> unsafe_make_placement_array(std::span<Byte> bytes, std::size_t &offset, std::size_t n)
157{
158 return placement_array<T, Byte>(bytes, offset, n);
159}
160
161template<typename T, typename Byte>
162placement_array<T, Byte> unsafe_make_placement_array(std::span<Byte> bytes, std::size_t &&offset, std::size_t n)
163{
164 std::size_t _offset = offset;
165 return unsafe_make_placement_array<T>(bytes, _offset, n);
166}
167
168template<typename T, typename Byte>
169placement_array<T, Byte> unsafe_make_placement_array(std::span<Byte> bytes, std::size_t &offset)
170{
171 hilet n = bytes.size() / sizeof(T);
172 return unsafe_make_placement_array<T>(bytes, offset, n);
173}
174
175template<typename T, typename Byte>
176placement_array<T, Byte> unsafe_make_placement_array(std::span<Byte> bytes, std::size_t &&offset = 0)
177{
178 std::size_t _offset = offset;
179 return unsafe_make_placement_array<T>(bytes, _offset);
180}
181
182template<typename T, typename Byte>
183bool check_placement_array(std::span<Byte> bytes, std::size_t offset, std::size_t n)
184{
185 return check_alignment<T>(bytes.data()) && (offset + (n * sizeof(T)) <= bytes.size());
186}
187
188template<typename T, typename Byte>
189bool check_placement_array(std::span<Byte> bytes, std::size_t offset)
190{
191 return check_alignment<T>(bytes.data());
192}
193
194template<typename T, typename Byte>
195placement_array<T, Byte> make_placement_array(std::span<Byte> bytes, std::size_t &offset, std::size_t n)
196{
197 hi_parse_check(check_placement_array<T>(bytes, offset, n), "Parsing beyond end of buffer");
198 return placement_array<T, Byte>(bytes, offset, n);
199}
200
201template<typename T, typename Byte>
202placement_array<T, Byte> make_placement_array(std::span<Byte> bytes, std::size_t &&offset, std::size_t n)
203{
204 std::size_t _offset = offset;
205 return make_placement_array<T>(bytes, _offset, n);
206}
207
208template<typename T, typename Byte>
209placement_array<T, Byte> make_placement_array(std::span<Byte> bytes, std::size_t &offset)
210{
211 hilet n = bytes.size() / ssizeof(T);
212 return make_placement_array<T>(bytes, offset, n);
213}
214
215template<typename T, typename Byte>
216placement_array<T, Byte> make_placement_array(std::span<Byte> bytes, std::size_t &&offset = 0)
217{
218 std::size_t _offset = offset;
219 return make_placement_array<T>(bytes, _offset);
220}
221
222} // namespace hi::inline v1
typename copy_cv< To, From >::type copy_cv_t
Type-trait to copy const volatile qualifiers from one type to another.
Definition type_traits.hpp:269
This file includes required definitions.
#define hilet
Invariant should be the default for variables.
Definition required.hpp:23
Definition placement.hpp:23
Definition placement.hpp:92
T distance(T... args)