ITK  5.4.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 };
154 struct NeverReallocate : AllocateRootPolicy
155 {
156 bool
157 operator()(unsigned int newSize, unsigned int oldSize) const
158 {
159 (void)newSize;
160 (void)oldSize;
161 itkAssertInDebugAndIgnoreInReleaseMacro(newSize == oldSize &&
162 "SetSize is expected to never change the VariableLengthVector size...");
163 return true;
164 }
165 };
185 struct ShrinkToFit : AllocateRootPolicy
186 {
187 bool
188 operator()(unsigned int newSize, unsigned int oldSize) const
189 {
190 return newSize != oldSize;
191 }
192 };
221 struct DontShrinkToFit : AllocateRootPolicy
222 {
223 bool
224 operator()(unsigned int newSize, unsigned int oldSize) const
225 {
226 return newSize > oldSize;
227 }
228 };
249 struct KeepValuesRootPolicy
250 {};
251
273 struct KeepOldValues : KeepValuesRootPolicy
274 {
275 template <typename TValue2>
276 void
277 operator()(unsigned int newSize, unsigned int oldSize, TValue2 * oldBuffer, TValue2 * newBuffer) const
278 {
279 itkAssertInDebugAndIgnoreInReleaseMacro(newBuffer);
280 const size_t nb = std::min(newSize, oldSize);
281 itkAssertInDebugAndIgnoreInReleaseMacro(nb == 0 || (nb > 0 && oldBuffer != nullptr));
282 std::copy_n(oldBuffer, nb, newBuffer);
283 }
284 };
303 struct DumpOldValues : KeepValuesRootPolicy
304 {
305 template <typename TValue2>
306 void
307 operator()(unsigned int itkNotUsed(newSize),
308 unsigned int itkNotUsed(oldSize),
309 TValue2 * itkNotUsed(oldBuffer),
310 TValue2 * itkNotUsed(newBuffer)) const
311 {}
312 };
314
318 using ValueType = TValue;
319 using ComponentType = TValue;
320 using RealValueType = typename NumericTraits<ValueType>::RealType;
321 using Self = VariableLengthVector;
322
324 using ElementIdentifier = unsigned int;
325
332 VariableLengthVector() = default;
333
342 explicit VariableLengthVector(unsigned int length);
343
357 VariableLengthVector(ValueType * datain, unsigned int sz, bool LetArrayManageMemory = false);
358
378 VariableLengthVector(const ValueType * datain, unsigned int sz, bool LetArrayManageMemory = false);
379
399 template <typename T>
400 VariableLengthVector(const VariableLengthVector<T> & v)
401 {
402 m_NumElements = v.Size();
403 m_LetArrayManageMemory = true;
404 if (m_NumElements != 0)
405 {
406 m_Data = this->AllocateElements(m_NumElements);
407 itkAssertInDebugAndIgnoreInReleaseMacro(m_Data != nullptr);
408 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
409 {
410 this->m_Data[i] = static_cast<ValueType>(v[i]);
411 }
412 }
413 else
414 {
415 m_Data = nullptr;
416 }
417 }
428 VariableLengthVector(const VariableLengthVector<TValue> & v);
429
438 void
439 Swap(Self & v) noexcept
440 {
441 itkAssertInDebugAndIgnoreInReleaseMacro(m_LetArrayManageMemory == v.m_LetArrayManageMemory);
442 using std::swap;
443 swap(v.m_Data, m_Data);
444 swap(v.m_NumElements, m_NumElements);
445 }
455 VariableLengthVector(Self && v) noexcept;
456
465 Self &
466 operator=(Self && v) noexcept;
467
484 template <typename TExpr1, typename TExpr2, typename TBinaryOp>
485 VariableLengthVector(VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp> const & rhs);
486
506 template <typename TExpr1, typename TExpr2, typename TBinaryOp>
507 Self &
508 operator=(VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp> const & rhs);
509
513 void
514 Fill(TValue const & v);
515
528 template <typename T>
529 Self &
530 operator=(const VariableLengthVector<T> & v)
531 {
532 // No self assignment test is done. Indeed:
533 // - the operator already resists self assignment through a strong exception
534 // guarantee
535 // - the test becomes a pessimization as we never write
536 // VLV<const TValue> vcref(v.GetDataPointer(), v.GetSize());
537 // ...;
538 // v = vcref;
539 ElementIdentifier const N = v.Size();
540 this->SetSize(N, DontShrinkToFit(), DumpOldValues());
541 for (ElementIdentifier i = 0; i < N; ++i)
542 {
543 this->m_Data[i] = static_cast<ValueType>(v[i]);
544 }
545 return *this;
546 }
564 Self &
565 operator=(const Self & v);
566
575 Self &
576 FastAssign(const Self & v);
577
585 Self &
586 operator=(TValue const & v);
587
589 unsigned int
590 Size() const
591 {
592 return m_NumElements;
593 }
594 unsigned int
595 GetSize() const
596 {
597 return m_NumElements;
598 }
599 unsigned int
600 GetNumberOfElements() const
601 {
602 return m_NumElements;
603 }
607 TValue & operator[](unsigned int i) { return this->m_Data[i]; }
608
610 TValue const & operator[](unsigned int i) const { return this->m_Data[i]; }
611
613 const TValue &
614 GetElement(unsigned int i) const
615 {
616 return m_Data[i];
617 }
618
620 void
621 SetElement(unsigned int i, const TValue & value)
622 {
623 m_Data[i] = value;
624 }
625
659 template <typename TReallocatePolicy, typename TKeepValuesPolicy>
660 void
661 SetSize(unsigned int sz, TReallocatePolicy reallocatePolicy, TKeepValuesPolicy keepValues);
662
673 void
674 SetSize(unsigned int sz, bool destroyExistingData = true)
675 {
676 // Stays compatible with previous code version
677 // And works around the fact C++03 template functions can't have default
678 // arguments on template types.
679 if (destroyExistingData)
680 {
681 SetSize(sz, AlwaysReallocate(), KeepOldValues());
682 }
683 else
684 {
685 SetSize(sz, ShrinkToFit(), KeepOldValues());
686 }
687 }
692 void
693 DestroyExistingData();
694
707 void
708 SetData(TValue * datain, bool LetArrayManageMemory = false);
709
724 void
725 SetData(TValue * datain, unsigned int sz, bool LetArrayManageMemory = false);
726
737 ~VariableLengthVector();
738
753 void
754 Reserve(ElementIdentifier size);
761 TValue *
762 AllocateElements(ElementIdentifier size) const;
763
764 const TValue *
765 GetDataPointer() const
766 {
767 return m_Data;
768 }
769
772 Self &
773 operator--()
774 {
775 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
776 {
777 this->m_Data[i] -= static_cast<ValueType>(1.0);
778 }
779 return *this;
780 }
784 Self &
785 operator++() // prefix operator ++v;
786 {
787 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
788 {
789 this->m_Data[i] += static_cast<ValueType>(1.0);
790 }
791 return *this;
792 }
797 Self
798 operator--(int) // postfix operator v--;
799 {
800 Self tmp(*this);
803 --tmp;
804 return tmp;
805 }
806
808 Self
809 operator++(int) // postfix operator v++;
810 {
811 Self tmp(*this);
814 ++tmp;
815 return tmp;
816 }
817
826 template <typename T>
827 Self &
828 operator-=(const VariableLengthVector<T> & v)
829 {
830 itkAssertInDebugAndIgnoreInReleaseMacro(m_NumElements == v.GetSize());
831 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
832 {
833 m_Data[i] -= static_cast<ValueType>(v[i]);
834 }
835 return *this;
836 }
840 Self &
841 operator-=(TValue s)
842 {
843 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
844 {
845 m_Data[i] -= s;
846 }
847 return *this;
848 }
859 template <typename T>
860 Self &
861 operator+=(const VariableLengthVector<T> & v)
862 {
863 itkAssertInDebugAndIgnoreInReleaseMacro(m_NumElements == v.GetSize());
864 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
865 {
866 m_Data[i] += static_cast<ValueType>(v[i]);
867 }
868 return *this;
869 }
873 Self &
874 operator+=(TValue s)
875 {
876 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
877 {
878 m_Data[i] += s;
879 }
880 return *this;
881 }
893 template <typename TExpr1, typename TExpr2, typename TBinaryOp>
894 Self &
895 operator+=(VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp> const & rhs)
896 {
897 itkAssertInDebugAndIgnoreInReleaseMacro(rhs.Size() == Size());
898 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
899 {
900 m_Data[i] += static_cast<ValueType>(rhs[i]);
901 }
902 return *this;
903 }
915 template <typename TExpr1, typename TExpr2, typename TBinaryOp>
916 Self &
917 operator-=(VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp> const & rhs)
918 {
919 itkAssertInDebugAndIgnoreInReleaseMacro(rhs.Size() == Size());
920 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
921 {
922 m_Data[i] -= static_cast<ValueType>(rhs[i]);
923 }
924 return *this;
925 }
933 template <typename T>
934 Self &
935 operator*=(T s)
936 {
937 const ValueType & sc = static_cast<ValueType>(s);
938 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
939 {
940 m_Data[i] *= sc;
941 }
942 return *this;
943 }
949 Self &
950 operator*=(TValue s)
951 {
952 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
953 {
954 m_Data[i] *= s;
955 }
956 return *this;
957 }
966 template <typename T>
967 Self &
968 operator/=(T s)
969 {
970 const RealValueType sc = s;
971 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
972 {
973 m_Data[i] = static_cast<ValueType>(static_cast<RealValueType>(m_Data[i]) / sc);
974 }
975 return *this;
976 }
983 Self &
984 operator-(); // negation operator
985
986 bool
987 operator==(const Self & v) const;
988
989 ITK_UNEQUAL_OPERATOR_MEMBER_FUNCTION(Self);
990
992 RealValueType
993 GetNorm() const;
994
996 RealValueType
997 GetSquaredNorm() const;
998
1000 bool
1001 IsAProxy() const
1002 {
1003 return !m_LetArrayManageMemory;
1004 }
1005
1006private:
1007 bool m_LetArrayManageMemory{ true }; // if true, the array is responsible
1008 // for memory of data
1009 TValue * m_Data{}; // Array to hold data
1010 ElementIdentifier m_NumElements{ 0 };
1011};
1012
1014namespace mpl
1015{
1025template <typename T>
1026struct IsArray : FalseType
1027{};
1028
1030template <typename T>
1031struct IsArray<itk::VariableLengthVector<T>> : TrueType
1032{};
1033
1034template <typename TExpr1, typename TExpr2, typename TBinaryOp>
1035struct IsArray<VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp>> : TrueType
1036{};
1038} // namespace mpl
1040
1041namespace Details
1042{
1044
1056template <typename TExpr>
1057struct GetType
1058{
1059 using Type = TExpr;
1060
1064 static Type
1065 Load(Type const & v, unsigned int idx)
1066 {
1067 (void)idx;
1068 return v;
1069 }
1070};
1083template <typename TExpr1, typename TExpr2>
1084inline std::enable_if_t<mpl::And<mpl::IsArray<TExpr1>, mpl::IsArray<TExpr2>>::Value, unsigned int>
1085GetSize(TExpr1 const & lhs, TExpr2 const & rhs)
1086{
1087 (void)rhs;
1088 itkAssertInDebugAndIgnoreInReleaseMacro(lhs.Size() == rhs.Size());
1089 return lhs.Size();
1090}
1094
1103template <typename TExpr1, typename TExpr2>
1104inline std::enable_if_t<mpl::And<mpl::IsArray<TExpr1>, mpl::Not<mpl::IsArray<TExpr2>>>::Value, unsigned int>
1105GetSize(TExpr1 const & lhs, TExpr2 const & itkNotUsed(rhs))
1106{
1107 return lhs.Size();
1108}
1109
1119template <typename TExpr1, typename TExpr2>
1120inline std::enable_if_t<mpl::And<mpl::IsArray<TExpr2>, mpl::Not<mpl::IsArray<TExpr1>>>::Value, unsigned int>
1121GetSize(TExpr1 const & itkNotUsed(lhs), TExpr2 const & rhs)
1122{
1123 return rhs.Size();
1124}
1125
1126template <typename T>
1127struct GetType<VariableLengthVector<T>>
1128{
1129 using Type = T;
1130 static Type
1131 Load(VariableLengthVector<T> const & v, unsigned int idx)
1132 {
1133 return v[idx];
1134 }
1135};
1136template <typename TExpr1, typename TExpr2, typename TBinaryOp>
1137struct GetType<VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp>>
1138{
1139 using Type = typename VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp>::ResType;
1140 static Type
1141 Load(VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp> const & v, unsigned int idx)
1142 {
1143 return v[idx];
1144 }
1145};
1147
1148namespace op
1149{
1162template <typename TExpr1, typename TExpr2>
1163struct CanBeAddedOrSubtracted
1164 : mpl::Or<mpl::And<mpl::IsArray<TExpr1>, mpl::IsArray<TExpr2>>,
1165 mpl::And<mpl::IsArray<TExpr1>, mpl::IsNumber<TExpr2>>,
1166 mpl::And<mpl::IsNumber<TExpr1>, mpl::IsArray<TExpr2>>>
1167{};
1168
1180template <typename TExpr1, typename TExpr2>
1181struct CanBeMultiplied
1182 : mpl::Or<mpl::And<mpl::IsArray<TExpr1>, mpl::IsNumber<TExpr2>>,
1183 mpl::And<mpl::IsNumber<TExpr1>, mpl::IsArray<TExpr2>>>
1184{};
1185
1197template <typename TExpr1, typename TExpr2>
1198struct CanBeDivided : mpl::And<mpl::IsArray<TExpr1>, mpl::IsNumber<TExpr2>>
1199{};
1200
1201} // namespace op
1202} // namespace Details
1204
1229template <typename TExpr1, typename TExpr2, typename TBinaryOp>
1230struct VariableLengthVectorExpression
1231{
1232 VariableLengthVectorExpression(TExpr1 const & lhs, TExpr2 const & rhs)
1233 : m_lhs(lhs)
1234 , m_rhs(rhs)
1235 {
1236 // Not necessary actually as end-user/developer is not expected to
1237 // provide new BinaryOperations
1238 static_assert(std::is_base_of_v<Details::op::BinaryOperationConcept, TBinaryOp>,
1239 "The Binary Operation shall inherit from BinaryOperationConcept");
1240 }
1241
1243 unsigned int
1244 Size() const
1245 {
1246 return Details::GetSize(m_lhs, m_rhs);
1247 }
1248
1250 using ResType =
1251 typename mpl::PromoteType<typename Details::GetType<TExpr1>::Type, typename Details::GetType<TExpr2>::Type>::Type;
1253 using RealValueType = typename NumericTraits<ResType>::RealType;
1254
1265 ResType operator[](unsigned int idx) const
1266 {
1267 itkAssertInDebugAndIgnoreInReleaseMacro(idx < Size());
1268 return TBinaryOp::Apply(Details::GetType<TExpr1>::Load(m_lhs, idx), Details::GetType<TExpr2>::Load(m_rhs, idx));
1269 }
1273 RealValueType
1274 GetNorm() const;
1275
1277 RealValueType
1278 GetSquaredNorm() const;
1279
1280private:
1281 TExpr1 const & m_lhs;
1282 TExpr2 const & m_rhs;
1283};
1284
1294template <typename TExpr1, typename TExpr2>
1295inline std::enable_if_t<Details::op::CanBeAddedOrSubtracted<TExpr1, TExpr2>::Value,
1296 VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Plus>>
1297operator+(TExpr1 const & lhs, TExpr2 const & rhs)
1298{
1299 return VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Plus>(lhs, rhs);
1300}
1301
1311template <typename TExpr1, typename TExpr2>
1312inline std::enable_if_t<Details::op::CanBeAddedOrSubtracted<TExpr1, TExpr2>::Value,
1313 VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Sub>>
1314operator-(TExpr1 const & lhs, TExpr2 const & rhs)
1315{
1316 return VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Sub>(lhs, rhs);
1317}
1318
1327template <typename TExpr1, typename TExpr2>
1328inline std::enable_if_t<Details::op::CanBeMultiplied<TExpr1, TExpr2>::Value,
1329 VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Mult>>
1330operator*(TExpr1 const & lhs, TExpr2 const & rhs)
1331{
1332 return VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Mult>(lhs, rhs);
1333}
1334
1342template <typename TExpr1, typename TExpr2>
1343inline std::enable_if_t<Details::op::CanBeDivided<TExpr1, TExpr2>::Value,
1344 VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Div>>
1345operator/(TExpr1 const & lhs, TExpr2 const & rhs)
1346{
1347 return VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Div>(lhs, rhs);
1348}
1349
1353template <typename TExpr1, typename TExpr2, typename TBinaryOp>
1354std::ostream &
1355operator<<(std::ostream & os, VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp> const & v)
1356{
1357 os << '[';
1358 if (v.Size() != 0)
1359 {
1360 os << v[0];
1361 for (unsigned int i = 1, N = v.Size(); i != N; ++i)
1362 {
1363 os << ", " << v[i];
1364 }
1365 }
1366 return os << ']';
1367}
1375template <typename TExpr>
1376inline std::enable_if_t<mpl::IsArray<TExpr>::Value, typename TExpr::RealValueType>
1377GetNorm(TExpr const & v)
1378{
1379 return static_cast<typename TExpr::RealValueType>(std::sqrt(static_cast<double>(GetSquaredNorm(v))));
1380}
1381
1387template <typename TExpr>
1388inline std::enable_if_t<mpl::IsArray<TExpr>::Value, typename TExpr::RealValueType>
1389GetSquaredNorm(TExpr const & v)
1390{
1391 using RealValueType = typename TExpr::RealValueType;
1392 RealValueType sum = 0.0;
1393 for (unsigned int i = 0, N = v.Size(); i < N; ++i)
1394 {
1395 const RealValueType value = v[i];
1396 sum += value * value;
1397 }
1398 return sum;
1399}
1404
1408template <typename TValue>
1409std::ostream &
1410operator<<(std::ostream & os, const VariableLengthVector<TValue> & arr)
1411{
1412 const unsigned int length = arr.Size();
1413 const int last = static_cast<unsigned int>(length) - 1;
1416 os << '[';
1417 for (int i = 0; i < last; ++i)
1418 {
1419 os << arr[i] << ", ";
1420 }
1421 if (length >= 1)
1422 {
1423 os << arr[last];
1424 }
1425 os << ']';
1426 return os;
1427}
1429
1432
1450template <typename T>
1451inline void
1452swap(VariableLengthVector<T> & l_, VariableLengthVector<T> & r_) noexcept
1453{
1454 l_.Swap(r_);
1455}
1457
1459} // namespace itk
1460
1462
1463#ifndef ITK_MANUAL_INSTANTIATION
1464# include "itkVariableLengthVector.hxx"
1465#endif
1466
1467#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)
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:545
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)