ITK  6.0.0
Insight Toolkit
itkVariableLengthVector.h
Go to the documentation of this file.
1/*=========================================================================
2 *
3 * Copyright NumFOCUS
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0.txt
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 *=========================================================================*/
18#ifndef itkVariableLengthVector_h
19#define itkVariableLengthVector_h
20
21#include <cassert>
22#include <algorithm>
23#include <type_traits>
24#include "itkNumericTraits.h"
26#include "itkIsNumber.h"
27#include "itkPromoteType.h"
29
30namespace itk
31{
32
33template <typename TExpr1, typename TExpr2, typename TBinaryOp>
34struct VariableLengthVectorExpression;
35
90template <typename TValue>
91class ITK_TEMPLATE_EXPORT VariableLengthVector
92{
93public:
98
110 struct AllocateRootPolicy
111 {};
112
126 struct AlwaysReallocate : AllocateRootPolicy
127 {
128 bool
129 operator()(unsigned int itkNotUsed(newSize), unsigned int itkNotUsed(oldSize)) const
130 {
131 return true;
132 }
133 };
153 struct NeverReallocate : AllocateRootPolicy
154 {
155 bool
156 operator()([[maybe_unused]] unsigned int newSize, [[maybe_unused]] unsigned int oldSize) const
157 {
158 itkAssertInDebugAndIgnoreInReleaseMacro(newSize == oldSize &&
159 "SetSize is expected to never change the VariableLengthVector size...");
160 return true;
161 }
162 };
182 struct ShrinkToFit : AllocateRootPolicy
183 {
184 bool
185 operator()(unsigned int newSize, unsigned int oldSize) const
186 {
187 return newSize != oldSize;
188 }
189 };
218 struct DontShrinkToFit : AllocateRootPolicy
219 {
220 bool
221 operator()(unsigned int newSize, unsigned int oldSize) const
222 {
223 return newSize > oldSize;
224 }
225 };
246 struct KeepValuesRootPolicy
247 {};
248
270 struct KeepOldValues : KeepValuesRootPolicy
271 {
272 template <typename TValue2>
273 void
274 operator()(unsigned int newSize, unsigned int oldSize, TValue2 * oldBuffer, TValue2 * newBuffer) const
275 {
276 itkAssertInDebugAndIgnoreInReleaseMacro(newBuffer);
277 const size_t nb = std::min(newSize, oldSize);
278 itkAssertInDebugAndIgnoreInReleaseMacro(nb == 0 || (nb > 0 && oldBuffer != nullptr));
279 std::copy_n(oldBuffer, nb, newBuffer);
280 }
281 };
300 struct DumpOldValues : KeepValuesRootPolicy
301 {
302 template <typename TValue2>
303 void
304 operator()(unsigned int itkNotUsed(newSize),
305 unsigned int itkNotUsed(oldSize),
306 TValue2 * itkNotUsed(oldBuffer),
307 TValue2 * itkNotUsed(newBuffer)) const
308 {}
309 };
311
315 using ValueType = TValue;
316 using ComponentType = TValue;
317 using RealValueType = typename NumericTraits<ValueType>::RealType;
318 using Self = VariableLengthVector;
319
321 using ElementIdentifier = unsigned int;
322
329 VariableLengthVector() = default;
330
339 explicit VariableLengthVector(unsigned int length);
340
354 VariableLengthVector(ValueType * datain, unsigned int sz, bool LetArrayManageMemory = false);
355
375 VariableLengthVector(const ValueType * datain, unsigned int sz, bool LetArrayManageMemory = false);
376
396 template <typename T>
397 VariableLengthVector(const VariableLengthVector<T> & v)
398 {
399 m_NumElements = v.Size();
400 m_LetArrayManageMemory = true;
401 if (m_NumElements != 0)
402 {
403 m_Data = this->AllocateElements(m_NumElements);
404 itkAssertInDebugAndIgnoreInReleaseMacro(m_Data != nullptr);
405 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
406 {
407 this->m_Data[i] = static_cast<ValueType>(v[i]);
408 }
409 }
410 else
411 {
412 m_Data = nullptr;
413 }
414 }
425 VariableLengthVector(const VariableLengthVector<TValue> & v);
426
435 void
436 Swap(Self & v) noexcept
437 {
438 itkAssertInDebugAndIgnoreInReleaseMacro(m_LetArrayManageMemory == v.m_LetArrayManageMemory);
439 using std::swap;
440 swap(v.m_Data, m_Data);
441 swap(v.m_NumElements, m_NumElements);
442 }
452 VariableLengthVector(Self && v) noexcept;
453
462 Self &
463 operator=(Self && v) noexcept;
464
481 template <typename TExpr1, typename TExpr2, typename TBinaryOp>
482 VariableLengthVector(const VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp> & rhs);
483
503 template <typename TExpr1, typename TExpr2, typename TBinaryOp>
504 Self &
505 operator=(const VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp> & rhs);
506
510 void
511 Fill(const TValue & v);
512
525 template <typename T>
526 Self &
527 operator=(const VariableLengthVector<T> & v)
528 {
529 // No self assignment test is done. Indeed:
530 // - the operator already resists self assignment through a strong exception
531 // guarantee
532 // - the test becomes a pessimization as we never write
533 // VLV<const TValue> vcref(v.GetDataPointer(), v.GetSize());
534 // ...;
535 // v = vcref;
536 const ElementIdentifier N = v.Size();
537 this->SetSize(N, DontShrinkToFit(), DumpOldValues());
538 for (ElementIdentifier i = 0; i < N; ++i)
539 {
540 this->m_Data[i] = static_cast<ValueType>(v[i]);
541 }
542 return *this;
543 }
561 Self &
562 operator=(const Self & v);
563
572 Self &
573 FastAssign(const Self & v);
574
582 Self &
583 operator=(const TValue & v);
584
586 unsigned int
587 Size() const
588 {
589 return m_NumElements;
590 }
591 unsigned int
592 GetSize() const
593 {
594 return m_NumElements;
595 }
596 unsigned int
597 GetNumberOfElements() const
598 {
599 return m_NumElements;
600 }
604 TValue &
605 operator[](unsigned int i)
606 {
607 return this->m_Data[i];
608 }
609
611 const TValue &
612 operator[](unsigned int i) const
613 {
614 return this->m_Data[i];
615 }
616
618 const TValue &
619 GetElement(unsigned int i) const
620 {
621 return m_Data[i];
622 }
623
625 void
626 SetElement(unsigned int i, const TValue & value)
627 {
628 m_Data[i] = value;
629 }
630
664 template <typename TReallocatePolicy, typename TKeepValuesPolicy>
665 void
666 SetSize(unsigned int sz, TReallocatePolicy reallocatePolicy, TKeepValuesPolicy keepValues);
667
678 void
679 SetSize(unsigned int sz, bool destroyExistingData = true)
680 {
681 // Stays compatible with previous code version
682 // And works around the fact C++03 template functions can't have default
683 // arguments on template types.
684 if (destroyExistingData)
685 {
686 SetSize(sz, AlwaysReallocate(), KeepOldValues());
687 }
688 else
689 {
690 SetSize(sz, ShrinkToFit(), KeepOldValues());
691 }
692 }
697 void
698 DestroyExistingData();
699
712 void
713 SetData(TValue * datain, bool LetArrayManageMemory = false);
714
729 void
730 SetData(TValue * datain, unsigned int sz, bool LetArrayManageMemory = false);
731
742 ~VariableLengthVector();
743
758 void
759 Reserve(ElementIdentifier size);
766 TValue *
767 AllocateElements(ElementIdentifier size) const;
768
769 const TValue *
770 GetDataPointer() const
771 {
772 return m_Data;
773 }
774
777 Self &
778 operator--()
779 {
780 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
781 {
782 this->m_Data[i] -= static_cast<ValueType>(1.0);
783 }
784 return *this;
785 }
789 Self &
790 operator++() // prefix operator ++v;
791 {
792 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
793 {
794 this->m_Data[i] += static_cast<ValueType>(1.0);
795 }
796 return *this;
797 }
802 Self
803 operator--(int) // postfix operator v--;
804 {
805 Self tmp(*this);
808 --tmp;
809 return tmp;
810 }
811
813 Self
814 operator++(int) // postfix operator v++;
815 {
816 Self tmp(*this);
819 ++tmp;
820 return tmp;
821 }
822
831 template <typename T>
832 Self &
833 operator-=(const VariableLengthVector<T> & v)
834 {
835 itkAssertInDebugAndIgnoreInReleaseMacro(m_NumElements == v.GetSize());
836 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
837 {
838 m_Data[i] -= static_cast<ValueType>(v[i]);
839 }
840 return *this;
841 }
845 Self &
846 operator-=(TValue s)
847 {
848 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
849 {
850 m_Data[i] -= s;
851 }
852 return *this;
853 }
864 template <typename T>
865 Self &
866 operator+=(const VariableLengthVector<T> & v)
867 {
868 itkAssertInDebugAndIgnoreInReleaseMacro(m_NumElements == v.GetSize());
869 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
870 {
871 m_Data[i] += static_cast<ValueType>(v[i]);
872 }
873 return *this;
874 }
878 Self &
879 operator+=(TValue s)
880 {
881 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
882 {
883 m_Data[i] += s;
884 }
885 return *this;
886 }
898 template <typename TExpr1, typename TExpr2, typename TBinaryOp>
899 Self &
900 operator+=(const VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp> & rhs)
901 {
902 itkAssertInDebugAndIgnoreInReleaseMacro(rhs.Size() == Size());
903 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
904 {
905 m_Data[i] += static_cast<ValueType>(rhs[i]);
906 }
907 return *this;
908 }
920 template <typename TExpr1, typename TExpr2, typename TBinaryOp>
921 Self &
922 operator-=(const VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp> & rhs)
923 {
924 itkAssertInDebugAndIgnoreInReleaseMacro(rhs.Size() == Size());
925 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
926 {
927 m_Data[i] -= static_cast<ValueType>(rhs[i]);
928 }
929 return *this;
930 }
938 template <typename T>
939 Self &
940 operator*=(T s)
941 {
942 const ValueType & sc = static_cast<ValueType>(s);
943 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
944 {
945 m_Data[i] *= sc;
946 }
947 return *this;
948 }
954 Self &
955 operator*=(TValue s)
956 {
957 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
958 {
959 m_Data[i] *= s;
960 }
961 return *this;
962 }
971 template <typename T>
972 Self &
973 operator/=(T s)
974 {
975 const RealValueType sc = s;
976 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
977 {
978 m_Data[i] = static_cast<ValueType>(static_cast<RealValueType>(m_Data[i]) / sc);
979 }
980 return *this;
981 }
988 Self &
989 operator-(); // negation operator
990
991 bool
992 operator==(const Self & v) const;
993
994 ITK_UNEQUAL_OPERATOR_MEMBER_FUNCTION(Self);
995
997 RealValueType
998 GetNorm() const;
999
1001 RealValueType
1002 GetSquaredNorm() const;
1003
1005 bool
1006 IsAProxy() const
1007 {
1008 return !m_LetArrayManageMemory;
1009 }
1010
1011private:
1012 bool m_LetArrayManageMemory{ true }; // if true, the array is responsible
1013 // for memory of data
1014 TValue * m_Data{}; // Array to hold data
1015 ElementIdentifier m_NumElements{ 0 };
1016};
1017
1019namespace mpl
1020{
1030template <typename T>
1031struct IsArray : FalseType
1032{};
1033
1035template <typename T>
1036struct IsArray<itk::VariableLengthVector<T>> : TrueType
1037{};
1038
1039template <typename TExpr1, typename TExpr2, typename TBinaryOp>
1040struct IsArray<VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp>> : TrueType
1041{};
1043} // namespace mpl
1045
1046namespace Details
1047{
1049
1061template <typename TExpr>
1062struct GetType
1063{
1064 using Type = TExpr;
1065
1069 static Type
1070 Load(const Type & v, unsigned int itkNotUsed(idx))
1071 {
1072 return v;
1073 }
1074};
1087template <typename TExpr1, typename TExpr2>
1088inline std::enable_if_t<mpl::And<mpl::IsArray<TExpr1>, mpl::IsArray<TExpr2>>::Value, unsigned int>
1089GetSize(const TExpr1 & lhs, [[maybe_unused]] const TExpr2 & rhs)
1090{
1091 itkAssertInDebugAndIgnoreInReleaseMacro(lhs.Size() == rhs.Size());
1092 return lhs.Size();
1093}
1097
1106template <typename TExpr1, typename TExpr2>
1107inline std::enable_if_t<mpl::And<mpl::IsArray<TExpr1>, mpl::Not<mpl::IsArray<TExpr2>>>::Value, unsigned int>
1108GetSize(const TExpr1 & lhs, const TExpr2 & itkNotUsed(rhs))
1109{
1110 return lhs.Size();
1111}
1112
1122template <typename TExpr1, typename TExpr2>
1123inline std::enable_if_t<mpl::And<mpl::IsArray<TExpr2>, mpl::Not<mpl::IsArray<TExpr1>>>::Value, unsigned int>
1124GetSize(const TExpr1 & itkNotUsed(lhs), const TExpr2 & rhs)
1125{
1126 return rhs.Size();
1127}
1128
1129template <typename T>
1130struct GetType<VariableLengthVector<T>>
1131{
1132 using Type = T;
1133 static Type
1134 Load(const VariableLengthVector<T> & v, unsigned int idx)
1135 {
1136 return v[idx];
1137 }
1138};
1139template <typename TExpr1, typename TExpr2, typename TBinaryOp>
1140struct GetType<VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp>>
1141{
1142 using Type = typename VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp>::ResType;
1143 static Type
1144 Load(const VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp> & v, unsigned int idx)
1145 {
1146 return v[idx];
1147 }
1148};
1150
1151namespace op
1152{
1165template <typename TExpr1, typename TExpr2>
1166struct CanBeAddedOrSubtracted
1167 : mpl::Or<mpl::And<mpl::IsArray<TExpr1>, mpl::IsArray<TExpr2>>,
1168 mpl::And<mpl::IsArray<TExpr1>, mpl::IsNumber<TExpr2>>,
1169 mpl::And<mpl::IsNumber<TExpr1>, mpl::IsArray<TExpr2>>>
1170{};
1171
1183template <typename TExpr1, typename TExpr2>
1184struct CanBeMultiplied
1185 : mpl::Or<mpl::And<mpl::IsArray<TExpr1>, mpl::IsNumber<TExpr2>>,
1186 mpl::And<mpl::IsNumber<TExpr1>, mpl::IsArray<TExpr2>>>
1187{};
1188
1200template <typename TExpr1, typename TExpr2>
1201struct CanBeDivided : mpl::And<mpl::IsArray<TExpr1>, mpl::IsNumber<TExpr2>>
1202{};
1203
1204} // namespace op
1205} // namespace Details
1207
1232template <typename TExpr1, typename TExpr2, typename TBinaryOp>
1233struct VariableLengthVectorExpression
1234{
1235 VariableLengthVectorExpression(const TExpr1 & lhs, const TExpr2 & rhs)
1236 : m_lhs(lhs)
1237 , m_rhs(rhs)
1238 {
1239 // Not necessary actually as end-user/developer is not expected to
1240 // provide new BinaryOperations
1241 static_assert(std::is_base_of_v<Details::op::BinaryOperationConcept, TBinaryOp>,
1242 "The Binary Operation shall inherit from BinaryOperationConcept");
1243 }
1244
1246 unsigned int
1247 Size() const
1248 {
1249 return Details::GetSize(m_lhs, m_rhs);
1250 }
1251
1253 using ResType =
1254 typename mpl::PromoteType<typename Details::GetType<TExpr1>::Type, typename Details::GetType<TExpr2>::Type>::Type;
1256 using RealValueType = typename NumericTraits<ResType>::RealType;
1257
1268 ResType
1269 operator[](unsigned int idx) const
1270 {
1271 itkAssertInDebugAndIgnoreInReleaseMacro(idx < Size());
1272 return TBinaryOp::Apply(Details::GetType<TExpr1>::Load(m_lhs, idx), Details::GetType<TExpr2>::Load(m_rhs, idx));
1273 }
1277 RealValueType
1278 GetNorm() const;
1279
1281 RealValueType
1282 GetSquaredNorm() const;
1283
1284private:
1285 const TExpr1 & m_lhs;
1286 const TExpr2 & m_rhs;
1287};
1288
1298template <typename TExpr1, typename TExpr2>
1299inline std::enable_if_t<Details::op::CanBeAddedOrSubtracted<TExpr1, TExpr2>::Value,
1300 VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Plus>>
1301operator+(const TExpr1 & lhs, const TExpr2 & rhs)
1302{
1303 return VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Plus>(lhs, rhs);
1304}
1305
1315template <typename TExpr1, typename TExpr2>
1316inline std::enable_if_t<Details::op::CanBeAddedOrSubtracted<TExpr1, TExpr2>::Value,
1317 VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Sub>>
1318operator-(const TExpr1 & lhs, const TExpr2 & rhs)
1319{
1320 return VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Sub>(lhs, rhs);
1321}
1322
1331template <typename TExpr1, typename TExpr2>
1332inline std::enable_if_t<Details::op::CanBeMultiplied<TExpr1, TExpr2>::Value,
1333 VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Mult>>
1334operator*(const TExpr1 & lhs, const TExpr2 & rhs)
1335{
1336 return VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Mult>(lhs, rhs);
1337}
1338
1346template <typename TExpr1, typename TExpr2>
1347inline std::enable_if_t<Details::op::CanBeDivided<TExpr1, TExpr2>::Value,
1348 VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Div>>
1349operator/(const TExpr1 & lhs, const TExpr2 & rhs)
1350{
1351 return VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Div>(lhs, rhs);
1352}
1353
1357template <typename TExpr1, typename TExpr2, typename TBinaryOp>
1358std::ostream &
1359operator<<(std::ostream & os, const VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp> & v)
1360{
1361 os << '[';
1362 if (v.Size() != 0)
1363 {
1364 os << v[0];
1365 for (unsigned int i = 1, N = v.Size(); i != N; ++i)
1366 {
1367 os << ", " << v[i];
1368 }
1369 }
1370 return os << ']';
1371}
1379template <typename TExpr>
1380inline std::enable_if_t<mpl::IsArray<TExpr>::Value, typename TExpr::RealValueType>
1381GetNorm(const TExpr & v)
1382{
1383 return static_cast<typename TExpr::RealValueType>(std::sqrt(static_cast<double>(GetSquaredNorm(v))));
1384}
1385
1391template <typename TExpr>
1392inline std::enable_if_t<mpl::IsArray<TExpr>::Value, typename TExpr::RealValueType>
1393GetSquaredNorm(const TExpr & v)
1394{
1395 using RealValueType = typename TExpr::RealValueType;
1396 RealValueType sum = 0.0;
1397 for (unsigned int i = 0, N = v.Size(); i < N; ++i)
1398 {
1399 const RealValueType value = v[i];
1400 sum += value * value;
1401 }
1402 return sum;
1403}
1408
1412template <typename TValue>
1413std::ostream &
1414operator<<(std::ostream & os, const VariableLengthVector<TValue> & arr)
1415{
1416 const unsigned int length = arr.Size();
1417 const int last = static_cast<unsigned int>(length) - 1;
1420 os << '[';
1421 for (int i = 0; i < last; ++i)
1422 {
1423 os << arr[i] << ", ";
1424 }
1425 if (length >= 1)
1426 {
1427 os << arr[last];
1428 }
1429 os << ']';
1430 return os;
1431}
1433
1436
1454template <typename T>
1455inline void
1456swap(VariableLengthVector<T> & l_, VariableLengthVector<T> & r_) noexcept
1457{
1458 l_.Swap(r_);
1459}
1461
1463} // namespace itk
1464
1466
1467#ifndef ITK_MANUAL_INSTANTIATION
1468# include "itkVariableLengthVector.hxx"
1469#endif
1470
1471#endif
Pixel-wise addition of two images.
The "itk" namespace contains all Insight Segmentation and Registration Toolkit (ITK) classes....
void swap(Array< T > &a, Array< T > &b) noexcept
Definition: itkArray.h:242
ITKCommon_EXPORT std::ostream & operator<<(std::ostream &out, typename AnatomicalOrientation::CoordinateEnum value)
CovariantVector< T, VVectorDimension > operator*(const T &scalar, const CovariantVector< T, VVectorDimension > &v)
ConstNeighborhoodIterator< TImage > operator-(const ConstNeighborhoodIterator< TImage > &it, const typename ConstNeighborhoodIterator< TImage >::OffsetType &ind)
bool operator==(const Index< VDimension > &one, const Index< VDimension > &two)
Definition: itkIndex.h:552
ConstNeighborhoodIterator< TImage > operator+(const ConstNeighborhoodIterator< TImage > &it, const typename ConstNeighborhoodIterator< TImage >::OffsetType &ind)