1 // Copyright 2018 The Draco Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15
16 #ifndef DRACO_COMPRESSION_ATTRIBUTES_POINT_D_VECTOR_H_
17 #define DRACO_COMPRESSION_ATTRIBUTES_POINT_D_VECTOR_H_
18
19 #include <cstring>
20 #include <memory>
21 #include <vector>
22 #include "draco/core/macros.h"
23
24 namespace draco {
25
26 // The main class of this file is PointDVector providing an interface similar to
27 // std::vector<PointD> for arbitrary number of dimensions (without a template
28 // argument). PointDVectorIterator is a random access iterator, which allows for
29 // compatibility with existing algorithms. PseudoPointD provides for a view on
30 // the individual items in a contiguous block of memory, which is compatible
31 // with the swap function and is returned by a dereference of
32 // PointDVectorIterator. Swap functions provide for compatibility/specialization
33 // that allows these classes to work with currently utilized STL functions.
34
35 // This class allows for swap functionality from the RandomIterator
36 // It seems problematic to bring this inside PointDVector due to templating.
37 template <typename internal_t>
38 class PseudoPointD {
39 public:
PseudoPointD(internal_t * mem,internal_t dimension)40 PseudoPointD(internal_t *mem, internal_t dimension)
41 : mem_(mem), dimension_(dimension) {}
42
43 // Specifically copies referenced memory
swap(PseudoPointD & other)44 void swap(PseudoPointD &other) noexcept {
45 for (internal_t dim = 0; dim < dimension_; dim += 1)
46 std::swap(mem_[dim], other.mem_[dim]);
47 }
48
PseudoPointD(const PseudoPointD & other)49 PseudoPointD(const PseudoPointD &other)
50 : mem_(other.mem_), dimension_(other.dimension_) {}
51
52 const internal_t &operator[](const size_t &n) const {
53 DRACO_DCHECK_LT(n, dimension_);
54 return mem_[n];
55 }
56 internal_t &operator[](const size_t &n) {
57 DRACO_DCHECK_LT(n, dimension_);
58 return mem_[n];
59 }
60
61 bool operator==(const PseudoPointD &other) const {
62 for (auto dim = 0; dim < dimension_; dim += 1)
63 if (mem_[dim] != other.mem_[dim])
64 return false;
65 return true;
66 }
67 bool operator!=(const PseudoPointD &other) const {
68 return !this->operator==(other);
69 }
70
71 private:
72 internal_t *const mem_;
73 const internal_t dimension_;
74 };
75
76 // It seems problematic to bring this inside PointDVector due to templating.
77 template <typename internal_t>
swap(draco::PseudoPointD<internal_t> && a,draco::PseudoPointD<internal_t> && b)78 void swap(draco::PseudoPointD<internal_t> &&a,
79 draco::PseudoPointD<internal_t> &&b) noexcept {
80 a.swap(b);
81 };
82 template <typename internal_t>
swap(draco::PseudoPointD<internal_t> & a,draco::PseudoPointD<internal_t> & b)83 void swap(draco::PseudoPointD<internal_t> &a,
84 draco::PseudoPointD<internal_t> &b) noexcept {
85 a.swap(b);
86 };
87
88 template <typename internal_t>
89 class PointDVector {
90 public:
PointDVector(const uint32_t n_items,const uint32_t dimensionality)91 PointDVector(const uint32_t n_items, const uint32_t dimensionality)
92 : n_items_(n_items),
93 dimensionality_(dimensionality),
94 item_size_bytes_(dimensionality * sizeof(internal_t)),
95 data_(n_items * dimensionality),
96 data0_(data_.data()) {}
97 // random access iterator
98 class PointDVectorIterator
99 : public std::iterator<std::random_access_iterator_tag, size_t, size_t> {
100 friend class PointDVector;
101
102 public:
103 // std::iter_swap is called inside of std::partition and needs this
104 // specialized support
105 PseudoPointD<internal_t> operator*() const {
106 return PseudoPointD<internal_t>(vec_->data0_ + item_ * dimensionality_,
107 dimensionality_);
108 }
109 const PointDVectorIterator &operator++() {
110 item_ += 1;
111 return *this;
112 }
113 const PointDVectorIterator &operator--() {
114 item_ -= 1;
115 return *this;
116 }
117 PointDVectorIterator operator++(int32_t) {
118 PointDVectorIterator copy(*this);
119 item_ += 1;
120 return copy;
121 }
122 PointDVectorIterator operator--(int32_t) {
123 PointDVectorIterator copy(*this);
124 item_ -= 1;
125 return copy;
126 }
127 PointDVectorIterator &operator=(const PointDVectorIterator &other) {
128 this->item_ = other.item_;
129 return *this;
130 }
131
132 bool operator==(const PointDVectorIterator &ref) const {
133 return item_ == ref.item_;
134 }
135 bool operator!=(const PointDVectorIterator &ref) const {
136 return item_ != ref.item_;
137 }
138 bool operator<(const PointDVectorIterator &ref) const {
139 return item_ < ref.item_;
140 }
141 bool operator>(const PointDVectorIterator &ref) const {
142 return item_ > ref.item_;
143 }
144 bool operator<=(const PointDVectorIterator &ref) const {
145 return item_ <= ref.item_;
146 }
147 bool operator>=(const PointDVectorIterator &ref) const {
148 return item_ >= ref.item_;
149 }
150
151 PointDVectorIterator operator+(const int32_t &add) const {
152 PointDVectorIterator copy(vec_, item_ + add);
153 return copy;
154 }
155 PointDVectorIterator &operator+=(const int32_t &add) {
156 item_ += add;
157 return *this;
158 }
159 PointDVectorIterator operator-(const int32_t &sub) const {
160 PointDVectorIterator copy(vec_, item_ - sub);
161 return copy;
162 }
163 size_t operator-(const PointDVectorIterator &sub) const {
164 return (item_ - sub.item_);
165 }
166
167 PointDVectorIterator &operator-=(const int32_t &sub) {
168 item_ -= sub;
169 return *this;
170 }
171
172 internal_t *operator[](const size_t &n) const {
173 return vec_->data0_ + (item_ + n) * dimensionality_;
174 }
175
176 protected:
PointDVectorIterator(PointDVector * vec,size_t start_item)177 explicit PointDVectorIterator(PointDVector *vec, size_t start_item)
178 : item_(start_item), vec_(vec), dimensionality_(vec->dimensionality_) {}
179
180 private:
181 size_t item_; // this counts the item that should be referenced.
182 PointDVector *const vec_; // the thing that we're iterating on
183 const uint32_t dimensionality_; // local copy from vec_
184 };
185
begin()186 PointDVectorIterator begin() { return PointDVectorIterator(this, 0); }
end()187 PointDVectorIterator end() { return PointDVectorIterator(this, n_items_); }
188
189 // operator[] allows for unprotected user-side usage of operator[] on the
190 // return value AS IF it were a natively indexable type like Point3*
191 internal_t *operator[](const uint32_t index) {
192 DRACO_DCHECK_LT(index, n_items_);
193 return data0_ + index * dimensionality_;
194 }
195 const internal_t *operator[](const uint32_t index) const {
196 DRACO_DCHECK_LT(index, n_items_);
197 return data0_ + index * dimensionality_;
198 }
199
size()200 uint32_t size() const { return n_items_; }
GetBufferSize()201 size_t GetBufferSize() const { return data_.size(); }
202
203 // copy a single contiguous 'item' from one PointDVector into this one.
CopyItem(const PointDVector & source,const internal_t source_index,const internal_t destination_index)204 void CopyItem(const PointDVector &source, const internal_t source_index,
205 const internal_t destination_index) {
206 DRACO_DCHECK(&source != this ||
207 (&source == this && source_index != destination_index));
208 DRACO_DCHECK_LT(destination_index, n_items_);
209 DRACO_DCHECK_LT(source_index, source.n_items_);
210
211 // DRACO_DCHECK_EQ(source.n_items_, n_items_); // not technically necessary
212 DRACO_DCHECK_EQ(source.dimensionality_, dimensionality_);
213
214 const internal_t *ref = source[source_index];
215 internal_t *const dest = this->operator[](destination_index);
216 std::memcpy(dest, ref, item_size_bytes_);
217 }
218
219 // Copy data directly off of an attribute buffer interleaved into internal
220 // memory.
CopyAttribute(const internal_t attribute_dimensionality,const internal_t offset_dimensionality,const internal_t index,const void * const attribute_item_data)221 void CopyAttribute(
222 // The dimensionality of the attribute being integrated
223 const internal_t attribute_dimensionality,
224 // The offset in dimensions to insert this attribute.
225 const internal_t offset_dimensionality, const internal_t index,
226 // The direct pointer to the data
227 const void *const attribute_item_data) {
228 // chunk copy
229 const size_t copy_size = sizeof(internal_t) * attribute_dimensionality;
230
231 // a multiply and add can be optimized away with an iterator
232 std::memcpy(data0_ + index * dimensionality_ + offset_dimensionality,
233 attribute_item_data, copy_size);
234 }
235 // Copy data off of a contiguous buffer interleaved into internal memory
CopyAttribute(const internal_t attribute_dimensionality,const internal_t offset_dimensionality,const internal_t * const attribute_mem)236 void CopyAttribute(
237 // The dimensionality of the attribute being integrated
238 const internal_t attribute_dimensionality,
239 // The offset in dimensions to insert this attribute.
240 const internal_t offset_dimensionality,
241 const internal_t *const attribute_mem) {
242 DRACO_DCHECK_LT(offset_dimensionality,
243 dimensionality_ - attribute_dimensionality);
244 // degenerate case block copy the whole buffer.
245 if (dimensionality_ == attribute_dimensionality) {
246 DRACO_DCHECK_EQ(offset_dimensionality, 0);
247 const size_t copy_size =
248 sizeof(internal_t) * attribute_dimensionality * n_items_;
249 std::memcpy(data0_, attribute_mem, copy_size);
250 } else { // chunk copy
251 const size_t copy_size = sizeof(internal_t) * attribute_dimensionality;
252 internal_t *internal_data;
253 const internal_t *attribute_data;
254 internal_t item;
255 for (internal_data = data0_ + offset_dimensionality,
256 attribute_data = attribute_mem, item = 0;
257 item < n_items_; internal_data += dimensionality_,
258 attribute_data += attribute_dimensionality, item += 1) {
259 std::memcpy(internal_data, attribute_data, copy_size);
260 }
261 }
262 }
263
264 private:
265 // internal parameters.
266 const uint32_t n_items_;
267 const uint32_t dimensionality_; // The dimension of the points in the buffer
268 const uint32_t item_size_bytes_;
269 std::vector<internal_t> data_; // contiguously stored data. Never resized.
270 internal_t *const data0_; // raw pointer to base data.
271 };
272
273 } // namespace draco
274
275 #endif // DRACO_COMPRESSION_ATTRIBUTES_POINT_D_VECTOR_H_
276