Loading...
Searching...
No Matches
flatVector2D.tpp
1/*---------------------------------------------------------------------------*\
2 *
3 * bitpit
4 *
5 * Copyright (C) 2015-2021 OPTIMAD engineering Srl
6 *
7 * -------------------------------------------------------------------------
8 * License
9 * This file is part of bitpit.
10 *
11 * bitpit is free software: you can redistribute it and/or modify it
12 * under the terms of the GNU Lesser General Public License v3 (LGPL)
13 * as published by the Free Software Foundation.
14 *
15 * bitpit is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
18 * License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with bitpit. If not, see <http://www.gnu.org/licenses/>.
22 *
23\*---------------------------------------------------------------------------*/
24
25#ifndef __BITPIT_FLAT_VECTOR_2D_TPP__
26#define __BITPIT_FLAT_VECTOR_2D_TPP__
27
28#include <vector>
29#include <cassert>
30#include <iostream>
31#include <memory>
32
33#include "binary_stream.hpp"
34
35namespace bitpit {
36
45template<class T>
46OBinaryStream& operator<<(OBinaryStream &buffer, const FlatVector2D<T> &vector)
47{
48 buffer << vector.m_index;
49 buffer << vector.m_v;
50
51 return buffer;
52}
53
62template<class T>
63IBinaryStream& operator>>(IBinaryStream &buffer, FlatVector2D<T> &vector)
64{
65 buffer >> vector.m_index;
66 buffer >> vector.m_v;
67
68 return buffer;
71/*!
72 Default constructor.
73*/
74template <class T>
76 : m_index(initialize ? 1 : 0, 0L)
77{
78}
79
87template <class T>
88FlatVector2D<T>::FlatVector2D(const std::vector<std::size_t> &sizes, const T &value)
89{
90 initialize(sizes.size(), sizes.data(), 1, &value, 0);
91}
92
93/*!
94 Creates a new container.
96 \param nVectors is the number of vectors
97 \param size is the size of the vectors
98 \param value is the value that will be use to initialize the
99 items of the vectors
101template <class T>
102FlatVector2D<T>::FlatVector2D(std::size_t nVectors, std::size_t size, const T &value)
104 initialize(nVectors, &size, 0, &value, 0);
107/*!
108 Creates a new container.
110 \param nVectors is the number of vectors
111 \param sizes are the sizes of the vectors
112 \param value is the value that will be use to initialize the
113 items of the vectors
115template <class T>
116FlatVector2D<T>::FlatVector2D(std::size_t nVectors, const std::size_t *sizes, const T &value)
118 initialize(nVectors, sizes, 1, &value, 0);
119}
121/*!
122 Creates a new container.
124 \param nVectors is the number of vectors
125 \param sizes are the sizes of the vectors
126 \param values are the values of the vectors
128template <class T>
129FlatVector2D<T>::FlatVector2D(std::size_t nVectors, const std::size_t *sizes, const T *values)
131 initialize(nVectors, sizes, 1, values, 1);
132}
134/*!
135 Creates a new container.
137 \param vector2D is a 2D vector that will be used to initialize the
138 newly created container
140template <class T>
141FlatVector2D<T>::FlatVector2D(const std::vector<std::vector<T> > &vector2D)
142{
143 initialize(vector2D);
146/*!
147 Check if the container has been initialized.
149 \result Returns true if the container has been initialized, false otherwise.
150*/
151template <class T>
153{
154 return (!m_index.empty());
155}
157/*!
158 Initializes the container.
159
160 \param sizes are the sizes of the vectors
161 \param value is the value that will be use to initialize the items of
162 the vectors
163*/
164template <class T>
165void FlatVector2D<T>::initialize(const std::vector<std::size_t> &sizes, const T &value)
166{
167 initialize(sizes.size(), sizes.data(), 1, &value, 1);
168}
169
178template <class T>
179void FlatVector2D<T>::initialize(std::size_t nVectors, std::size_t size, const T &value)
180{
181 initialize(nVectors, &size, 0, &value, 0);
182}
183
192template <class T>
193void FlatVector2D<T>::initialize(std::size_t nVectors, const std::size_t *sizes, const T &value)
194{
195 initialize(nVectors, sizes, 1, &value, 0);
196}
197
198
206template <class T>
207void FlatVector2D<T>::initialize(std::size_t nVectors, const std::size_t *sizes, const T *values)
208{
209 initialize(nVectors, sizes, 1, values, 1);
210}
211
221template <class T>
222void FlatVector2D<T>::initialize(std::size_t nVectors,
223 const std::size_t *sizes, std::size_t sizesStride,
224 const T *values, std::size_t valuesStride)
225{
226 std::size_t nItems = 0;
227 for (std::size_t i = 0; i < nVectors; ++i) {
228 nItems += *(sizes + i * sizesStride);
229 }
230
231 // Check if the container need reallocation
232 //
233 // If the current number of items is different from the number of items
234 // the container should contain after the initialization, a reallocation
235 // is needed.
236 bool reallocateIndex = (nVectors != size());
237 bool reallocateValues = (nItems != getItemCount());
238
239 // Destroy current data structures
240 //
241 // Index and the storage data will probabily be stored in memory
242 // regions contigous to each other. To reduce memory fragmentation
243 // it's better to deallocate the container before updating its
244 // data structures.
245 if (reallocateIndex || reallocateValues) {
246 destroy(reallocateIndex, reallocateValues);
247 }
248
249 // Initialize the indexes
250 if (reallocateIndex) {
251 m_index.resize(nVectors + 1);
252 }
253
254 m_index[0] = 0;
255 for (std::size_t i = 0; i < nVectors; ++i) {
256 m_index[i+1] = m_index[i] + *(sizes + i * sizesStride);
257 }
258
259 // Initialize the storage
260 if (valuesStride == 0) {
261 if (reallocateValues) {
262 m_v.assign(nItems, *values);
263 } else {
264 for (std::size_t k = 0; k < nItems; ++k) {
265 m_v[k] = *values;
266 }
267 }
268 } else {
269 if (reallocateValues) {
270 m_v.resize(nItems);
271 }
272
273 std::size_t k = 0;
274 for (std::size_t i = 0; i < nVectors; ++i) {
275 std::size_t subArraySize = *(sizes + i * sizesStride);
276 for (std::size_t j = 0; j < subArraySize; ++j) {
277 m_v[k++] = *(values + i * valuesStride + j);
278 }
279 }
280 }
281}
282
289template <class T>
290void FlatVector2D<T>::initialize(const std::vector<std::vector<T> > &vector2D)
291{
292 std::size_t nVectors = vector2D.size();
293
294 std::size_t nItems = 0;
295 for (std::size_t i = 0; i < nVectors; ++i) {
296 nItems += vector2D[i].size();
297 }
298
299 // Check if the container need reallocation
300 //
301 // If the current number of items is different from the number of items
302 // the container should contain after the initialization, a reallocation
303 // is needed.
304 bool reallocateIndex = (nVectors != size());
305 bool reallocateValues = (nItems != getItemCount());
306
307 // Destroy current data structures
308 //
309 // Index and the storage data will probabily be stored in memory
310 // regions contigous to each other. To reduce memory fragmentation
311 // it's better to deallocate the container before updating its
312 // data structures.
313 if (reallocateIndex || reallocateValues) {
314 destroy(reallocateIndex, reallocateValues);
315 }
316
317 // Initialize the indexes
318 if (reallocateIndex) {
319 m_index.resize(nVectors + 1);
320 }
321
322 m_index[0] = 0;
323 for (std::size_t i = 0; i < nVectors; ++i) {
324 m_index[i+1] = m_index[i] + vector2D[i].size();
325 }
326
327 // Initialize the storage
328 if (reallocateValues) {
329 m_v.resize(nItems);
330 }
331
332 std::size_t k = 0;
333 for (std::size_t i = 0; i < nVectors; ++i) {
334 std::size_t subArraySize = vector2D[i].size();
335 for (std::size_t j = 0; j < subArraySize; ++j) {
336 m_v[k++] = vector2D[i][j];
337 }
338 }
339}
340
347template <class T>
349{
350 m_v.assign(other.m_v.begin(), other.m_v.end());
351 m_index.assign(other.m_index.begin(), other.m_index.end());
352}
353
360template <class T>
362{
363 destroy(true, true);
364}
365
375template <class T>
376void FlatVector2D<T>::destroy(bool destroyIndex, bool destroyValues)
377{
378 if (destroyIndex) {
379 m_index.clear();
380 m_index.shrink_to_fit();
381 }
382
383 if (destroyValues) {
384 m_v.clear();
385 m_v.shrink_to_fit();
386 }
387}
388
400template <class T>
401void FlatVector2D<T>::reserve(std::size_t nVectors, std::size_t nItems)
402{
403 m_index.reserve(nVectors + 1);
404 if (nItems > 0) {
405 m_v.reserve(nItems);
406 }
407}
408
414template <class T>
416{
417 m_index.swap(other.m_index);
418 m_v.swap(other.m_v);
419}
420
427template <class T>
429{
430 std::fill(m_v.begin(), m_v.end(), value);
431}
432
438template <class T>
440{
441 return m_index == rhs.m_index && m_v == rhs.m_v;
442}
443
449template <class T>
451{
452 return size() == 0;
453}
454
465template <class T>
466void FlatVector2D<T>::clear(bool release)
467{
468 if (release) {
469 std::vector<T>(0).swap(m_v);
470
471 std::vector<size_t>(1, 0L).swap(m_index);
472 } else {
473 m_v.clear();
474
475 m_index.resize(1);
476 m_index[0] = 0;
477 }
478}
479
490template <class T>
492{
493 std::size_t nVectors = size();
494 if (release) {
495 std::vector<T>(0).swap(m_v);
496
497 std::vector<size_t>(nVectors + 1, 0L).swap(m_index);
498 } else {
499 m_v.clear();
500
501 m_index.assign(nVectors + 1, 0L);
502 }
503}
504
510template <class T>
512{
513 m_v.shrink_to_fit();
514 m_index.shrink_to_fit();
515}
516
524template <class T>
525const std::size_t * FlatVector2D<T>::indices() const noexcept
526{
527 return m_index.data();
528}
529
540template <class T>
541const std::size_t * FlatVector2D<T>::indices(std::size_t i) const noexcept
542{
543 return (m_index.data() + i);
544}
545
554template <class T>
556{
557 return m_v.data();
558}
559
568template <class T>
569const T * FlatVector2D<T>::data() const noexcept
570{
571 return m_v.data();
572}
573
582template <class T>
583const std::vector<T> & FlatVector2D<T>::vector() const
584{
585 return m_v;
586}
587
594template <class T>
596{
597 pushBack(0);
598}
599
611template <class T>
612void FlatVector2D<T>::pushBack(std::size_t subArraySize, const T &value)
613{
614 std::size_t previousLastIndex = m_index.back();
615 m_index.emplace_back(previousLastIndex + subArraySize);
616
617 m_v.resize(m_v.size() + subArraySize, value);
618}
619
628template <class T>
629void FlatVector2D<T>::pushBack(const std::vector<T> &subArray)
630{
631 pushBack(subArray.size(), subArray.data());
632}
633
643template <class T>
644void FlatVector2D<T>::pushBack(std::size_t subArraySize, const T *subArray)
645{
646 std::size_t previousLastIndex = m_index.back();
647 m_index.emplace_back(previousLastIndex + subArraySize);
648
649 m_v.insert(m_v.end(), subArray, subArray + subArraySize);
650}
651
659template <class T>
661{
662 m_index.back()++;
663
664 m_v.emplace_back(value);
665}
666
674template <class T>
676{
677 m_index.back()++;
678
679 m_v.emplace_back(std::move(value));
680}
681
690template <class T>
691void FlatVector2D<T>::pushBackItem(std::size_t i, const T &value)
692{
693 assert(isIndexValid(i));
694
695 m_v.insert(m_v.begin() + m_index[i+1], value);
696
697 std::size_t nIndexes = m_index.size();
698 for (std::size_t k = i + 1; k < nIndexes; ++k) {
699 m_index[k]++;
700 }
701}
702
703
712template <class T>
713void FlatVector2D<T>::pushBackItem(std::size_t i, T &&value)
714{
715 assert(isIndexValid(i));
716
717 m_v.insert(m_v.begin() + m_index[i+1], std::move(value));
718
719 std::size_t nIndexes = m_index.size();
720 for (std::size_t k = i + 1; k < nIndexes; ++k) {
721 m_index[k]++;
722 }
723}
724
731template <class T>
733{
734 if (size() == 0) {
735 return;
736 }
737
738 m_index.pop_back();
739 m_v.resize(m_index.back() + 1);
740}
741
747template <class T>
749{
750 if (getItemCount(size() - 1) == 0) {
751 return;
752 }
753
754 m_index.back()--;
755 m_v.resize(m_index.back() + 1);
756}
757
765template <class T>
767{
768 assert(isIndexValid(i));
769
770 if (getItemCount(i) == 0) {
771 return;
772 }
773
774 m_v.erase(m_v.begin() + m_index[i+1] - 1);
775
776 std::size_t nIndexes = m_index.size();
777 for (std::size_t k = i + 1; k < nIndexes; ++k) {
778 m_index[k]--;
779 }
780}
781
790template <class T>
791void FlatVector2D<T>::erase(std::size_t i)
792{
793 assert(isIndexValid(i));
794
795 m_v.erase(m_v.begin() + m_index[i], m_v.begin() + m_index[i+1] - 1);
796 m_index.erase(m_index.begin() + i + 1);
797}
798
805template <class T>
806void FlatVector2D<T>::eraseItem(std::size_t i, std::size_t j)
807{
808 assert(isIndexValid(i, j));
809
810 m_v.erase(m_v.begin() + m_index[i] + j);
811
812 std::size_t nIndexes = m_index.size();
813 for (std::size_t k = i + 1; k < nIndexes; ++k) {
814 m_index[k]--;
815 }
816}
817
825template <class T>
826void FlatVector2D<T>::setItem(std::size_t i, std::size_t j, const T &value)
827{
828 assert(isIndexValid(i, j));
829 (*this)[i][j] = value;
830}
831
839template <class T>
840void FlatVector2D<T>::setItem(std::size_t i, std::size_t j, T &&value)
841{
842 assert(isIndexValid(i, j));
843 (*this)[i][j] = std::move(value);
844}
845
853template <class T>
854T & FlatVector2D<T>::getItem(std::size_t i, std::size_t j)
855{
856 assert(isIndexValid(i, j));
857 return (*this)[i][j];
858}
859
867template <class T>
868const T & FlatVector2D<T>::getItem(std::size_t i, std::size_t j) const
869{
870 assert(isIndexValid(i, j));
871 return (*this)[i][j];
872}
873
880template <class T>
881const T * FlatVector2D<T>::get(std::size_t i) const
882{
883 assert(!empty());
884 assert(isIndexValid(i));
885 return (*this)[i];
886}
887
894template <class T>
895T * FlatVector2D<T>::get(std::size_t i)
896{
897 assert(!empty());
898 assert(isIndexValid(i));
899 return (*this)[i];
900}
901
908template <class T>
909void FlatVector2D<T>::rawSetItem(std::size_t k, const T &value)
910{
911 m_v[k] = value;
912}
913
920template <class T>
921void FlatVector2D<T>::rawSetItem(std::size_t k, T &&value)
922{
923 m_v[k] = std::move(value);
924}
925
932template <class T>
934{
935 return m_v[k];
936}
937
944template <class T>
945const T & FlatVector2D<T>::rawGetItem(std::size_t k) const
946{
947 return m_v[k];
948}
949
955template <class T>
957{
958 return get(size() - 1);
959}
960
966template <class T>
968{
969 return get(0);
970}
971
977template <class T>
978std::size_t FlatVector2D<T>::size() const
979{
980 if (!isInitialized()) {
981 return 0;
982 }
983
984 return (m_index.size() - 1);
985}
986
994template <class T>
995std::size_t FlatVector2D<T>::capacity() const
996{
997 if (!isInitialized()) {
998 return 0;
999 }
1000
1001 return m_index.capacity() - 1;
1002}
1003
1007template <class T>
1009{
1010 if (size() == 0) {
1011 return;
1012 }
1013
1014 m_index[1] = m_index.back();
1015 m_index.resize(2);
1016}
1017
1023template <class T>
1025{
1026 if (!isInitialized()) {
1027 return 0;
1028 }
1029
1030 return m_v.size();
1031}
1032
1039template <class T>
1040std::size_t FlatVector2D<T>::getItemCount(std::size_t i) const
1041{
1042 if (!isInitialized()) {
1043 return 0;
1044 }
1045
1046 return m_index[i + 1] - m_index[i];
1047}
1048
1056template <class T>
1058{
1059 return m_v.capacity();
1060}
1061
1067template <class T>
1069{
1070 return ((2 + m_index.size())*sizeof(size_t) + m_v.size() * sizeof(T));
1071}
1072
1079template <class T>
1080const T* FlatVector2D<T>::operator[](std::size_t i) const
1081{
1082 assert(isIndexValid(i));
1083
1084 if (m_v.empty()) {
1085 return nullptr;
1086 }
1087
1088 std::size_t index = m_index[i];
1089 return &m_v[index];
1090}
1091
1098template <class T>
1099T* FlatVector2D<T>::operator[](std::size_t i)
1100{
1101 assert(isIndexValid(i));
1102
1103 if (m_v.empty()) {
1104 return nullptr;
1105 }
1106
1107 std::size_t index = m_index[i];
1108 return &m_v[index];
1109}
1110
1117template <class T>
1118bool FlatVector2D<T>::isIndexValid(std::size_t i) const
1119{
1120 return (i < size());
1121}
1122
1130template <class T>
1131bool FlatVector2D<T>::isIndexValid(std::size_t i, std::size_t j) const
1132{
1133 if (!isIndexValid(i)) {
1134 return false;
1135 }
1136
1137 return (j < (m_index[i+1] - m_index[i]));
1138}
1139
1140}
1141
1142#endif
Metafunction for generation of a flattened vector of vectors.
const std::size_t * indices() const noexcept
bool isInitialized() const
void clearItems(bool release=true)
T & getItem(std::size_t i, std::size_t j)
bool operator==(const FlatVector2D &rhs) const
void swap(FlatVector2D &other) noexcept
T & rawGetItem(std::size_t k)
const std::vector< T > & vector() const
std::size_t getItemCapacity() const
FlatVector2D(bool initialize=true)
void rawSetItem(std::size_t k, const T &value)
void clear(bool release=true)
void reserve(std::size_t nVectors, std::size_t nItems=0)
std::size_t getItemCount() const
void initialize(const std::vector< std::size_t > &sizes, const T &value=T())
void eraseItem(std::size_t i, std::size_t j)
void erase(std::size_t i)
const T * get(std::size_t i) const
std::size_t capacity() const
std::size_t getBinarySize() const
void setItem(std::size_t i, std::size_t j, const T &value)
void pushBackItem(const T &value)
Output binary stream.
Output binary stream.