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
193 if (detail::numProperties<Ts...>() < (last - first))
200 if (std::any_of(firstToSkip, last, [](
const PlyProperty &p) {
return p.isList(); }))
202 for (std::size_t i{0}; i < element.size(); ++i)
204 dest = detail::align(readElement<Ts...>(dest, first, last), alignment);
206 auto curr = firstToSkip;
207 while (curr < last) this->skipProperty(*curr++);
216 const std::size_t numBytesToSkip =
217 std::accumulate(firstToSkip, last, std::size_t{0}, [](std::size_t acc,
const PlyProperty &p) {
218 return acc +
sizeOf(p.isList() ? p.sizeType() : p.type());
221 for (std::size_t i{0}; i < element.size(); ++i)
223 dest = detail::align(readElement<Ts...>(dest, first, last), alignment);
224 this->skipProperties(numBytesToSkip);
230 for (std::size_t i{0}; i < element.size(); ++i)
232 dest = detail::align(readElement<Ts...>(dest, first, last), alignment);
238 std::uint8_t *readElement(std::uint8_t *dest, PlyPropertyConstIterator first, PlyPropertyConstIterator last)
241 return first < last ? readProperty(dest, *first, reflect::Type<T>{})
242 : static_cast<std::uint8_t *>(detail::
align(dest, alignof(T))) + sizeof(T);
245 template<
typename T,
typename U,
typename... Ts>
246 std::uint8_t *readElement(std::uint8_t *dest, PlyPropertyConstIterator first, PlyPropertyConstIterator last)
const
248 return readElement<U, Ts...>(readElement<T>(dest, first, last), first + detail::numProperties<T>(), last);
251 template<
typename PlyT,
typename PlySizeT,
typename DestT>
252 std::uint8_t *readListProperty(std::uint8_t *dest, reflect::Type<std::vector<DestT>>)
const
254 dest =
static_cast<std::uint8_t *
>(detail::align(dest,
alignof(std::vector<DestT>)));
255 std::vector<DestT> &v = *
reinterpret_cast<std::vector<DestT> *
>(dest);
257 const PlySizeT size = this->
template readNumber<PlySizeT>();
258 v.reserve(
static_cast<std::size_t
>(size));
259 for (PlySizeT i = 0; i < size; ++i) { v.push_back(
static_cast<DestT
>(this->
template readNumber<PlyT>())); }
261 return dest +
sizeof(std::vector<DestT>);
264 template<
typename PlyT,
typename PlySizeT,
typename DestT, std::
size_t N>
265 std::uint8_t *readListProperty(std::uint8_t *dest, reflect::Type<reflect::Array<DestT, N>>)
const
267 static_assert(std::is_arithmetic<PlyT>::value,
"unexpected PLY data type");
271 this->
template skipNumber<PlySizeT>();
272 dest =
static_cast<std::uint8_t *
>(detail::align(dest,
alignof(DestT)));
273 return this->
template readNumbers<PlyT, DestT, N>(dest);
276 template<
typename PlyT,
typename TypeTag>
277 std::uint8_t *readListProperty(std::uint8_t *dest,
const PlyProperty &property, TypeTag tag)
const
279 switch (property.sizeType())
281 case PlyDataType::Char:
282 return readListProperty<PlyT, char>(dest, tag);
283 case PlyDataType::UChar:
284 return readListProperty<PlyT, unsigned char>(dest, tag);
285 case PlyDataType::Short:
286 return readListProperty<PlyT, short>(dest, tag);
287 case PlyDataType::UShort:
288 return readListProperty<PlyT, unsigned short>(dest, tag);
289 case PlyDataType::Int:
290 return readListProperty<PlyT, int>(dest, tag);
291 case PlyDataType::UInt:
292 return readListProperty<PlyT, unsigned int>(dest, tag);
293 case PlyDataType::Float:
294 return readListProperty<PlyT, float>(dest, tag);
295 case PlyDataType::Double:
296 return readListProperty<PlyT, double>(dest, tag);
302 template<
typename PlyT,
typename DestT>
303 std::uint8_t *readProperty(std::uint8_t *dest, reflect::Type<DestT>)
const
305 if constexpr (std::is_arithmetic_v<DestT>)
307 dest =
static_cast<std::uint8_t *
>(detail::align(dest,
alignof(DestT)));
308 *
reinterpret_cast<DestT *
>(dest) =
static_cast<DestT
>(this->
template readNumber<PlyT>());
309 return dest +
sizeof(DestT);
311 else {
return static_cast<std::uint8_t *
>(detail::align(dest,
alignof(DestT))) +
sizeof(DestT); }
314 template<
typename PlyT>
315 std::uint8_t *readProperty(std::uint8_t *dest, reflect::Type<reflect::Skip>)
const
320 template<
typename PlyT,
typename DestT>
321 std::uint8_t *readProperty(std::uint8_t *dest, reflect::Type<reflect::Stride<DestT>>)
const
323 return static_cast<std::uint8_t *
>(detail::align(dest,
alignof(DestT))) +
sizeof(DestT);
326 template<
typename PlyT,
typename DestT, std::
size_t N>
327 std::uint8_t *readProperty(std::uint8_t *dest, reflect::Type<reflect::Pack<DestT, N>>)
const
329 static_assert(std::is_arithmetic<PlyT>::value,
"unexpected PLY data type");
330 dest =
static_cast<std::uint8_t *
>(detail::align(dest,
alignof(DestT)));
331 return this->
template readNumbers<PlyT, DestT, N>(dest);
334 template<
typename TypeTag>
335 std::uint8_t *readProperty(std::uint8_t *dest,
const PlyProperty &property, TypeTag tag)
const
337 if constexpr (detail::isList<TypeTag>())
339 switch (property.type())
341 case PlyDataType::Char:
342 return readListProperty<char>(dest, property, tag);
343 case PlyDataType::UChar:
344 return readListProperty<unsigned char>(dest, property, tag);
345 case PlyDataType::Short:
346 return readListProperty<short>(dest, property, tag);
347 case PlyDataType::UShort:
348 return readListProperty<unsigned short>(dest, property, tag);
349 case PlyDataType::Int:
350 return readListProperty<int>(dest, property, tag);
351 case PlyDataType::UInt:
352 return readListProperty<unsigned int>(dest, property, tag);
353 case PlyDataType::Float:
354 return readListProperty<float>(dest, property, tag);
355 case PlyDataType::Double:
356 return readListProperty<double>(dest, property, tag);
359 else if constexpr (std::is_same_v<typename TypeTag::DestT, reflect::Skip>)
361 this->skipProperty(property);
365 switch (property.type())
367 case PlyDataType::Char:
368 return readProperty<char>(dest, tag);
369 case PlyDataType::UChar:
370 return readProperty<unsigned char>(dest, tag);
371 case PlyDataType::Short:
372 return readProperty<short>(dest, tag);
373 case PlyDataType::UShort:
374 return readProperty<unsigned short>(dest, tag);
375 case PlyDataType::Int:
376 return readProperty<int>(dest, tag);
377 case PlyDataType::UInt:
378 return readProperty<unsigned int>(dest, tag);
379 case PlyDataType::Float:
380 return readProperty<float>(dest, tag);
381 case PlyDataType::Double:
382 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