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(VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp> const & rhs);
483
503 template <typename TExpr1, typename TExpr2, typename TBinaryOp>
504 Self &
505 operator=(VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp> const & rhs);
506
510 void
511 Fill(TValue const & 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 ElementIdentifier const 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=(TValue const & 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 & operator[](unsigned int i) { return this->m_Data[i]; }
605
607 TValue const & operator[](unsigned int i) const { return this->m_Data[i]; }
608
610 const TValue &
611 GetElement(unsigned int i) const
612 {
613 return m_Data[i];
614 }
615
617 void
618 SetElement(unsigned int i, const TValue & value)
619 {
620 m_Data[i] = value;
621 }
622
656 template <typename TReallocatePolicy, typename TKeepValuesPolicy>
657 void
658 SetSize(unsigned int sz, TReallocatePolicy reallocatePolicy, TKeepValuesPolicy keepValues);
659
670 void
671 SetSize(unsigned int sz, bool destroyExistingData = true)
672 {
673 // Stays compatible with previous code version
674 // And works around the fact C++03 template functions can't have default
675 // arguments on template types.
676 if (destroyExistingData)
677 {
678 SetSize(sz, AlwaysReallocate(), KeepOldValues());
679 }
680 else
681 {
682 SetSize(sz, ShrinkToFit(), KeepOldValues());
683 }
684 }
689 void
690 DestroyExistingData();
691
704 void
705 SetData(TValue * datain, bool LetArrayManageMemory = false);
706
721 void
722 SetData(TValue * datain, unsigned int sz, bool LetArrayManageMemory = false);
723
734 ~VariableLengthVector();
735
750 void
751 Reserve(ElementIdentifier size);
758 TValue *
759 AllocateElements(ElementIdentifier size) const;
760
761 const TValue *
762 GetDataPointer() const
763 {
764 return m_Data;
765 }
766
769 Self &
770 operator--()
771 {
772 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
773 {
774 this->m_Data[i] -= static_cast<ValueType>(1.0);
775 }
776 return *this;
777 }
781 Self &
782 operator++() // prefix operator ++v;
783 {
784 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
785 {
786 this->m_Data[i] += static_cast<ValueType>(1.0);
787 }
788 return *this;
789 }
794 Self
795 operator--(int) // postfix operator v--;
796 {
797 Self tmp(*this);
800 --tmp;
801 return tmp;
802 }
803
805 Self
806 operator++(int) // postfix operator v++;
807 {
808 Self tmp(*this);
811 ++tmp;
812 return tmp;
813 }
814
823 template <typename T>
824 Self &
825 operator-=(const VariableLengthVector<T> & v)
826 {
827 itkAssertInDebugAndIgnoreInReleaseMacro(m_NumElements == v.GetSize());
828 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
829 {
830 m_Data[i] -= static_cast<ValueType>(v[i]);
831 }
832 return *this;
833 }
837 Self &
838 operator-=(TValue s)
839 {
840 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
841 {
842 m_Data[i] -= s;
843 }
844 return *this;
845 }
856 template <typename T>
857 Self &
858 operator+=(const VariableLengthVector<T> & v)
859 {
860 itkAssertInDebugAndIgnoreInReleaseMacro(m_NumElements == v.GetSize());
861 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
862 {
863 m_Data[i] += static_cast<ValueType>(v[i]);
864 }
865 return *this;
866 }
870 Self &
871 operator+=(TValue s)
872 {
873 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
874 {
875 m_Data[i] += s;
876 }
877 return *this;
878 }
890 template <typename TExpr1, typename TExpr2, typename TBinaryOp>
891 Self &
892 operator+=(VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp> const & rhs)
893 {
894 itkAssertInDebugAndIgnoreInReleaseMacro(rhs.Size() == Size());
895 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
896 {
897 m_Data[i] += static_cast<ValueType>(rhs[i]);
898 }
899 return *this;
900 }
912 template <typename TExpr1, typename TExpr2, typename TBinaryOp>
913 Self &
914 operator-=(VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp> const & rhs)
915 {
916 itkAssertInDebugAndIgnoreInReleaseMacro(rhs.Size() == Size());
917 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
918 {
919 m_Data[i] -= static_cast<ValueType>(rhs[i]);
920 }
921 return *this;
922 }
930 template <typename T>
931 Self &
932 operator*=(T s)
933 {
934 const ValueType & sc = static_cast<ValueType>(s);
935 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
936 {
937 m_Data[i] *= sc;
938 }
939 return *this;
940 }
946 Self &
947 operator*=(TValue s)
948 {
949 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
950 {
951 m_Data[i] *= s;
952 }
953 return *this;
954 }
963 template <typename T>
964 Self &
965 operator/=(T s)
966 {
967 const RealValueType sc = s;
968 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
969 {
970 m_Data[i] = static_cast<ValueType>(static_cast<RealValueType>(m_Data[i]) / sc);
971 }
972 return *this;
973 }
980 Self &
981 operator-(); // negation operator
982
983 bool
984 operator==(const Self & v) const;
985
986 ITK_UNEQUAL_OPERATOR_MEMBER_FUNCTION(Self);
987
989 RealValueType
990 GetNorm() const;
991
993 RealValueType
994 GetSquaredNorm() const;
995
997 bool
998 IsAProxy() const
999 {
1000 return !m_LetArrayManageMemory;
1001 }
1002
1003private:
1004 bool m_LetArrayManageMemory{ true }; // if true, the array is responsible
1005 // for memory of data
1006 TValue * m_Data{}; // Array to hold data
1007 ElementIdentifier m_NumElements{ 0 };
1008};
1009
1011namespace mpl
1012{
1022template <typename T>
1023struct IsArray : FalseType
1024{};
1025
1027template <typename T>
1028struct IsArray<itk::VariableLengthVector<T>> : TrueType
1029{};
1030
1031template <typename TExpr1, typename TExpr2, typename TBinaryOp>
1032struct IsArray<VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp>> : TrueType
1033{};
1035} // namespace mpl
1037
1038namespace Details
1039{
1041
1053template <typename TExpr>
1054struct GetType
1055{
1056 using Type = TExpr;
1057
1061 static Type
1062 Load(Type const & v, unsigned int itkNotUsed(idx))
1063 {
1064 return v;
1065 }
1066};
1079template <typename TExpr1, typename TExpr2>
1080inline std::enable_if_t<mpl::And<mpl::IsArray<TExpr1>, mpl::IsArray<TExpr2>>::Value, unsigned int>
1081GetSize(TExpr1 const & lhs, [[maybe_unused]] TExpr2 const & rhs)
1082{
1083 itkAssertInDebugAndIgnoreInReleaseMacro(lhs.Size() == rhs.Size());
1084 return lhs.Size();
1085}
1089
1098template <typename TExpr1, typename TExpr2>
1099inline std::enable_if_t<mpl::And<mpl::IsArray<TExpr1>, mpl::Not<mpl::IsArray<TExpr2>>>::Value, unsigned int>
1100GetSize(TExpr1 const & lhs, TExpr2 const & itkNotUsed(rhs))
1101{
1102 return lhs.Size();
1103}
1104
1114template <typename TExpr1, typename TExpr2>
1115inline std::enable_if_t<mpl::And<mpl::IsArray<TExpr2>, mpl::Not<mpl::IsArray<TExpr1>>>::Value, unsigned int>
1116GetSize(TExpr1 const & itkNotUsed(lhs), TExpr2 const & rhs)
1117{
1118 return rhs.Size();
1119}
1120
1121template <typename T>
1122struct GetType<VariableLengthVector<T>>
1123{
1124 using Type = T;
1125 static Type
1126 Load(VariableLengthVector<T> const & v, unsigned int idx)
1127 {
1128 return v[idx];
1129 }
1130};
1131template <typename TExpr1, typename TExpr2, typename TBinaryOp>
1132struct GetType<VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp>>
1133{
1134 using Type = typename VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp>::ResType;
1135 static Type
1136 Load(VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp> const & v, unsigned int idx)
1137 {
1138 return v[idx];
1139 }
1140};
1142
1143namespace op
1144{
1157template <typename TExpr1, typename TExpr2>
1158struct CanBeAddedOrSubtracted
1159 : mpl::Or<mpl::And<mpl::IsArray<TExpr1>, mpl::IsArray<TExpr2>>,
1160 mpl::And<mpl::IsArray<TExpr1>, mpl::IsNumber<TExpr2>>,
1161 mpl::And<mpl::IsNumber<TExpr1>, mpl::IsArray<TExpr2>>>
1162{};
1163
1175template <typename TExpr1, typename TExpr2>
1176struct CanBeMultiplied
1177 : mpl::Or<mpl::And<mpl::IsArray<TExpr1>, mpl::IsNumber<TExpr2>>,
1178 mpl::And<mpl::IsNumber<TExpr1>, mpl::IsArray<TExpr2>>>
1179{};
1180
1192template <typename TExpr1, typename TExpr2>
1193struct CanBeDivided : mpl::And<mpl::IsArray<TExpr1>, mpl::IsNumber<TExpr2>>
1194{};
1195
1196} // namespace op
1197} // namespace Details
1199
1224template <typename TExpr1, typename TExpr2, typename TBinaryOp>
1225struct VariableLengthVectorExpression
1226{
1227 VariableLengthVectorExpression(TExpr1 const & lhs, TExpr2 const & rhs)
1228 : m_lhs(lhs)
1229 , m_rhs(rhs)
1230 {
1231 // Not necessary actually as end-user/developer is not expected to
1232 // provide new BinaryOperations
1233 static_assert(std::is_base_of_v<Details::op::BinaryOperationConcept, TBinaryOp>,
1234 "The Binary Operation shall inherit from BinaryOperationConcept");
1235 }
1236
1238 unsigned int
1239 Size() const
1240 {
1241 return Details::GetSize(m_lhs, m_rhs);
1242 }
1243
1245 using ResType =
1246 typename mpl::PromoteType<typename Details::GetType<TExpr1>::Type, typename Details::GetType<TExpr2>::Type>::Type;
1248 using RealValueType = typename NumericTraits<ResType>::RealType;
1249
1260 ResType operator[](unsigned int idx) const
1261 {
1262 itkAssertInDebugAndIgnoreInReleaseMacro(idx < Size());
1263 return TBinaryOp::Apply(Details::GetType<TExpr1>::Load(m_lhs, idx), Details::GetType<TExpr2>::Load(m_rhs, idx));
1264 }
1268 RealValueType
1269 GetNorm() const;
1270
1272 RealValueType
1273 GetSquaredNorm() const;
1274
1275private:
1276 TExpr1 const & m_lhs;
1277 TExpr2 const & m_rhs;
1278};
1279
1289template <typename TExpr1, typename TExpr2>
1290inline std::enable_if_t<Details::op::CanBeAddedOrSubtracted<TExpr1, TExpr2>::Value,
1291 VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Plus>>
1292operator+(TExpr1 const & lhs, TExpr2 const & rhs)
1293{
1294 return VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Plus>(lhs, rhs);
1295}
1296
1306template <typename TExpr1, typename TExpr2>
1307inline std::enable_if_t<Details::op::CanBeAddedOrSubtracted<TExpr1, TExpr2>::Value,
1308 VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Sub>>
1309operator-(TExpr1 const & lhs, TExpr2 const & rhs)
1310{
1311 return VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Sub>(lhs, rhs);
1312}
1313
1322template <typename TExpr1, typename TExpr2>
1323inline std::enable_if_t<Details::op::CanBeMultiplied<TExpr1, TExpr2>::Value,
1324 VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Mult>>
1325operator*(TExpr1 const & lhs, TExpr2 const & rhs)
1326{
1327 return VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Mult>(lhs, rhs);
1328}
1329
1337template <typename TExpr1, typename TExpr2>
1338inline std::enable_if_t<Details::op::CanBeDivided<TExpr1, TExpr2>::Value,
1339 VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Div>>
1340operator/(TExpr1 const & lhs, TExpr2 const & rhs)
1341{
1342 return VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Div>(lhs, rhs);
1343}
1344
1348template <typename TExpr1, typename TExpr2, typename TBinaryOp>
1349std::ostream &
1350operator<<(std::ostream & os, VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp> const & v)
1351{
1352 os << '[';
1353 if (v.Size() != 0)
1354 {
1355 os << v[0];
1356 for (unsigned int i = 1, N = v.Size(); i != N; ++i)
1357 {
1358 os << ", " << v[i];
1359 }
1360 }
1361 return os << ']';
1362}
1370template <typename TExpr>
1371inline std::enable_if_t<mpl::IsArray<TExpr>::Value, typename TExpr::RealValueType>
1372GetNorm(TExpr const & v)
1373{
1374 return static_cast<typename TExpr::RealValueType>(std::sqrt(static_cast<double>(GetSquaredNorm(v))));
1375}
1376
1382template <typename TExpr>
1383inline std::enable_if_t<mpl::IsArray<TExpr>::Value, typename TExpr::RealValueType>
1384GetSquaredNorm(TExpr const & v)
1385{
1386 using RealValueType = typename TExpr::RealValueType;
1387 RealValueType sum = 0.0;
1388 for (unsigned int i = 0, N = v.Size(); i < N; ++i)
1389 {
1390 const RealValueType value = v[i];
1391 sum += value * value;
1392 }
1393 return sum;
1394}
1399
1403template <typename TValue>
1404std::ostream &
1405operator<<(std::ostream & os, const VariableLengthVector<TValue> & arr)
1406{
1407 const unsigned int length = arr.Size();
1408 const int last = static_cast<unsigned int>(length) - 1;
1411 os << '[';
1412 for (int i = 0; i < last; ++i)
1413 {
1414 os << arr[i] << ", ";
1415 }
1416 if (length >= 1)
1417 {
1418 os << arr[last];
1419 }
1420 os << ']';
1421 return os;
1422}
1424
1427
1445template <typename T>
1446inline void
1447swap(VariableLengthVector<T> & l_, VariableLengthVector<T> & r_) noexcept
1448{
1449 l_.Swap(r_);
1450}
1452
1454} // namespace itk
1455
1457
1458#ifndef ITK_MANUAL_INSTANTIATION
1459# include "itkVariableLengthVector.hxx"
1460#endif
1461
1462#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
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:543
std::ostream & operator<<(std::ostream &os, const Array< TValue > &arr)
Definition: itkArray.h:216
ConstNeighborhoodIterator< TImage > operator+(const ConstNeighborhoodIterator< TImage > &it, const typename ConstNeighborhoodIterator< TImage >::OffsetType &ind)