ITK 6.0.0
Insight Toolkit
 
Loading...
Searching...
No Matches
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 };
134
152 struct NeverReallocate : AllocateRootPolicy
153 {
154 bool
155 operator()([[maybe_unused]] unsigned int newSize, [[maybe_unused]] unsigned int oldSize) const
156 {
157 itkAssertInDebugAndIgnoreInReleaseMacro(newSize == oldSize &&
158 "SetSize is expected to never change the VariableLengthVector size...");
159 return true;
160 }
161 };
162
180 struct ShrinkToFit : AllocateRootPolicy
181 {
182 bool
183 operator()(unsigned int newSize, unsigned int oldSize) const
184 {
185 return newSize != oldSize;
186 }
187 };
188
215 struct DontShrinkToFit : AllocateRootPolicy
216 {
217 bool
218 operator()(unsigned int newSize, unsigned int oldSize) const
219 {
220 return newSize > oldSize;
221 }
222 };
223
242 struct KeepValuesRootPolicy
243 {};
244
266 struct KeepOldValues : KeepValuesRootPolicy
267 {
268 template <typename TValue2>
269 void
270 operator()(unsigned int newSize, unsigned int oldSize, TValue2 * oldBuffer, TValue2 * newBuffer) const
271 {
272 itkAssertInDebugAndIgnoreInReleaseMacro(newBuffer);
273 const size_t nb = std::min(newSize, oldSize);
274 itkAssertInDebugAndIgnoreInReleaseMacro(nb == 0 || (nb > 0 && oldBuffer != nullptr));
275 std::copy_n(oldBuffer, nb, newBuffer);
276 }
277 };
278
295 struct DumpOldValues : KeepValuesRootPolicy
296 {
297 template <typename TValue2>
298 void
299 operator()(unsigned int itkNotUsed(newSize),
300 unsigned int itkNotUsed(oldSize),
301 TValue2 * itkNotUsed(oldBuffer),
302 TValue2 * itkNotUsed(newBuffer)) const
303 {}
304 };
306
307
309 using ValueType = TValue;
310 using ComponentType = TValue;
311 using RealValueType = typename NumericTraits<ValueType>::RealType;
312 using Self = VariableLengthVector;
313
315 using ElementIdentifier = unsigned int;
316
323 VariableLengthVector() = default;
324
333 explicit VariableLengthVector(unsigned int length);
334
348 VariableLengthVector(ValueType * datain, unsigned int sz, bool LetArrayManageMemory = false);
349
369 VariableLengthVector(const ValueType * datain, unsigned int sz, bool LetArrayManageMemory = false);
370
390 template <typename T>
391 VariableLengthVector(const VariableLengthVector<T> & v)
392 : m_NumElements(v.Size())
393 {
394 if (m_NumElements != 0)
395 {
396 m_Data = this->AllocateElements(m_NumElements);
397 itkAssertInDebugAndIgnoreInReleaseMacro(m_Data != nullptr);
398 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
399 {
400 this->m_Data[i] = static_cast<ValueType>(v[i]);
401 }
402 }
403 else
404 {
405 m_Data = nullptr;
406 }
407 }
408
417 VariableLengthVector(const VariableLengthVector<TValue> & v);
418
427 void
428 Swap(Self & v) noexcept
429 {
430 itkAssertInDebugAndIgnoreInReleaseMacro(m_LetArrayManageMemory == v.m_LetArrayManageMemory);
431 using std::swap;
432 swap(v.m_Data, m_Data);
433 swap(v.m_NumElements, m_NumElements);
434 }
435
443 VariableLengthVector(Self && v) noexcept;
444
453 Self &
454 operator=(Self && v) noexcept;
455
472 template <typename TExpr1, typename TExpr2, typename TBinaryOp>
473 VariableLengthVector(const VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp> & rhs);
474
494 template <typename TExpr1, typename TExpr2, typename TBinaryOp>
495 Self &
496 operator=(const VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp> & rhs);
497
501 void
502 Fill(const TValue & v);
503
516 template <typename T>
517 Self &
518 operator=(const VariableLengthVector<T> & v)
519 {
520 // No self assignment test is done. Indeed:
521 // - the operator already resists self assignment through a strong exception
522 // guarantee
523 // - the test becomes a pessimization as we never write
524 // VLV<const TValue> vcref(v.GetDataPointer(), v.GetSize());
525 // ...;
526 // v = vcref;
527 const ElementIdentifier N = v.Size();
528 this->SetSize(N, DontShrinkToFit(), DumpOldValues());
529 for (ElementIdentifier i = 0; i < N; ++i)
530 {
531 this->m_Data[i] = static_cast<ValueType>(v[i]);
532 }
533 return *this;
534 }
535
551 Self &
552 operator=(const Self & v);
553
562 Self &
563 FastAssign(const Self & v);
564
572 Self &
573 operator=(const TValue & v);
574
577 [[nodiscard]] unsigned int
578 Size() const
579 {
580 return m_NumElements;
581 }
582 [[nodiscard]] unsigned int
583 GetSize() const
584 {
585 return m_NumElements;
586 }
587 [[nodiscard]] unsigned int
588 GetNumberOfElements() const
589 {
590 return m_NumElements;
591 }
594 TValue &
595 operator[](unsigned int i)
596 {
597 return this->m_Data[i];
598 }
599
601 const TValue &
602 operator[](unsigned int i) const
603 {
604 return this->m_Data[i];
605 }
606
608 [[nodiscard]] const TValue &
609 GetElement(unsigned int i) const
610 {
611 return m_Data[i];
612 }
613
615 void
616 SetElement(unsigned int i, const TValue & value)
617 {
618 m_Data[i] = value;
619 }
620
654 template <typename TReallocatePolicy, typename TKeepValuesPolicy>
655 void
656 SetSize(unsigned int sz, TReallocatePolicy reallocatePolicy, TKeepValuesPolicy keepValues);
657
668 void
669 SetSize(unsigned int sz, bool destroyExistingData = true)
670 {
671 // Stays compatible with previous code version
672 // And works around the fact C++03 template functions can't have default
673 // arguments on template types.
674 if (destroyExistingData)
675 {
676 SetSize(sz, AlwaysReallocate(), KeepOldValues());
677 }
678 else
679 {
680 SetSize(sz, ShrinkToFit(), KeepOldValues());
681 }
682 }
683
686 void
687 DestroyExistingData();
688
701 void
702 SetData(TValue * datain, bool LetArrayManageMemory = false);
703
718 void
719 SetData(TValue * datain, unsigned int sz, bool LetArrayManageMemory = false);
720
731 ~VariableLengthVector();
732
747 void
748 Reserve(ElementIdentifier size);
749
754 [[nodiscard]] TValue *
755 AllocateElements(ElementIdentifier size) const;
756
757 [[nodiscard]] const TValue *
758 GetDataPointer() const
759 {
760 return m_Data;
761 }
762
765 Self &
766 operator--()
767 {
768 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
769 {
770 this->m_Data[i] -= static_cast<ValueType>(1.0);
771 }
772 return *this;
773 }
774
776 Self &
777 operator++() // prefix operator ++v;
778 {
779 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
780 {
781 this->m_Data[i] += static_cast<ValueType>(1.0);
782 }
783 return *this;
784 }
785
788 Self
789 operator--(int) // postfix operator v--;
790 {
791 Self tmp(*this);
792
793 --tmp;
794 return tmp;
795 }
796
798 Self
799 operator++(int) // postfix operator v++;
800 {
801 Self tmp(*this);
802
803 ++tmp;
804 return tmp;
805 }
806
815 template <typename T>
816 Self &
817 operator-=(const VariableLengthVector<T> & v)
818 {
819 itkAssertInDebugAndIgnoreInReleaseMacro(m_NumElements == v.GetSize());
820 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
821 {
822 m_Data[i] -= static_cast<ValueType>(v[i]);
823 }
824 return *this;
825 }
826
828 Self &
829 operator-=(TValue s)
830 {
831 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
832 {
833 m_Data[i] -= s;
834 }
835 return *this;
836 }
837
846 template <typename T>
847 Self &
848 operator+=(const VariableLengthVector<T> & v)
849 {
850 itkAssertInDebugAndIgnoreInReleaseMacro(m_NumElements == v.GetSize());
851 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
852 {
853 m_Data[i] += static_cast<ValueType>(v[i]);
854 }
855 return *this;
856 }
857
859 Self &
860 operator+=(TValue s)
861 {
862 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
863 {
864 m_Data[i] += s;
865 }
866 return *this;
867 }
868
878 template <typename TExpr1, typename TExpr2, typename TBinaryOp>
879 Self &
880 operator+=(const VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp> & rhs)
881 {
882 itkAssertInDebugAndIgnoreInReleaseMacro(rhs.Size() == Size());
883 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
884 {
885 m_Data[i] += static_cast<ValueType>(rhs[i]);
886 }
887 return *this;
888 }
889
899 template <typename TExpr1, typename TExpr2, typename TBinaryOp>
900 Self &
901 operator-=(const VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp> & rhs)
902 {
903 itkAssertInDebugAndIgnoreInReleaseMacro(rhs.Size() == Size());
904 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
905 {
906 m_Data[i] -= static_cast<ValueType>(rhs[i]);
907 }
908 return *this;
909 }
910
916 template <typename T>
917 Self &
918 operator*=(T s)
919 {
920 const ValueType & sc = static_cast<ValueType>(s);
921 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
922 {
923 m_Data[i] *= sc;
924 }
925 return *this;
926 }
927
931 Self &
932 operator*=(TValue s)
933 {
934 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
935 {
936 m_Data[i] *= s;
937 }
938 return *this;
939 }
940
947 template <typename T>
948 Self &
949 operator/=(T s)
950 {
951 const RealValueType sc = s;
952 for (ElementIdentifier i = 0; i < m_NumElements; ++i)
953 {
954 m_Data[i] = static_cast<ValueType>(static_cast<RealValueType>(m_Data[i]) / sc);
955 }
956 return *this;
957 }
958
963 Self &
964 operator-(); // negation operator
965
966 bool
967 operator==(const Self & v) const;
968
969 ITK_UNEQUAL_OPERATOR_MEMBER_FUNCTION(Self);
970
972 [[nodiscard]] RealValueType
973 GetNorm() const;
974
976 [[nodiscard]] RealValueType
977 GetSquaredNorm() const;
978
980 [[nodiscard]] bool
981 IsAProxy() const
982 {
983 return !m_LetArrayManageMemory;
984 }
985
986private:
987 bool m_LetArrayManageMemory{ true }; // if true, the array is responsible
988 // for memory of data
989 TValue * m_Data{}; // Array to hold data
990 ElementIdentifier m_NumElements{ 0 };
991};
992
994namespace mpl
995{
1005template <typename T>
1006struct IsArray : FalseType
1007{};
1008
1010template <typename T>
1011struct IsArray<itk::VariableLengthVector<T>> : TrueType
1012{};
1013
1014template <typename TExpr1, typename TExpr2, typename TBinaryOp>
1015struct IsArray<VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp>> : TrueType
1016{};
1018} // namespace mpl
1020
1021namespace Details
1022{
1024
1036template <typename TExpr>
1037struct GetType
1038{
1039 using Type = TExpr;
1040
1044 static Type
1045 Load(const Type & v, unsigned int itkNotUsed(idx))
1046 {
1047 return v;
1048 }
1049};
1050
1061template <typename TExpr1, typename TExpr2>
1062inline std::enable_if_t<mpl::And<mpl::IsArray<TExpr1>, mpl::IsArray<TExpr2>>::Value, unsigned int>
1063GetSize(const TExpr1 & lhs, [[maybe_unused]] const TExpr2 & rhs)
1064{
1065 itkAssertInDebugAndIgnoreInReleaseMacro(lhs.Size() == rhs.Size());
1066 return lhs.Size();
1067}
1068
1070
1079template <typename TExpr1, typename TExpr2>
1080inline std::enable_if_t<mpl::And<mpl::IsArray<TExpr1>, mpl::Not<mpl::IsArray<TExpr2>>>::Value, unsigned int>
1081GetSize(const TExpr1 & lhs, const TExpr2 & itkNotUsed(rhs))
1082{
1083 return lhs.Size();
1084}
1085
1095template <typename TExpr1, typename TExpr2>
1096inline std::enable_if_t<mpl::And<mpl::IsArray<TExpr2>, mpl::Not<mpl::IsArray<TExpr1>>>::Value, unsigned int>
1097GetSize(const TExpr1 & itkNotUsed(lhs), const TExpr2 & rhs)
1098{
1099 return rhs.Size();
1100}
1101
1102template <typename T>
1103struct GetType<VariableLengthVector<T>>
1104{
1105 using Type = T;
1106 static Type
1107 Load(const VariableLengthVector<T> & v, unsigned int idx)
1108 {
1109 return v[idx];
1110 }
1111};
1112template <typename TExpr1, typename TExpr2, typename TBinaryOp>
1113struct GetType<VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp>>
1114{
1115 using Type = typename VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp>::ResType;
1116 static Type
1117 Load(const VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp> & v, unsigned int idx)
1118 {
1119 return v[idx];
1120 }
1121};
1123
1124namespace op
1125{
1138template <typename TExpr1, typename TExpr2>
1139struct CanBeAddedOrSubtracted
1140 : mpl::Or<mpl::And<mpl::IsArray<TExpr1>, mpl::IsArray<TExpr2>>,
1141 mpl::And<mpl::IsArray<TExpr1>, mpl::IsNumber<TExpr2>>,
1142 mpl::And<mpl::IsNumber<TExpr1>, mpl::IsArray<TExpr2>>>
1143{};
1144
1156template <typename TExpr1, typename TExpr2>
1157struct CanBeMultiplied
1158 : mpl::Or<mpl::And<mpl::IsArray<TExpr1>, mpl::IsNumber<TExpr2>>,
1159 mpl::And<mpl::IsNumber<TExpr1>, mpl::IsArray<TExpr2>>>
1160{};
1161
1173template <typename TExpr1, typename TExpr2>
1174struct CanBeDivided : mpl::And<mpl::IsArray<TExpr1>, mpl::IsNumber<TExpr2>>
1175{};
1176
1177} // namespace op
1178} // namespace Details
1180
1205template <typename TExpr1, typename TExpr2, typename TBinaryOp>
1206struct VariableLengthVectorExpression
1207{
1208 VariableLengthVectorExpression(const TExpr1 & lhs, const TExpr2 & rhs)
1209 : m_lhs(lhs)
1210 , m_rhs(rhs)
1211 {
1212 // Not necessary actually as end-user/developer is not expected to
1213 // provide new BinaryOperations
1214 static_assert(std::is_base_of_v<Details::op::BinaryOperationConcept, TBinaryOp>,
1215 "The Binary Operation shall inherit from BinaryOperationConcept");
1216 }
1217
1219 [[nodiscard]] unsigned int
1220 Size() const
1221 {
1222 return Details::GetSize(m_lhs, m_rhs);
1223 }
1224
1226 using ResType =
1227 typename mpl::PromoteType<typename Details::GetType<TExpr1>::Type, typename Details::GetType<TExpr2>::Type>::Type;
1229 using RealValueType = typename NumericTraits<ResType>::RealType;
1230
1241 ResType
1242 operator[](unsigned int idx) const
1243 {
1244 itkAssertInDebugAndIgnoreInReleaseMacro(idx < Size());
1245 return TBinaryOp::Apply(Details::GetType<TExpr1>::Load(m_lhs, idx), Details::GetType<TExpr2>::Load(m_rhs, idx));
1246 }
1247
1249 [[nodiscard]] RealValueType
1250 GetNorm() const;
1251
1253 [[nodiscard]] RealValueType
1254 GetSquaredNorm() const;
1255
1256private:
1257 const TExpr1 & m_lhs;
1258 const TExpr2 & m_rhs;
1259};
1260
1270template <typename TExpr1, typename TExpr2>
1271inline std::enable_if_t<Details::op::CanBeAddedOrSubtracted<TExpr1, TExpr2>::Value,
1272 VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Plus>>
1273operator+(const TExpr1 & lhs, const TExpr2 & rhs)
1274{
1275 return VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Plus>(lhs, rhs);
1276}
1277
1287template <typename TExpr1, typename TExpr2>
1288inline std::enable_if_t<Details::op::CanBeAddedOrSubtracted<TExpr1, TExpr2>::Value,
1289 VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Sub>>
1290operator-(const TExpr1 & lhs, const TExpr2 & rhs)
1291{
1292 return VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Sub>(lhs, rhs);
1293}
1294
1303template <typename TExpr1, typename TExpr2>
1304inline std::enable_if_t<Details::op::CanBeMultiplied<TExpr1, TExpr2>::Value,
1305 VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Mult>>
1306operator*(const TExpr1 & lhs, const TExpr2 & rhs)
1307{
1308 return VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Mult>(lhs, rhs);
1309}
1310
1318template <typename TExpr1, typename TExpr2>
1319inline std::enable_if_t<Details::op::CanBeDivided<TExpr1, TExpr2>::Value,
1320 VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Div>>
1321operator/(const TExpr1 & lhs, const TExpr2 & rhs)
1322{
1323 return VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Div>(lhs, rhs);
1324}
1325
1329template <typename TExpr1, typename TExpr2, typename TBinaryOp>
1330std::ostream &
1331operator<<(std::ostream & os, const VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp> & v)
1332{
1333 os << '[';
1334 if (v.Size() != 0)
1335 {
1336 os << v[0];
1337 for (unsigned int i = 1, N = v.Size(); i != N; ++i)
1338 {
1339 os << ", " << v[i];
1340 }
1341 }
1342 return os << ']';
1343}
1344
1350template <typename TExpr>
1351inline std::enable_if_t<mpl::IsArray<TExpr>::Value, typename TExpr::RealValueType>
1352GetNorm(const TExpr & v)
1353{
1354 return static_cast<typename TExpr::RealValueType>(std::sqrt(static_cast<double>(GetSquaredNorm(v))));
1355}
1356
1362template <typename TExpr>
1363inline std::enable_if_t<mpl::IsArray<TExpr>::Value, typename TExpr::RealValueType>
1364GetSquaredNorm(const TExpr & v)
1365{
1366 using RealValueType = typename TExpr::RealValueType;
1367 RealValueType sum = 0.0;
1368 for (unsigned int i = 0, N = v.Size(); i < N; ++i)
1369 {
1370 const RealValueType value = v[i];
1371 sum += value * value;
1372 }
1373 return sum;
1374}
1375
1377
1381template <typename TValue>
1382std::ostream &
1383operator<<(std::ostream & os, const VariableLengthVector<TValue> & arr)
1384{
1385 const unsigned int length = arr.Size();
1386 const int last = static_cast<unsigned int>(length) - 1;
1387
1388 os << '[';
1389 for (int i = 0; i < last; ++i)
1390 {
1391 os << arr[i] << ", ";
1392 }
1393 if (length >= 1)
1394 {
1395 os << arr[last];
1396 }
1397 os << ']';
1398 return os;
1399}
1400
1402
1420template <typename T>
1421inline void
1423{
1424 l_.Swap(r_);
1425}
1426
1427} // namespace itk
1428
1430
1431#ifndef ITK_MANUAL_INSTANTIATION
1432# include "itkVariableLengthVector.hxx"
1433#endif
1434
1435#endif
bool ITKIOXML_EXPORT operator==(itk::FancyString &s, const std::string &)
The "itk" namespace contains all Insight Segmentation and Registration Toolkit (ITK) classes....
void swap(Array< T > &a, Array< T > &b) noexcept
Definition itkArray.h:247
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)
ConstNeighborhoodIterator< TImage > operator+(const ConstNeighborhoodIterator< TImage > &it, const typename ConstNeighborhoodIterator< TImage >::OffsetType &ind)