Line data Source code
1 : //* This file is part of the MOOSE framework
2 : //* https://mooseframework.inl.gov
3 : //*
4 : //* All rights reserved, see COPYRIGHT for full restrictions
5 : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 : //*
7 : //* Licensed under LGPL 2.1, please see LICENSE for details
8 : //* https://www.gnu.org/licenses/lgpl-2.1.html
9 :
10 : #pragma once
11 :
12 : #include "libmesh/elem.h"
13 : #include "libmesh/mesh_base.h"
14 :
15 : namespace RayTracingPackingUtils
16 : {
17 :
18 : /**
19 : * Like std::copy, but passes the input iterator by reference
20 : */
21 : template <class Cont, class InputIt>
22 : void unpackCopy(Cont & container, InputIt & input_iterator);
23 :
24 : /**
25 : * Packs the data in \p values into the iterator \p out and minimizes memory
26 : * storage in said iterator.
27 : *
28 : * In specific, ValueType is packed into BufferType at a byte level. That is,
29 : * if sizeof(ValueType) == 4 and sizeof(BufferType) == 8, two values of type ValueType
30 : * objects will be stored in a single value of type BufferType.
31 : */
32 : template <typename BufferType, typename BufferIter, typename ValueType>
33 : void reinterpretPackCopy(const std::vector<ValueType> & values, BufferIter & out);
34 :
35 : /**
36 : * Packs the data from \p in into the vector \p values.
37 : *
38 : * \p values MUST be resized ahead of time in order to know how much to advance \p in.
39 : *
40 : * This is to be used in the unpacking of values stored by reinterpretPackCopy().
41 : */
42 : template <typename BufferType, typename BufferIter, typename ValueType>
43 : void reinterpretUnpackCopy(std::vector<ValueType> & values, BufferIter & in);
44 :
45 : /**
46 : * Gets the minimum number of values of BufferType needed to represent
47 : * \p input_size values of ValueType
48 : *
49 : * To be used with sizing for reinterpretPackCopy() and reinterpretUnpackCopy().
50 : */
51 : template <typename ValueType, typename BufferType>
52 : std::size_t reinterpretCopySize(const std::size_t input_size);
53 :
54 : /**
55 : * Unpacks the mixed-values from \p in into \p values that were packed with mixedPack().
56 : */
57 : template <typename BufferType, typename BufferIter, typename... ValueTypes>
58 : void mixedUnpack(BufferIter & in, ValueTypes &... values);
59 :
60 : /**
61 : * Packs the mixed-type values in \p values into \p out to be unpacked with mixedUnpack().
62 : *
63 : * Uses as few entries in \p out needed to represent \p values in order.
64 : */
65 : template <typename BufferType, typename BufferIter, typename... ValueTypes>
66 : void mixedPack(BufferIter & out, ValueTypes const &... values);
67 :
68 : /**
69 : * Gets the number of BufferType required to store the expanded InputTypes for use with
70 : * mixedPack() and mixedUnpack().
71 : *
72 : * Can be stored as constexpr to evaluate the size at compile time only.
73 : */
74 : template <typename BufferType, typename... InputTypes>
75 : constexpr std::size_t mixedPackSize();
76 :
77 : /**
78 : * Packs \p value into a value of type BufferType at a byte level, to be unpacked with
79 : * the unpack() routines in this namespace.
80 : */
81 : template <typename BufferType, typename ValueType>
82 : BufferType pack(const ValueType value);
83 :
84 : /**
85 : * Unpacks \p value_as_buffer_type (which is packed with pack()) into \p value at a byte level.
86 : */
87 : template <typename BufferType, typename ValueType>
88 : void unpack(const BufferType value_as_buffer_type, ValueType & value);
89 :
90 : /**
91 : * Packs the ID of \p elem into a type of BufferType to be unpacked later into another const Elem *
92 : * with unpack().
93 : */
94 : template <typename BufferType>
95 : BufferType pack(const Elem * elem, MeshBase * mesh_base = nullptr);
96 :
97 : /**
98 : * Unpacks the const Elem * from \p id_as_buffer_type (packed using pack()) into \p elem.
99 : */
100 : template <typename BufferType>
101 : void unpack(const Elem *& elem, const BufferType id_as_buffer_type, MeshBase * mesh_base);
102 :
103 : namespace detail
104 : {
105 :
106 : /**
107 : * Helper for mixedPackSize().
108 : *
109 : * Called after evaluating the last InputType, and increases the size
110 : * if any offset remains
111 : */
112 : template <typename BufferType>
113 : constexpr std::size_t
114 : mixedPackSizeHelper(const std::size_t offset, const std::size_t size)
115 : {
116 : return offset ? size + 1 : size;
117 : }
118 :
119 : /**
120 : * Recursive helper for mixedPackSize().
121 : *
122 : * Recurses through the types (in InputType and rest), and increments the
123 : * offset and size as needed
124 : */
125 : template <typename BufferType, typename InputType, typename... Rest>
126 : constexpr std::size_t
127 : mixedPackSizeHelper(std::size_t offset, std::size_t size)
128 : {
129 : return offset + sizeof(InputType) > sizeof(BufferType)
130 : ? mixedPackSizeHelper<BufferType, Rest...>(sizeof(InputType), ++size)
131 : : mixedPackSizeHelper<BufferType, Rest...>(offset + sizeof(InputType), size);
132 : }
133 :
134 : /**
135 : * Helper for mixedUnpack()
136 : */
137 : template <typename BufferType, typename BufferIter, typename ValueType>
138 : void
139 6375870 : mixedUnpackHelper(BufferIter & in,
140 : const BufferType *& src,
141 : std::size_t & src_offset,
142 : ValueType & output)
143 : {
144 : static_assert(sizeof(ValueType) <= sizeof(BufferType), "ValueType will not fit into BufferType");
145 :
146 6375870 : if (src_offset + sizeof(ValueType) > sizeof(BufferType))
147 : {
148 2550348 : src = &(*in++);
149 2550348 : src_offset = 0;
150 : }
151 :
152 6375870 : std::memcpy(&output, (char *)src + src_offset, sizeof(ValueType));
153 6375870 : src_offset += sizeof(ValueType);
154 6375870 : }
155 :
156 : /**
157 : * Helper for mixedPack()
158 : */
159 : template <typename BufferIter, typename BufferType, typename ValueType>
160 : void
161 6375870 : mixedPackHelper(BufferIter & out,
162 : BufferType & dest,
163 : std::size_t & dest_offset,
164 : const ValueType & input)
165 : {
166 : static_assert(sizeof(ValueType) <= sizeof(BufferType), "ValueType will not fit into BufferType");
167 :
168 6375870 : if (dest_offset + sizeof(ValueType) > sizeof(BufferType))
169 : {
170 : out++ = dest;
171 1275174 : dest_offset = 0;
172 : }
173 :
174 6375870 : std::memcpy((char *)&dest + dest_offset, &input, sizeof(ValueType));
175 6375870 : dest_offset += sizeof(ValueType);
176 6375870 : }
177 : }
178 :
179 : template <class Cont, class InputIt>
180 : void
181 : unpackCopy(Cont & container, InputIt & input_iterator)
182 : {
183 : auto first = container.begin();
184 1631284 : while (first != container.end())
185 356110 : *first++ = *input_iterator++;
186 : }
187 :
188 : template <typename BufferType, typename BufferIter, typename ValueType>
189 : void
190 : reinterpretPackCopy(const std::vector<ValueType> & values, BufferIter & out)
191 : {
192 : static_assert(sizeof(ValueType) <= sizeof(BufferType), "ValueType will not fit into BufferType");
193 :
194 : BufferType dest;
195 : const ValueType * src = values.data();
196 :
197 : std::size_t dest_offset = 0;
198 : for (std::size_t i = 0; i < values.size(); ++i)
199 : {
200 : if (dest_offset + sizeof(ValueType) > sizeof(BufferType))
201 : {
202 : out++ = dest;
203 : dest_offset = 0;
204 : }
205 :
206 : std::memcpy((char *)&dest + dest_offset, &src[i], sizeof(ValueType));
207 : dest_offset += sizeof(ValueType);
208 : }
209 :
210 : if (dest_offset)
211 : out++ = dest;
212 : }
213 :
214 : template <typename BufferType, typename BufferIter, typename ValueType>
215 : void
216 : reinterpretUnpackCopy(std::vector<ValueType> & values, BufferIter & in)
217 : {
218 : static_assert(sizeof(ValueType) <= sizeof(BufferType), "ValueType will not fit into BufferType");
219 :
220 : ValueType * dest = values.data();
221 : const BufferType * src = nullptr;
222 :
223 : std::size_t src_offset = sizeof(BufferType);
224 : for (std::size_t i = 0; i < values.size(); ++i)
225 : {
226 : if (src_offset + sizeof(ValueType) > sizeof(BufferType))
227 : {
228 : src = &(*in++);
229 : src_offset = 0;
230 : }
231 :
232 : std::memcpy(&dest[i], (char *)src + src_offset, sizeof(ValueType));
233 : src_offset += sizeof(ValueType);
234 : }
235 : }
236 :
237 : template <typename ValueType, typename BufferType>
238 : std::size_t
239 : reinterpretCopySize(const std::size_t input_size)
240 : {
241 : const double input_per_output = std::floor(sizeof(BufferType) / sizeof(ValueType));
242 : return (std::size_t)std::ceil((double)input_size / input_per_output);
243 : }
244 :
245 : template <typename BufferType, typename BufferIter, typename... ValueTypes>
246 : void
247 1275174 : mixedUnpack(BufferIter & in, ValueTypes &... values)
248 : {
249 1275174 : std::size_t src_offset = sizeof(BufferType);
250 1275174 : const BufferType * src = nullptr;
251 :
252 : int expander[] = {
253 : 0,
254 1275174 : ((void)detail::mixedUnpackHelper(in, src, src_offset, std::forward<ValueTypes &>(values)),
255 : 0)...};
256 : (void)expander;
257 1275174 : }
258 :
259 : template <typename BufferType, typename BufferIter, typename... ValueTypes>
260 : void
261 1275174 : mixedPack(BufferIter & out, ValueTypes const &... values)
262 : {
263 1275174 : std::size_t dest_offset = 0;
264 : BufferType dest;
265 :
266 : int expander[] = {0,
267 1275174 : ((void)detail::mixedPackHelper(
268 : out, dest, dest_offset, std::forward<ValueTypes const &>(values)),
269 : 0)...};
270 : (void)expander;
271 :
272 1275174 : if (dest_offset)
273 : out++ = dest;
274 1275174 : }
275 :
276 : template <typename BufferType, typename... InputTypes>
277 : constexpr std::size_t
278 : mixedPackSize()
279 : {
280 : // Call the recursive helper with an initial offset and size of 0
281 : return detail::mixedPackSizeHelper<BufferType, InputTypes...>(/* offset = */ 0, /* size = */ 0);
282 : }
283 :
284 : template <typename BufferType, typename ValueType>
285 : BufferType
286 : pack(const ValueType value)
287 : {
288 : static_assert(sizeof(ValueType) <= sizeof(BufferType), "Value will won't fit into buffer type");
289 :
290 : BufferType value_as_buffer_type;
291 : std::memcpy(&value_as_buffer_type, &value, sizeof(ValueType));
292 : return value_as_buffer_type;
293 : }
294 :
295 : template <typename BufferType, typename ValueType>
296 : void
297 : unpack(const BufferType value_as_buffer_type, ValueType & value)
298 : {
299 : static_assert(sizeof(ValueType) <= sizeof(BufferType), "Value will won't fit into buffer type");
300 1275174 : std::memcpy(&value, &value_as_buffer_type, sizeof(ValueType));
301 : }
302 :
303 : template <typename BufferType>
304 : BufferType
305 : pack(const Elem * elem, MeshBase * libmesh_dbg_var(mesh_base /* = nullptr */))
306 : {
307 1275174 : const dof_id_type id = elem ? elem->id() : libMesh::DofObject::invalid_id;
308 : mooseAssert(mesh_base ? mesh_base->query_elem_ptr(id) == elem : true,
309 : "Elem doesn't exist in mesh");
310 :
311 : return pack<BufferType>(id);
312 : }
313 :
314 : template <typename BufferType>
315 : void
316 : unpack(const Elem *& elem, const BufferType id_as_buffer_type, MeshBase * mesh_base)
317 : {
318 : dof_id_type id;
319 : unpack<BufferType>(id_as_buffer_type, id);
320 :
321 1275174 : elem = (id == libMesh::DofObject::invalid_id ? nullptr : mesh_base->query_elem_ptr(id));
322 : }
323 : }
|