20#ifndef PLYWOOT_PARSER_HPP
21#define PLYWOOT_PARSER_HPP
33namespace plywoot::detail {
52template<
typename FormatParserPolicy>
53class Parser :
private FormatParserPolicy
56 template<
typename... Ts>
57 struct MaybeMemcpyable
59 static constexpr bool value = !std::is_same<FormatParserPolicy, AsciiParserPolicy>::value &&
60 detail::isPacked<Ts...>() && detail::isTriviallyCopyable<Ts...>();
64 using FormatParserPolicy::FormatParserPolicy;
76 PlyElementData read(
const PlyElement &element)
const
78 PlyElementData result(element);
80 std::uint8_t *dest = result.data();
81 for (std::size_t i = 0; i < element.size(); ++i)
83 for (
const PlyProperty &property : element.properties())
87 if (property.isList())
89 switch (property.type())
91 case PlyDataType::Char:
92 dest = readProperty(dest, property, reflect::Type<std::vector<char>>{});
94 case PlyDataType::UChar:
95 dest = readProperty(dest, property, reflect::Type<std::vector<unsigned char>>{});
97 case PlyDataType::Short:
98 dest = readProperty(dest, property, reflect::Type<std::vector<short>>{});
100 case PlyDataType::UShort:
101 dest = readProperty(dest, property, reflect::Type<std::vector<unsigned short>>{});
103 case PlyDataType::Int:
104 dest = readProperty(dest, property, reflect::Type<std::vector<int>>{});
106 case PlyDataType::UInt:
107 dest = readProperty(dest, property, reflect::Type<std::vector<unsigned int>>{});
109 case PlyDataType::Float:
110 dest = readProperty(dest, property, reflect::Type<std::vector<float>>{});
112 case PlyDataType::Double:
113 dest = readProperty(dest, property, reflect::Type<std::vector<double>>{});
119 switch (property.type())
121 case PlyDataType::Char:
122 dest = readProperty(dest, property, reflect::Type<char>{});
124 case PlyDataType::UChar:
125 dest = readProperty(dest, property, reflect::Type<unsigned char>{});
127 case PlyDataType::Short:
128 dest = readProperty(dest, property, reflect::Type<short>{});
130 case PlyDataType::UShort:
131 dest = readProperty(dest, property, reflect::Type<unsigned short>{});
133 case PlyDataType::Int:
134 dest = readProperty(dest, property, reflect::Type<int>{});
136 case PlyDataType::UInt:
137 dest = readProperty(dest, property, reflect::Type<unsigned int>{});
139 case PlyDataType::Float:
140 dest = readProperty(dest, property, reflect::Type<float>{});
142 case PlyDataType::Double:
143 dest = readProperty(dest, property, reflect::Type<double>{});
149 dest = detail::align(dest, result.alignment());
169 template<
typename... Ts>
170 void read(
const PlyElement &element, std::uint8_t *dest, std::size_t alignment)
const
172 if constexpr (MaybeMemcpyable<Ts...>::value)
174 if (detail::isMemcpyable<Ts...>(element.properties().begin(), element.properties().end()))
176 this->
template memcpy<Ts...>(dest, element);
181 readElements<Ts...>(element, dest, alignment);
184 void skip(
const PlyElement &element)
const { this->skipElement(element); }
187 template<
typename... Ts>
188 void readElements(
const PlyElement &element, std::uint8_t *dest, std::size_t alignment)
const
194 if (firstToSkip < last)
199 if (std::any_of(firstToSkip, last, [](
const PlyProperty &p) {
return p.isList(); }))
201 for (std::size_t i{0}; i < element.size(); ++i)
203 dest = detail::align(readElement<Ts...>(dest, first, last), alignment);
205 auto curr = firstToSkip;
206 while (curr < last) this->skipProperty(*curr++);
215 const std::size_t numBytesToSkip =
216 std::accumulate(firstToSkip, last, 0ul, [](std::size_t acc,
const PlyProperty &p) {
217 return acc +
sizeOf(p.isList() ? p.sizeType() : p.type());
220 for (std::size_t i{0}; i < element.size(); ++i)
222 dest = detail::align(readElement<Ts...>(dest, first, last), alignment);
223 this->skipProperties(numBytesToSkip);
229 for (std::size_t i{0}; i < element.size(); ++i)
231 dest = detail::align(readElement<Ts...>(dest, first, last), alignment);
237 std::uint8_t *readElement(std::uint8_t *dest, PlyPropertyConstIterator first, PlyPropertyConstIterator last)
240 return first < last ? readProperty(dest, *first, reflect::Type<T>{})
241 : static_cast<std::uint8_t *>(detail::
align(dest, alignof(T))) + sizeof(T);
244 template<
typename T,
typename U,
typename... Ts>
245 std::uint8_t *readElement(std::uint8_t *dest, PlyPropertyConstIterator first, PlyPropertyConstIterator last)
const
247 return readElement<U, Ts...>(readElement<T>(dest, first, last), first + detail::numProperties<T>(), last);
250 template<
typename PlyT,
typename PlySizeT,
typename DestT>
251 std::uint8_t *readListProperty(std::uint8_t *dest, reflect::Type<std::vector<DestT>>)
const
253 dest =
static_cast<std::uint8_t *
>(detail::align(dest,
alignof(std::vector<DestT>)));
254 std::vector<DestT> &v = *
reinterpret_cast<std::vector<DestT> *
>(dest);
256 const PlySizeT size = this->
template readNumber<PlySizeT>();
258 for (PlySizeT i = 0; i < size; ++i) { v.push_back(this->
template readNumber<PlyT>()); }
260 return dest +
sizeof(std::vector<DestT>);
263 template<
typename PlyT,
typename PlySizeT,
typename DestT, std::
size_t N>
264 std::uint8_t *readListProperty(std::uint8_t *dest, reflect::Type<reflect::Array<DestT, N>>)
const
266 static_assert(std::is_arithmetic<PlyT>::value,
"unexpected PLY data type");
270 this->
template skipNumber<PlySizeT>();
271 dest =
static_cast<std::uint8_t *
>(detail::align(dest,
alignof(DestT)));
272 return this->
template readNumbers<PlyT, DestT, N>(dest);
275 template<
typename PlyT,
typename TypeTag>
276 std::uint8_t *readListProperty(std::uint8_t *dest,
const PlyProperty &property, TypeTag tag)
const
278 switch (property.sizeType())
280 case PlyDataType::Char:
281 return readListProperty<PlyT, char>(dest, tag);
282 case PlyDataType::UChar:
283 return readListProperty<PlyT, unsigned char>(dest, tag);
284 case PlyDataType::Short:
285 return readListProperty<PlyT, short>(dest, tag);
286 case PlyDataType::UShort:
287 return readListProperty<PlyT, unsigned short>(dest, tag);
288 case PlyDataType::Int:
289 return readListProperty<PlyT, int>(dest, tag);
290 case PlyDataType::UInt:
291 return readListProperty<PlyT, unsigned int>(dest, tag);
292 case PlyDataType::Float:
293 return readListProperty<PlyT, float>(dest, tag);
294 case PlyDataType::Double:
295 return readListProperty<PlyT, double>(dest, tag);
301 template<
typename PlyT,
typename DestT>
302 std::uint8_t *readProperty(std::uint8_t *dest, reflect::Type<DestT>)
const
304 if constexpr (std::is_arithmetic_v<DestT>)
306 dest =
static_cast<std::uint8_t *
>(detail::align(dest,
alignof(DestT)));
307 *
reinterpret_cast<DestT *
>(dest) = this->
template readNumber<PlyT>();
308 return dest +
sizeof(DestT);
310 else {
return static_cast<std::uint8_t *
>(detail::align(dest,
alignof(DestT))) +
sizeof(DestT); }
313 template<
typename PlyT>
314 std::uint8_t *readProperty(std::uint8_t *dest, reflect::Type<reflect::Skip>)
const
319 template<
typename PlyT,
typename DestT>
320 std::uint8_t *readProperty(std::uint8_t *dest, reflect::Type<reflect::Stride<DestT>>)
const
322 return static_cast<std::uint8_t *
>(detail::align(dest,
alignof(DestT))) +
sizeof(DestT);
325 template<
typename PlyT,
typename DestT, std::
size_t N>
326 std::uint8_t *readProperty(std::uint8_t *dest, reflect::Type<reflect::Pack<DestT, N>>)
const
328 static_assert(std::is_arithmetic<PlyT>::value,
"unexpected PLY data type");
329 dest =
static_cast<std::uint8_t *
>(detail::align(dest,
alignof(DestT)));
330 return this->
template readNumbers<PlyT, DestT, N>(dest);
333 template<
typename TypeTag>
334 std::uint8_t *readProperty(std::uint8_t *dest,
const PlyProperty &property, TypeTag tag)
const
336 if constexpr (detail::isList<TypeTag>())
338 switch (property.type())
340 case PlyDataType::Char:
341 return readListProperty<char>(dest, property, tag);
342 case PlyDataType::UChar:
343 return readListProperty<unsigned char>(dest, property, tag);
344 case PlyDataType::Short:
345 return readListProperty<short>(dest, property, tag);
346 case PlyDataType::UShort:
347 return readListProperty<unsigned short>(dest, property, tag);
348 case PlyDataType::Int:
349 return readListProperty<int>(dest, property, tag);
350 case PlyDataType::UInt:
351 return readListProperty<unsigned int>(dest, property, tag);
352 case PlyDataType::Float:
353 return readListProperty<float>(dest, property, tag);
354 case PlyDataType::Double:
355 return readListProperty<double>(dest, property, tag);
358 else if constexpr (std::is_same_v<typename TypeTag::DestT, reflect::Skip>)
360 this->skipProperty(property);
364 switch (property.type())
366 case PlyDataType::Char:
367 return readProperty<char>(dest, tag);
368 case PlyDataType::UChar:
369 return readProperty<unsigned char>(dest, tag);
370 case PlyDataType::Short:
371 return readProperty<short>(dest, tag);
372 case PlyDataType::UShort:
373 return readProperty<unsigned short>(dest, tag);
374 case PlyDataType::Int:
375 return readProperty<int>(dest, tag);
376 case PlyDataType::UInt:
377 return readProperty<unsigned int>(dest, tag);
378 case PlyDataType::Float:
379 return readProperty<float>(dest, tag);
380 case PlyDataType::Double:
381 return readProperty<double>(dest, tag);
constexpr Ptr align(Ptr ptr, std::size_t alignment)
constexpr std::size_t sizeOf()
std::vector< PlyProperty >::const_iterator PlyPropertyConstIterator