PLYwoot
Header-only C++17 library for parsing and writing PLY files
Loading...
Searching...
No Matches
element_data.hpp
Go to the documentation of this file.
1/*
2 This file is part of PLYwoot, a header-only PLY parser.
3
4 Copyright (C) 2023-2025, Ton van den Heuvel
5
6 PLYwoot is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18*/
19
20#ifndef PLYWOOT_ELEMENT_DATA_HPP
21#define PLYWOOT_ELEMENT_DATA_HPP
22
24
25#include "types.hpp"
26
27#include <algorithm>
28#include <memory>
29#include <vector>
30
31namespace plywoot {
32
36{
37public:
39 PlyElementData() = default;
40
47 explicit PlyElementData(const PlyElement &element) : element_{element}
48 {
49 // Keep track of the alignment requirements of the memory block that will
50 // store all element data. Store the relative offsets of every manually
51 // allocated `std::vector` in the element data.
52 const std::vector<PlyProperty> &properties = element_.properties();
53 for (const PlyProperty &property : properties)
54 {
55 if (property.isList())
56 {
57 // Note, the exact type of the vector element does not matter here.
58 listOffsets_.push_back(detail::align(bytesPerElement_, alignof(std::vector<int>)));
59 bytesPerElement_ = listOffsets_.back() + sizeof(std::vector<int>);
60 alignment_ = std::max(alignment_, alignof(std::vector<int>));
61 }
62 else
63 {
64 bytesPerElement_ = detail::align(bytesPerElement_, property.type()) + detail::sizeOf(property.type());
65 switch (property.type())
66 {
67 case PlyDataType::Short:
68 alignment_ = std::max(alignment_, alignof(short));
69 break;
70 case PlyDataType::UShort:
71 alignment_ = std::max(alignment_, alignof(unsigned short));
72 break;
73 case PlyDataType::Int:
74 alignment_ = std::max(alignment_, alignof(int));
75 break;
76 case PlyDataType::UInt:
77 alignment_ = std::max(alignment_, alignof(unsigned int));
78 break;
79 case PlyDataType::Float:
80 alignment_ = std::max(alignment_, alignof(float));
81 break;
82 case PlyDataType::Double:
83 alignment_ = std::max(alignment_, alignof(double));
84 break;
85 default:
86 break;
87 }
88 }
89 }
90
91 // Consecutive instances of an element in the memory block are aligned given
92 // the maximum alignment requirement of an individual property type in an
93 // element. The overall alignment requirements of an element determine the
94 // overall size of the element in bytes.
95 bytesPerElement_ = detail::align(bytesPerElement_, alignment_);
96
97 // Now, allocate a raw block of memory large enough to hold all element
98 // data.
99 data_ = std::unique_ptr<std::uint8_t[]>(new std::uint8_t[element_.size() * bytesPerElement_]);
100
101 // Finally, allocate all vectors holding the variable length list
102 // properties.
103 auto listOffset = listOffsets_.begin();
104 for (PlyProperty property : element_.properties())
105 {
106 if (property.isList())
107 {
108 // Note, the exact type of the vector element does not matter here.
109 std::uint8_t *ptr = data_.get() + *listOffset++;
110 for (std::size_t i = 0; i < element_.size(); ++i, ptr += bytesPerElement_)
111 {
112 switch (property.type())
113 {
114 case PlyDataType::Char:
115 new (ptr) std::vector<char>();
116 break;
117 case PlyDataType::UChar:
118 new (ptr) std::vector<unsigned char>();
119 break;
120 case PlyDataType::Short:
121 new (ptr) std::vector<short>();
122 break;
123 case PlyDataType::UShort:
124 new (ptr) std::vector<unsigned short>();
125 break;
126 case PlyDataType::Int:
127 new (ptr) std::vector<int>();
128 break;
129 case PlyDataType::UInt:
130 new (ptr) std::vector<unsigned int>();
131 break;
132 case PlyDataType::Float:
133 new (ptr) std::vector<float>();
134 break;
135 case PlyDataType::Double:
136 new (ptr) std::vector<double>();
137 break;
138 }
139 }
140 }
141 }
142 }
143
146 {
147 auto listOffset = listOffsets_.begin();
148 for (const PlyProperty &property : element_.properties())
149 {
150 if (property.isList())
151 {
152 // Note, the exact type of the vector element does not matter here.
153 std::uint8_t *ptr = data_.get() + *listOffset++;
154 for (std::size_t i = 0; i < element_.size(); ++i, ptr += bytesPerElement_)
155 {
156 switch (property.type())
157 {
158 case PlyDataType::Char:
159 reinterpret_cast<std::vector<char> *>(ptr)->~vector<char>();
160 break;
161 case PlyDataType::UChar:
162 reinterpret_cast<std::vector<unsigned char> *>(ptr)->~vector<unsigned char>();
163 break;
164 case PlyDataType::Short:
165 reinterpret_cast<std::vector<short> *>(ptr)->~vector<short>();
166 break;
167 case PlyDataType::UShort:
168 reinterpret_cast<std::vector<unsigned short> *>(ptr)->~vector<unsigned short>();
169 break;
170 case PlyDataType::Int:
171 reinterpret_cast<std::vector<int> *>(ptr)->~vector<int>();
172 break;
173 case PlyDataType::UInt:
174 reinterpret_cast<std::vector<unsigned int> *>(ptr)->~vector<unsigned int>();
175 break;
176 case PlyDataType::Float:
177 reinterpret_cast<std::vector<float> *>(ptr)->~vector<float>();
178 break;
179 case PlyDataType::Double:
180 reinterpret_cast<std::vector<double> *>(ptr)->~vector<double>();
181 break;
182 }
183 }
184 }
185 }
186 }
187
188 // This type is non-copyable.
190 PlyElementData(const PlyElementData &) = delete;
191 PlyElementData &operator=(const PlyElementData &) = delete;
193
197 PlyElementData(PlyElementData &&x) noexcept { *this = std::move(x); }
198
204 {
205 element_ = std::move(x.element_);
206 data_.reset(x.data_.release());
207 listOffsets_ = std::move(x.listOffsets_);
208 bytesPerElement_ = x.bytesPerElement_;
209 alignment_ = x.alignment_;
210
211 x.bytesPerElement_ = 0;
212 x.listOffsets_.clear();
213 x.element_ = PlyElement();
214
215 return *this;
216 }
217
222 const PlyElement &element() const { return element_; }
223
227 std::uint8_t *data() const { return data_.get(); }
228
234 std::size_t alignment() const { return alignment_; }
235
236private:
238 PlyElement element_;
240 std::unique_ptr<std::uint8_t[]> data_;
243 std::vector<std::size_t> listOffsets_;
245 std::size_t bytesPerElement_ = 0;
248 std::size_t alignment_ = alignof(char);
249};
250
251}
252
253#endif
PlyElementData(PlyElementData &&x) noexcept
const PlyElement & element() const
PlyElementData & operator=(PlyElementData &&x) noexcept
std::uint8_t * data() const
PlyElementData(const PlyElement &element)
~PlyElementData()
Destructor, deallocates all vectors holding the variable length lists.
PlyElementData()=default
Default constructor.
std::size_t alignment() const
const std::vector< PlyProperty > & properties() const
Definition types.hpp:181
std::size_t size() const
Definition types.hpp:177