/*=========================================================================
 *
 *  Copyright NumFOCUS
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         https://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/
#ifndef itkVariableLengthVector_h
#define itkVariableLengthVector_h

#include <cassert>
#include <algorithm>
#include <type_traits>
#include "itkNumericTraits.h"
#include "itkMetaProgrammingLibrary.h"
#include "itkIsNumber.h"
#include "itkPromoteType.h"
#include "itkBinaryOperationConcept.h"

namespace itk
{

template <typename TExpr1, typename TExpr2, typename TBinaryOp>
struct VariableLengthVectorExpression;

/** \class VariableLengthVector
 * \brief Represents an array whose length can be defined at run-time.
 *
 * This class is templated over the data type. This data-type is meant
 * to be a scalar, such as float, double etc...
 *
 * \note
 * ITK itself provides several classes that can serve as \c Arrays.
 * \li FixedArray - Compile time fixed length arrays that's intended to
 * represent an enumerated collection of \c n entities.
 *
 * \li Array - Run time resizeable array that is intended to hold a
 * collection of \c n entities
 *
 * \li Vector - Compile time fixed length array that is intended to hold
 * a collection of \c n data types. A vector usually has a mathematical meaning.
 * It should only be used when mathematical operations such as addition,
 * multiplication by a scalar, product etc make sense.
 *
 * \li VariableLengthVector - Run time array that is intended to hold a collection
 * of scalar data types. Again, it should be used only when mathematical
 * operations on it are relevant. If not, use an Array.
 *
 * \li Point - Represents the spatial coordinates of a spatial location. Operators
 * on Point reflect geometrical concepts.
 *
 * \par For the reasons listed above, you cannot instantiate
 * \code VariableLengthVector< bool > \endcode.
 *
 * \par
 * Design Considerations: We do not derive from \c vnl_vector to avoid being
 * limited by the explicit template instantiations of vnl_vector and other
 * hacks that vnl folks have been forced to use.
 *
 * \note
 * This work is part of the National Alliance for Medical Image Computing
 * (NAMIC), funded by the National Institutes of Health through the NIH Roadmap
 * for Medical Research, Grant U54 EB005149.
 *
 * \sa CovariantVector
 * \sa SymmetricSecondRankTensor
 * \sa RGBPixel
 * \sa DiffusionTensor3D
 * \ingroup DataRepresentation
 * \ingroup ITKCommon
 *
 * \sphinx
 * \sphinxexample{Core/Common/VariableLengthVector,Variable Length Vector}
 * \endsphinx
 *
 * \invariant If \c m_LetArrayManageMemory is true, \c m_Data is deletable
 * (whether it's null or pointing to something with no elements. i.e. \c
 * m_NumElements may be 0 and yet \c m_Data may be not null.)
 */
template <typename TValue>
class ITK_TEMPLATE_EXPORT VariableLengthVector
{
public:
  /**\name Policies
   * The following Policies will be used by \c itk::VariableLengthVector::SetSize
   */
  //@{
  /** \c VariableLengthVector empty base-class for allocation policies.
   * All Allocation Policies are expected to inherit from this empty base
   * class.
   *
   * \sa \c itk::VariableLengthVector::SetSize
   * \sa \c NeverReallocate
   * \sa \c ShrinkToFit
   * \sa \c DontShrinkToFit
   * \ingroup ITKCommon
   * \ingroup DataRepresentation
   */
  struct AllocateRootPolicy
  {};

  /** \c VariableLengthVector Allocation Policy: Always reallocate memory.
   * This policy, when used from \c VariableLengthVector::SetSize(), always
   * implies that the previous internal buffer will be reallocated. Even if
   * enough memory was available.
   * \return true (always)
   *
   * \sa \c itk::VariableLengthVector::SetSize
   * \sa \c NeverReallocate
   * \sa \c ShrinkToFit
   * \sa \c DontShrinkToFit
   * \ingroup ITKCommon
   * \ingroup DataRepresentation
   */
  struct AlwaysReallocate : AllocateRootPolicy
  {
    bool
    operator()(unsigned int itkNotUsed(newSize), unsigned int itkNotUsed(oldSize)) const
    {
      return true;
    }
  };

  /** \c VariableLengthVector Allocation Policy: Never reallocate memory.
   * This policy, when used from \c VariableLengthVector::SetSize(), always
   * implies that the previous internal buffer will be kept. Even if not enough
   * memory was available.
   *
   * The typical use case of this policy is to make sure a \c
   * VariableLengthVector is not a proxy object.
   * \return false (always)
   *
   * \pre <tt>oldSize == newSize</tt>, checked by assertion
   *
   * \sa \c itk::VariableLengthVector::SetSize
   * \sa \c AlwaysReallocate
   * \sa \c ShrinkToFit
   * \sa \c DontShrinkToFit
   * \ingroup ITKCommon
   * \ingroup DataRepresentation
   */
  struct NeverReallocate : AllocateRootPolicy
  {
    bool
    operator()(unsigned int newSize, unsigned int oldSize) const
    {
      (void)newSize;
      (void)oldSize;
      itkAssertInDebugAndIgnoreInReleaseMacro(newSize == oldSize &&
                                              "SetSize is expected to never change the VariableLengthVector size...");
      return true;
    }
  };

  /** \c VariableLengthVector Allocation Policy: reallocate memory only when
   * size changes.
   * This policy, when used from \c VariableLengthVector::SetSize(), will
   * reallocate the internal buffer only if the size of the \c
   * VariableLengthVector changes.
   * \return whether \c newSize differs from \c oldSize
   *
   * \note The name is related to \c DontShrinkToFit reallocation policy that
   * will avoid reallocating when enough memory has already been allocated.
   *
   * \sa \c itk::VariableLengthVector::SetSize
   * \sa \c AlwaysReallocate
   * \sa \c NeverReallocate
   * \sa \c DontShrinkToFit
   * \ingroup ITKCommon
   * \ingroup DataRepresentation
   */
  struct ShrinkToFit : AllocateRootPolicy
  {
    bool
    operator()(unsigned int newSize, unsigned int oldSize) const
    {
      return newSize != oldSize;
    }
  };

  /** \c VariableLengthVector Allocation Policy: reallocate memory only when
   * size increases.
   * This policy, when used from \c VariableLengthVector::SetSize(), will
   * reallocate the internal buffer only if the new size requested for the \c
   * VariableLengthVector increases.
   * \return whether \c newSize is bigger than \c oldSize
   *
   * \warning Unlike classes like \c std::vector<>, \c VariableLengthVector has
   * no capacity concept: the size of the \c VariableLengthVector is its
   * capacity. However, this will help a class without capacity to emulate one.
   * The consequence is that reallocations will occur with scenarios such as
   * the following:
   \code
   VariableLengthVector<...> v;
   v.SetSize(42);
   v.SetSize(12); // no reallocation
   v.SetSize(42); // pointless reallocation (given this policy)
   \endcode
   *
   * \sa \c itk::VariableLengthVector::SetSize
   * \sa \c AlwaysReallocate
   * \sa \c NeverReallocate
   * \sa \c ShrinkToFit
   * \ingroup ITKCommon
   * \ingroup DataRepresentation
   */
  struct DontShrinkToFit : AllocateRootPolicy
  {
    bool
    operator()(unsigned int newSize, unsigned int oldSize) const
    {
      return newSize > oldSize;
    }
  };

  /** \c VariableLengthVector empty base-class for values Keeping policies.
   * All Values Keeping Policies are expected to inherit from this empty base
   * class.
   *
   * The preconditions common to all sub classes are:
   * \pre This policy is only meant to be executed in case of reallocation,
   * i.e. \c oldBuffer and \c newBuffer are expected to differ (unchecked).
   * \pre This presumes \c TValue assignment is a \c noexcept operation.
   * \pre \c newBuffer is not null (pre-conditions imposed by some
   * implementations of \c std::copy())
   * \pre `[oldBuffer, oldBuffer+oldSize)` is a valid range
   *
   * \sa \c itk::VariableLengthVector::SetSize
   * \sa \c KeepOldValues
   * \sa \c DumpOldValues
   * \ingroup ITKCommon
   * \ingroup DataRepresentation
   */
  struct KeepValuesRootPolicy
  {};

  /** \c VariableLengthVector Invariability Policy: Always keep old values.
   * This policy, when used from \c VariableLengthVector::SetSize(), always
   * copies <tt>min(newSize,oldSize)</tt> previous values from the previous
   * internal buffer to the new one
   *
   * \pre This policy is only meant to be executed in case of reallocation,
   * i.e. \c oldBuffer and \c newBuffer are expected to differ (unchecked).
   * \pre This presumes \c TValue assignment is a \c noexcept operation.
   * \pre \c newBuffer is not null (pre-conditions imposed by some
   * implementations of \c std::copy())
   * \pre `[oldBuffer, oldBuffer+oldSize)` is a valid range
   *
   * This behaviour mimics \c std::vector<>::resize() behaviour. However, it
   * makes to sense from \c VariableLengthVector::operator=()
   *
   * \sa \c itk::VariableLengthVector::SetSize
   * \sa \c KeepValuesRootPolicy
   * \sa \c DumpOldValues
   * \ingroup ITKCommon
   * \ingroup DataRepresentation
   */
  struct KeepOldValues : KeepValuesRootPolicy
  {
    template <typename TValue2>
    void
    operator()(unsigned int newSize, unsigned int oldSize, TValue2 * oldBuffer, TValue2 * newBuffer) const
    {
      itkAssertInDebugAndIgnoreInReleaseMacro(newBuffer);
      const size_t nb = std::min(newSize, oldSize);
      itkAssertInDebugAndIgnoreInReleaseMacro(nb == 0 || (nb > 0 && oldBuffer != nullptr));
      std::copy_n(oldBuffer, nb, newBuffer);
    }
  };

  /** \c VariableLengthVector Invariability Policy: Never keep old values.
   * This policy, when used from \c VariableLengthVector::SetSize(), is a no-op.
   * It won't try to copy previous values from the previous internal buffer to
   * the new one.
   *
   * \pre This policy is only meant to be executed in case of reallocation,
   * i.e. \c oldBuffer and \c newBuffer are expected to differ (unchecked).
   *
   * This behaviour particularly fits \c VariableLengthVector::operator=()
   *
   * \sa \c itk::VariableLengthVector::SetSize
   * \sa \c KeepValuesRootPolicy
   * \sa \c DumpOldValues
   * \ingroup ITKCommon
   * \ingroup DataRepresentation
   */
  struct DumpOldValues : KeepValuesRootPolicy
  {
    template <typename TValue2>
    void
    operator()(unsigned int itkNotUsed(newSize),
               unsigned int itkNotUsed(oldSize),
               TValue2 *    itkNotUsed(oldBuffer),
               TValue2 *    itkNotUsed(newBuffer)) const
    {}
  };
  //@}


  /** The element type stored at each location in the Array. */
  using ValueType = TValue;
  using ComponentType = TValue;
  using RealValueType = typename NumericTraits<ValueType>::RealType;
  using Self = VariableLengthVector;

  /** Typedef used to indicate the number of elements in the vector */
  using ElementIdentifier = unsigned int;

  /** Default constructor. It is created with an empty array
   *  it has to be allocated later by assignment, \c SetSize() or \c Reserve().
   * \post \c m_Data is null
   * \post \c m_NumElements is 0
   * \post \c m_LetArrayManageMemory is true
   */
  VariableLengthVector() = default;

  /** Constructor with size.
   * Size can only be changed by assignment, \c SetSize() or \c Reserve().
   * \post \c m_Data is not null and points to an array of \c m_NumElements,
   * even if \c m_NumElements is 0
   * \post values are left uninitialized.
   * \post \c m_NumElements is \c dimension
   * \post \c m_LetArrayManageMemory is true
   */
  explicit VariableLengthVector(unsigned int length);

  /** Constructor that initializes array with contents from a user supplied
   * buffer.
   * The pointer to the buffer and the length is specified. By default, the
   * array does not manage the memory of the buffer. It merely points to that
   * location and it is the user's responsibility to delete it.
   * If \c LetArrayManageMemory is true, then this class will free the
   * memory when this object is destroyed.
   *
   * \post `m_Data == data`
   * \post values are left unmodified
   * \post `m_NumElements == sz`
   * \post `m_LetArrayManageMemory == LetArrayManageMemory`
   */
  VariableLengthVector(ValueType * datain, unsigned int sz, bool LetArrayManageMemory = false);

  /** Constructor that initializes array with contents from a user supplied
   * buffer.
   * The pointer to the buffer and the length is specified. By default, the
   * array does not manage the memory of the buffer. It merely points to that
   * location and it is the user's responsibility to delete it.
   * If \c LetArrayManageMemory is true, then this class will free the
   * memory when this object is destroyed.
   *
   * \warning This overload receives a non-modifiable array, and yet it will let
   * the end-user try to modify it through \c VariableLengthVector interface.
   * Use this constructor with care as this may lead to undefined behaviour.
   * Prefer using `VariableLengthVector<const TValue>` instead of
   * `VariableLengthVector<TValue>` in case we which to use this constructor.
   *
   * \post `m_Data == data`
   * \post values are left unmodified
   * \post `m_NumElements == sz`
   * \post `m_LetArrayManageMemory == LetArrayManageMemory`
   */
  VariableLengthVector(const ValueType * datain, unsigned int sz, bool LetArrayManageMemory = false);

  /** Copy constructor. The reason why the copy constructor and the assignment
   * operator are templated is that it will allow implicit casts to be
   * performed. For instance:
   \code
   VariableLengthVector< int > vI;
   VariableLengthVector< float > vF( vI );
   or for instance vF = static_cast< VariableLengthVector< float > >( vI );
   \endcode
   * \note However that static casting in this way will imply the allocation of
   * a temporary \c VariableLengthVector. Prefer to directly use the assignment
   * converting operator in code where uses of \c static_cast<> would be
   * required.
   *
   * \post \c m_Data is not null and points to an array of \c m_NumElements,
   * if \c m_NumElements is 0, otherwise it's null.
   * \post values are left uninitialized.
   * \post \c m_NumElements is \c v.GetSize()
   * \post \c m_LetArrayManageMemory is true
   */
  template <typename T>
  VariableLengthVector(const VariableLengthVector<T> & v)
  {
    m_NumElements = v.Size();
    m_LetArrayManageMemory = true;
    if (m_NumElements != 0)
    {
      m_Data = this->AllocateElements(m_NumElements);
      itkAssertInDebugAndIgnoreInReleaseMacro(m_Data != nullptr);
      for (ElementIdentifier i = 0; i < m_NumElements; ++i)
      {
        this->m_Data[i] = static_cast<ValueType>(v[i]);
      }
    }
    else
    {
      m_Data = nullptr;
    }
  }

  /** Copy constructor. Overrides the default non-templated copy constructor
   * that the compiler provides.
   * \post \c m_Data is not null and points to an array of \c m_NumElements,
   * if \c m_NumElements is 0, otherwise it's null.
   * \post values are left uninitialized.
   * \post \c m_NumElements is \c v.GetSize()
   * \post \c m_LetArrayManageMemory is true
   */
  VariableLengthVector(const VariableLengthVector<TValue> & v);

  /** Swaps two \c VariableLengthVector 's.
   * \pre Expects either none of the \c VariableLengthVector to act as a proxy,
   * or both, checked with an assertion.
   * \post \c *this and \c old contents are swapped.
   * \param[in,out] v  other \c VariableLengthVector to be swapped with.
   * \throw None
   * \sa \c itk::swap()
   */
  void
  Swap(Self & v) noexcept
  {
    itkAssertInDebugAndIgnoreInReleaseMacro(m_LetArrayManageMemory == v.m_LetArrayManageMemory);
    using std::swap;
    swap(v.m_Data, m_Data);
    swap(v.m_NumElements, m_NumElements);
  }

  /** C++11 Move Constructor.
   * \post \c v is destructible and assignable.
   * \post `m_NumElements == 0`
   * \post `m_LetArrayManageMemory == true`
   * \post `m_Data == nullptr`
   * \post Built object contains old \c v data.
   */
  VariableLengthVector(Self && v) noexcept;

  /** C++11 Move assignment operator.
   * \pre \c v shall not be the same as the current object
   * \post \c v is destructible and assignable.
   * \post `m_NumElements == 0`
   * \post `m_LetArrayManageMemory == true`
   * \post `m_Data == nullptr`
   * \post Current object contains old \c v data.
   */
  Self &
  operator=(Self && v) noexcept;

  /** Constructor from an Expression Template vector.
   * \tparam TExpr1 Type of the left sub-expression
   * \tparam TExpr2 Type of the right sub-expression
   * \tparam TBinaryOp Binary Operation to apply to both sub-expressions.
   * \param[in] rhs Non evaluated Expression Template.
   *
   * Builds the new \c VariableLengthVector with an expression template. The
   * code loops over all components from the template expression, and evaluates
   * them on the fly to fill the content of the new vector.
   *
   * \post \c m_Data is not null and points to an array of \c m_NumElements,
   * even if \c m_NumElements is 0
   * \post `*this == rhs`
   * \post \c m_NumElements is \c rhs.GetSize()
   * \post \c m_LetArrayManageMemory is true
   */
  template <typename TExpr1, typename TExpr2, typename TBinaryOp>
  VariableLengthVector(VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp> const & rhs);
  /** Assignment from an Expression Template vector.
   * \tparam TExpr1 Type of the left sub-expression
   * \tparam TExpr2 Type of the right sub-expression
   * \tparam TBinaryOp Binary Operation to apply to both sub-expressions.
   * \param[in] rhs Non evaluated Expression Template.
   *
   * Resets the new \c VariableLengthVector with an expression template. The
   * code loops over all components from the template expression, and evaluates
   * them on the fly to fill the content of the current vector.
   *
   * \post if called on a \c VariableLengthVector proxy, the referenced values
   * are left unchanged.
   * \post \c m_Data is not null and points to an array of \c m_NumElements,
   * if \c m_NumElements is not 0. \c m_Data may be null otherwise (an empty
   * vector is assigned into another empty vector)
   * \post \c m_LetArrayManageMemory is true
   * \post `GetSize() == rhs.GetSize()`
   * \post `*this == rhs`
   */
  template <typename TExpr1, typename TExpr2, typename TBinaryOp>
  Self &
  operator=(VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp> const & rhs);

  /** Set all the elements of the array to the specified value.
   * \pre This function may be called on empty vectors, it's a no-op.
   */
  void
  Fill(TValue const & v);

  /** Converting assignment operator.
   * \note Ensures a <em>String Exception Guarantee</em>: resists to
   * self-assignment, and no changes are made if memory cannot be allocated to
   * hold the new elements. This presumes \c TValue assignment is a \c
   * noexcept operation.
   *
   * \post if called on a \c VariableLengthVector proxy, the referenced values
   * are left unchanged.
   * \post \c m_LetArrayManageMemory is true
   * \post <tt>GetSize() == v.GetSize()</tt>, modulo precision
   * \post <tt>*this == v</tt>
   */
  template <typename T>
  Self &
  operator=(const VariableLengthVector<T> & v)
  {
    // No self assignment test is done. Indeed:
    // - the operator already resists self assignment through a strong exception
    // guarantee
    // - the test becomes a pessimization as we never write
    //    VLV<const TValue> vcref(v.GetDataPointer(), v.GetSize());
    //    ...;
    //    v = vcref;
    ElementIdentifier const N = v.Size();
    this->SetSize(N, DontShrinkToFit(), DumpOldValues());
    for (ElementIdentifier i = 0; i < N; ++i)
    {
      this->m_Data[i] = static_cast<ValueType>(v[i]);
    }
    return *this;
  }

  /** Copy-Assignment operator.
   * \note Ensures a <em>String Exception Guarantee</em>: resists to
   * self-assignment, and no changes are made if memory cannot be allocated to
   * hold the new elements. This is expecting \c TValue assignment is a \c
   * noexcept operation.
   *
   * \post if called on a \c VariableLengthVector proxy, the referenced values
   * are left unchanged.
   * \post \c m_Data is not null and points to an array of \c m_NumElements,
   * if \c m_NumElements is not 0. \c m_Data may be null otherwise (an empty
   * vector is assigned into another empty vector)
   * \post \c m_LetArrayManageMemory is true
   * \post <tt>GetSize() == v.GetSize()</tt>
   * \post <tt>*this == v</tt>
   */
  Self &
  operator=(const Self & v);

  /** Fast Assignment.
   * \pre \c m_LetArrayManageMemory is true: the \c VariableLengthVector is not
   * a proxy, checked with an assertion. Call <tt>SetSize(GetSize(), NeverReallocate(),
   * DumpOldValues())</tt> to ensure a vector is not a proxy anymore.
   * \pre current size is identical to the one from the right hand side
   * operand, checked with an assertion.
   * \pre Doesn't not support empty vectors.
   */
  Self &
  FastAssign(const Self & v);

  /** Assignment operator from a numeric value.
   * \pre This assumes \c m_LetArrayManageMemory is true, but it is unchecked.
   * If this operator is called on a \c VariableLengthVector proxy, referenced
   * values will be overwritten.
   * \post Elements in `[m_Data, m_Data+GetSize())` will be equal to \c v, modulo
   * precision
   */
  Self &
  operator=(TValue const & v);

  /** Return the number of elements in the Array  */
  unsigned int
  Size() const
  {
    return m_NumElements;
  }
  unsigned int
  GetSize() const
  {
    return m_NumElements;
  }
  unsigned int
  GetNumberOfElements() const
  {
    return m_NumElements;
  }

  /** Return reference to the element at specified index. No range checking. */
  TValue & operator[](unsigned int i) { return this->m_Data[i]; }
  /** Return reference to the element at specified index. No range checking. */
  TValue const & operator[](unsigned int i) const { return this->m_Data[i]; }

  /** Get one element */
  const TValue &
  GetElement(unsigned int i) const
  {
    return m_Data[i];
  }

  /** Set one element */
  void
  SetElement(unsigned int i, const TValue & value)
  {
    m_Data[i] = value;
  }

  /** Resizes the vector.
   * \tparam TReallocatePolicy Policy that determines precisely the conditions
   * under which the internal buffer shall be reallocated. It shall inherit
   * from \c AllocateRootPolicy.
   * \tparam TKeepValuesPolicy Policy that determines whether old elements
   * shall be kept. It shall inherit from \c KeepValuesRootPolicy.
   *
   * \internal
   * The purpose of this overload is to fine tune what \c SetSize() does. Some
   * users seem to need to always reallocate, or to maintain old elements.
   * However, some usages require fast resizing. In the assignment operators
   * cases, we don't need to reallocate anything if we have enough memory, and
   * we certainly do not need to maintain previous values as they'll get
   * overridden with new ones.
   * \internal
   * If we could assert that \c VariableLengthVector proxies would (shall!)
   * never be assigned anything, we could benefit from a version that won't
   * check \c m_LetArrayManageMemory.
   *
   * \pre `m_NumElements == sz` if \c TReallocatePolicy is \c NeverReallocate
   * \post `m_NumElements == sz`
   * \post \c m_LetArrayManageMemory is true
   * \post In case of reallocation, old \c m_Data buffer is deleted.
   * \post If \c TKeepValuesPolicy is \c KeepOldValues, old values are
   * guaranteed to be kept, otherwise, it'll depend on the reallocation policy
   * and the old and new vector size.
   * \sa \c AlwaysReallocate
   * \sa \c NeverReallocate
   * \sa \c ShrinkToFit
   * \sa \c DontShrinkToFit
   * \sa \c KeepOldValues
   * \sa \c DumpOldValues
   */
  template <typename TReallocatePolicy, typename TKeepValuesPolicy>
  void
  SetSize(unsigned int sz, TReallocatePolicy reallocatePolicy, TKeepValuesPolicy keepValues);

  /** Set the size to that given.
   *
   * If \c destroyExistingData is \c false:
   * If the array already contains data, the existing data is copied over and
   * new space is allocated, if necessary. If the length to reserve is less
   * than the current number of elements, then an appropriate number of elements
   * are discarded.
   *    If \c true, the size is set destructively to the length given. If the
   * length is different from the current length, existing data will be lost.
   * The default is \c true. */
  void
  SetSize(unsigned int sz, bool destroyExistingData = true)
  {
    // Stays compatible with previous code version
    // And works around the fact C++03 template functions can't have default
    // arguments on template types.
    if (destroyExistingData)
    {
      SetSize(sz, AlwaysReallocate(), KeepOldValues());
    }
    else
    {
      SetSize(sz, ShrinkToFit(), KeepOldValues());
    }
  }

  /** Destroy data that is allocated internally, if \c LetArrayManageMemory is
   * true. */
  void
  DestroyExistingData();

  /** Set the pointer from which the data is imported.
   * If "LetArrayManageMemory" is false, then the application retains
   * the responsibility of freeing the memory for this data.  If
   * "LetArrayManageMemory" is true, then this class will free the
   * memory when this object is destroyed.
   * \warning The size of the new \c data shall match vector current size.
   * Prefer the other overload.
   * \post old \c m_Data is deleted iff \c m_LetArrayManageMemory is true
   * \post `m_Data == data`
   * \post `m_LetArrayManageMemory ==LetArrayManageMemory`
   * \post \c Size() is left unmodified.
   */
  void
  SetData(TValue * datain, bool LetArrayManageMemory = false);

  /** Similar to the previous method. In the above method, the size must be
   * separately set prior to using user-supplied data. This introduces an
   * unnecessary allocation step to be performed. This method avoids it
   * and should be used to import data wherever possible to avoid this.
   * Set the pointer from which the data is imported.
   * If "LetArrayManageMemory" is false, then the application retains
   * the responsibility of freeing the memory for this data.  If
   * "LetArrayManageMemory" is true, then this class will free the
   * memory when this object is destroyed.
   * \post old \c m_Data is deleted iff \c m_LetArrayManageMemory is true
   * \post `m_Data == data`
   * \post `m_LetArrayManageMemory ==LetArrayManageMemory`
   * \post `m_NumElements == sz`
   */
  void
  SetData(TValue * datain, unsigned int sz, bool LetArrayManageMemory = false);

  /** This destructor is not virtual for performance reasons. However, this
   * means that subclasses cannot allocate memory.
   *
   * \internal
   * More precisely, this class has value semantics (copyable, assignable,
   * comparable). It's hardly compatible with public inheritance: slicing would
   * always be there somewhere to annoy us if we try to inherit publicly from
   * such a class.
   * As a consequence, having the destructor virtual makes hardly any sense.
   */
  ~VariableLengthVector();

  /** Reserves memory of a certain size of data.
   *
   * If the array already contains data, the existing data is copied over and
   * new space is allocated, if necessary. If the length to reserve is less
   * than the current number of elements, then an appropriate number of elements
   * are discarded.
   * \post \c m_Data is not null and can hold \c size elements.
   * \post \c m_LetArrayManageMemory may be left unchanged if there already are
   * enough elements.
   *
   * \note You may prefer instead
   * `SetSize(N, DontShrinkToFit(), KeepOldValues());` that ensures that the
   * array is not a proxy at the end of the operation.
   */
  void
  Reserve(ElementIdentifier size);

  /** Allocate memory of certain size and return it.
   * \return a non-null pointer to an array of \c size elements (0 is a valid
   * parameter).
   */
  TValue *
  AllocateElements(ElementIdentifier size) const;

  const TValue *
  GetDataPointer() const
  {
    return m_Data;
  }

  /** Prefix operator that subtracts 1 from each element of the
   * vector. */
  Self &
  operator--()
  {
    for (ElementIdentifier i = 0; i < m_NumElements; ++i)
    {
      this->m_Data[i] -= static_cast<ValueType>(1.0);
    }
    return *this;
  }

  /** Prefix operator that adds 1 to each element of the vector. */
  Self &
  operator++() // prefix operator ++v;
  {
    for (ElementIdentifier i = 0; i < m_NumElements; ++i)
    {
      this->m_Data[i] += static_cast<ValueType>(1.0);
    }
    return *this;
  }

  /** Postfix operator that subtracts 1 from each element of the
   * vector. */
  Self
  operator--(int) // postfix operator v--;
  {
    Self tmp(*this);

    --tmp;
    return tmp;
  }

  /** Postfix operator that adds 1 to each element of the vector. */
  Self
  operator++(int) // postfix operator v++;
  {
    Self tmp(*this);

    ++tmp;
    return tmp;
  }

  /** Element-wise subtraction of vector 'v' from the current
   * vector. The vectors do not have to have the same element
   * type. The input vector elements are cast to the current vector
   * element type before the subtraction is performed.
   *
   * \throw None
   * \note For efficiency, the length of the vectors is not checked;
   * they are assumed to have the same length. */
  template <typename T>
  Self &
  operator-=(const VariableLengthVector<T> & v)
  {
    itkAssertInDebugAndIgnoreInReleaseMacro(m_NumElements == v.GetSize());
    for (ElementIdentifier i = 0; i < m_NumElements; ++i)
    {
      m_Data[i] -= static_cast<ValueType>(v[i]);
    }
    return *this;
  }

  /** Subtract scalar 's' from each element of the current vector. */
  Self &
  operator-=(TValue s)
  {
    for (ElementIdentifier i = 0; i < m_NumElements; ++i)
    {
      m_Data[i] -= s;
    }
    return *this;
  }

  /** Element-wise addition of vector 'v' to the current vector. The
   * vectors do not have to have the same element type. The input
   * vector elements are cast to the current vector element type
   * before the addition is performed.
   *
   * \throw None
   * \note For efficiency, the length of the vectors is not checked;
   * they are assumed to have the same length. */
  template <typename T>
  Self &
  operator+=(const VariableLengthVector<T> & v)
  {
    itkAssertInDebugAndIgnoreInReleaseMacro(m_NumElements == v.GetSize());
    for (ElementIdentifier i = 0; i < m_NumElements; ++i)
    {
      m_Data[i] += static_cast<ValueType>(v[i]);
    }
    return *this;
  }

  /** Add scalar 's' to each element of the vector. */
  Self &
  operator+=(TValue s)
  {
    for (ElementIdentifier i = 0; i < m_NumElements; ++i)
    {
      m_Data[i] += s;
    }
    return *this;
  }

  /** Compound addition operator with a expression template vector.
   * \tparam TExpr1 Type of the left sub-expression
   * \tparam TExpr2 Type of the right sub-expression
   * \tparam TBinaryOp Binary Operation to apply to both sub-expressions.
   * \param[in] rhs Non evaluated Expression Template.
   *
   * \pre `Size() == rhs.Size()`, checked with an assertion
   * \note The elements of the expression template are evaluated one by one.
   */
  template <typename TExpr1, typename TExpr2, typename TBinaryOp>
  Self &
  operator+=(VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp> const & rhs)
  {
    itkAssertInDebugAndIgnoreInReleaseMacro(rhs.Size() == Size());
    for (ElementIdentifier i = 0; i < m_NumElements; ++i)
    {
      m_Data[i] += static_cast<ValueType>(rhs[i]);
    }
    return *this;
  }

  /** Compound subtraction operator with a expression template vector.
   * \tparam TExpr1 Type of the left sub-expression
   * \tparam TExpr2 Type of the right sub-expression
   * \tparam TBinaryOp Binary Operation to apply to both sub-expressions.
   * \param[in] rhs Non evaluated Expression Template.
   *
   * \pre `Size() == rhs.Size()`, checked with an assertion
   * \note The elements of the expression template are evaluated one by one.
   */
  template <typename TExpr1, typename TExpr2, typename TBinaryOp>
  Self &
  operator-=(VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp> const & rhs)
  {
    itkAssertInDebugAndIgnoreInReleaseMacro(rhs.Size() == Size());
    for (ElementIdentifier i = 0; i < m_NumElements; ++i)
    {
      m_Data[i] -= static_cast<ValueType>(rhs[i]);
    }
    return *this;
  }

  /** Multiply each element of the vector by a scalar 's'. The scalar
   * value is cast to the current vector element type prior to
   * multiplication.
   * \throw None
   */
  template <typename T>
  Self &
  operator*=(T s)
  {
    const ValueType & sc = static_cast<ValueType>(s);
    for (ElementIdentifier i = 0; i < m_NumElements; ++i)
    {
      m_Data[i] *= sc;
    }
    return *this;
  }

  /** Multiply each element of the vector by a scalar 's'.
   * \throw None
   */
  Self &
  operator*=(TValue s)
  {
    for (ElementIdentifier i = 0; i < m_NumElements; ++i)
    {
      m_Data[i] *= s;
    }
    return *this;
  }

  /** Divide vector elements by a scalar 's'. The vector does not
   * have to have the same element type as the scalar type. Both the
   * scalar and vector elements are cast to the RealValueType prior to
   * division, and the result is cast to the ValueType.
   * \throw None
   */
  template <typename T>
  Self &
  operator/=(T s)
  {
    const RealValueType sc = s;
    for (ElementIdentifier i = 0; i < m_NumElements; ++i)
    {
      m_Data[i] = static_cast<ValueType>(static_cast<RealValueType>(m_Data[i]) / sc);
    }
    return *this;
  }

  /** Negates each vector element.
   * \warning This operator has a non standard semantics. Instead of returning
   * a new \c VariableLengthVector, it modifies the current object.
   */
  Self &
  operator-(); // negation operator

  bool
  operator==(const Self & v) const;

  ITK_UNEQUAL_OPERATOR_MEMBER_FUNCTION(Self);

  /** Returns vector's Euclidean norm. */
  RealValueType
  GetNorm() const;

  /** Returns vector's squared Euclidean norm. */
  RealValueType
  GetSquaredNorm() const;

  /** letArrayManageMemory getter. */
  bool
  IsAProxy() const
  {
    return !m_LetArrayManageMemory;
  }

private:
  bool m_LetArrayManageMemory{ true }; // if true, the array is responsible
                                       // for memory of data
  TValue *          m_Data{};          // Array to hold data
  ElementIdentifier m_NumElements{ 0 };
};

/// \cond HIDE_META_PROGRAMMING
namespace mpl
{
/** Tells whether a type is an array type for which the support of arithmetic
 * operations is done with Expression Template.
 * \note For the moment, only \c itk::VariableLengthVector<> is supported. It
 * could be extended to other types of ITK arrays.
 * \ingroup MetaProgrammingLibrary
 * \ingroup ITKCommon
 * \sa \c VariableLengthVector
 * \sa \c VariableLengthVectorExpression
 */
template <typename T>
struct IsArray : FalseType
{};

/// \cond SPECIALIZATION_IMPLEMENTATION
template <typename T>
struct IsArray<itk::VariableLengthVector<T>> : TrueType
{};

template <typename TExpr1, typename TExpr2, typename TBinaryOp>
struct IsArray<VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp>> : TrueType
{};
/// \endcond
} // namespace mpl
/// \endcond

namespace Details
{
/// \cond HIDE_META_PROGRAMMING
/** Helper Trait for VLV expression template: returns the value type.
 * \tparam TExpr Expression type
 * \return \c Type The value type behind \c TExpr (\c TExpr in case of a
 * numerical type, \c TExpr::ValueType in case of the \c VariableLengthVector,
 * etc.)
 *
 * Also defines \c Load() that permits to fetch the i-th element in case of an
 * array, array expression, or just the number in case of a number.
 * \ingroup ITKCommon
 * \sa \c VariableLengthVector
 * \sa \c VariableLengthVectorExpression
 */
template <typename TExpr>
struct GetType
{
  using Type = TExpr;
  /** Fetches the i-th element from an array (expression).
   * \note the default unspecialized behaviour returns the input number \c v.
   */
  static Type
  Load(Type const & v, unsigned int idx)
  {
    (void)idx;
    return v;
  }
};

/** Helper function for VLV expression templates: returns the common size.
 * \param[in] lhs left hand side expression
 * \param[in] rhs right hand side expression
 * \note The default overload assumes both operands are \c VariableLengthVector
 * (or expression) arrays
 * \pre asserts both arrays have the same size.
 * \ingroup ITKCommon
 * \sa \c VariableLengthVector
 * \sa \c VariableLengthVectorExpression
 */
template <typename TExpr1, typename TExpr2>
inline std::enable_if_t<mpl::And<mpl::IsArray<TExpr1>, mpl::IsArray<TExpr2>>::Value, unsigned int>
GetSize(TExpr1 const & lhs, TExpr2 const & rhs)
{
  (void)rhs;
  itkAssertInDebugAndIgnoreInReleaseMacro(lhs.Size() == rhs.Size());
  return lhs.Size();
}

/// \cond SPECIALIZATION_IMPLEMENTATION
/** Helper function for VLV expression templates: returns the common size.
 * \param[in] lhs left hand side expression
 * \param[in] rhs right hand side expression
 * \note This overload assumes that only the first operand is a \c
 * VariableLengthVector (or expression) array.
 * \ingroup ITKCommon
 * \sa \c VariableLengthVector
 * \sa \c VariableLengthVectorExpression
 */
template <typename TExpr1, typename TExpr2>
inline std::enable_if_t<mpl::And<mpl::IsArray<TExpr1>, mpl::Not<mpl::IsArray<TExpr2>>>::Value, unsigned int>
GetSize(TExpr1 const & lhs, TExpr2 const & itkNotUsed(rhs))
{
  return lhs.Size();
}

/** Helper function for VLV expression templates: returns the common size.
 * \param[in] lhs left hand side expression
 * \param[in] rhs right hand side expression
 * \note This overload assumes that only the second operand is a \c
 * VariableLengthVector (or expression) array.
 * \ingroup ITKCommon
 * \sa \c VariableLengthVector
 * \sa \c VariableLengthVectorExpression
 */
template <typename TExpr1, typename TExpr2>
inline std::enable_if_t<mpl::And<mpl::IsArray<TExpr2>, mpl::Not<mpl::IsArray<TExpr1>>>::Value, unsigned int>
GetSize(TExpr1 const & itkNotUsed(lhs), TExpr2 const & rhs)
{
  return rhs.Size();
}

template <typename T>
struct GetType<VariableLengthVector<T>>
{
  using Type = T;
  static Type
  Load(VariableLengthVector<T> const & v, unsigned int idx)
  {
    return v[idx];
  }
};
template <typename TExpr1, typename TExpr2, typename TBinaryOp>
struct GetType<VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp>>
{
  using Type = typename VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp>::ResType;
  static Type
  Load(VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp> const & v, unsigned int idx)
  {
    return v[idx];
  }
};
/// \endcond

namespace op
{
/** Tells whether objects from two types can be added or subtracted.
 * The operation is authorized if and only if:
 * - both are arrays,
 * - or one operand is an array while the second is a number.
 * \note As this traits is dedicated to help overload binary operators, it
 * shall not be used to help overload `operator+()` between floats for instance.
 * Hence, the case where both operands are numbers is rejected.
 *
 * \sa \c mpl::IsArray<> to know the exact array types recognized as \em array by this traits
 * \ingroup MetaProgrammingLibrary
 * \ingroup ITKCommon
 */
template <typename TExpr1, typename TExpr2>
struct CanBeAddedOrSubtracted
  : mpl::Or<mpl::And<mpl::IsArray<TExpr1>, mpl::IsArray<TExpr2>>,
            mpl::And<mpl::IsArray<TExpr1>, mpl::IsNumber<TExpr2>>,
            mpl::And<mpl::IsNumber<TExpr1>, mpl::IsArray<TExpr2>>>
{};

/** Tells whether objects from two types can be multiplied.
 * The operation is authorized if and only if:
 * - one operand is an array while the second is a number.
 * \note As this traits is dedicated to help overload `operator*()`, it
 * shall not be used to help overload the operator between floats for instance.
 * Hence, the case where both operands are numbers is rejected.
 *
 * \sa \c mpl::IsArray<> to know the exact array types recognized as \em array by this traits
 * \ingroup MetaProgrammingLibrary
 * \ingroup ITKCommon
 */
template <typename TExpr1, typename TExpr2>
struct CanBeMultiplied
  : mpl::Or<mpl::And<mpl::IsArray<TExpr1>, mpl::IsNumber<TExpr2>>,
            mpl::And<mpl::IsNumber<TExpr1>, mpl::IsArray<TExpr2>>>
{};

/** Tells whether objects from two types can be divided.
 * The operation is authorized if and only if:
 * - the first operand is an array while the second is a number.
 * \note As this traits is dedicated to help overload `operator/()`, it
 * shall not be used to help overload the operator between floats for instance.
 * Hence, the case where both operands are numbers is rejected.
 *
 * \sa \c mpl::IsArray<> to know the exact array types recognized as \em array by this traits
 * \ingroup MetaProgrammingLibrary
 * \ingroup ITKCommon
 */
template <typename TExpr1, typename TExpr2>
struct CanBeDivided : mpl::And<mpl::IsArray<TExpr1>, mpl::IsNumber<TExpr2>>
{};

} // namespace op
} // namespace Details
/// \endcond

/** Expression Template for \c VariableLengthVector.
 * Contains an expression template that models a binary operation between two
 * sub expressions (of type \c VariableLengthVector, or \c VariableLengthVectorExpression)
 * \tparam TExpr1 Type of the left sub-expression
 * \tparam TExpr2 Type of the right sub-expression
 * \tparam TBinaryOp Binary Operation to apply to both sub-expressions.
 *
 * \note We permit to add a `VariableLengthVector<float>` with a
 * `VariableLengthVector<double>`, the result will be of type
 * `VariableLengthVector<double>`.
 *
 * \warning Explicitly static casting an expression to a
 * \c VariableLengthVector<> will defeat the purpose of the optimization
 * implemented here. It's thus best to let the expression automatically adjust
 * to the type with the most precision.
 * Eventually, when assigning to the final destination (a
 * \c VariableLengthVector<>), a casting on-the-fly could be realized by the
 * assignment operator, or by the copy constructor.
 *
 * \todo Add support for unary operations like `operator-()`.
 *
 * \ingroup DataRepresentation
 * \ingroup ITKCommon
 */
template <typename TExpr1, typename TExpr2, typename TBinaryOp>
struct VariableLengthVectorExpression
{
  VariableLengthVectorExpression(TExpr1 const & lhs, TExpr2 const & rhs)
    : m_lhs(lhs)
    , m_rhs(rhs)
  {
    // Not necessary actually as end-user/developer is not expected to
    // provide new BinaryOperations
    static_assert(std::is_base_of_v<Details::op::BinaryOperationConcept, TBinaryOp>,
                  "The Binary Operation shall inherit from BinaryOperationConcept");
  }

  /// Returns the size of the vector expression.
  unsigned int
  Size() const
  {
    return Details::GetSize(m_lhs, m_rhs);
  }

  /// Vector type of the Result Expression
  using ResType =
    typename mpl::PromoteType<typename Details::GetType<TExpr1>::Type, typename Details::GetType<TExpr2>::Type>::Type;
  /// Real type of the elements
  using RealValueType = typename NumericTraits<ResType>::RealType;

  /** Element access operator.
   * \pre `idx < Size()`
   * \internal
   * This is where the magic happens. Instead of building a new vector based on
   * the two input vectors, we compute each element on-the-fly when
   * requested(by a \c VariableLengthVector constructor or an assignment
   * operator).
   *
   * \c Load() is in charge of fetching the i-th element of the sub-expressions
   */
  ResType operator[](unsigned int idx) const
  {
    itkAssertInDebugAndIgnoreInReleaseMacro(idx < Size());
    return TBinaryOp::Apply(Details::GetType<TExpr1>::Load(m_lhs, idx), Details::GetType<TExpr2>::Load(m_rhs, idx));
  }

  /** Returns vector's Euclidean Norm  */
  RealValueType
  GetNorm() const;

  /** Returns vector's squared Euclidean Norm  */
  RealValueType
  GetSquaredNorm() const;

private:
  TExpr1 const & m_lhs;
  TExpr2 const & m_rhs;
};

/** Addition involving a \c VariableLengthVector.
 * This operation is generic and takes:
 * - two arrays,
 * - or one array and one number (on either side)
 * \return an expression template proxy object.
 * \throw None As no allocation will be performed.
 * \relates itk::VariableLengthVector
 * \sa \c mpl::IsArray<> to know the exact array types recognized as \em array by this traits
 */
template <typename TExpr1, typename TExpr2>
inline std::enable_if_t<Details::op::CanBeAddedOrSubtracted<TExpr1, TExpr2>::Value,
                        VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Plus>>
operator+(TExpr1 const & lhs, TExpr2 const & rhs)
{
  return VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Plus>(lhs, rhs);
}

/** Subtraction involving a \c VariableLengthVector.
 * This operation is generic and takes:
 * - two arrays,
 * - or one array and one number (on either side)
 * \return an expression template proxy object.
 * \throw None As no allocation will be performed.
 * \relates itk::VariableLengthVector
 * \sa \c mpl::IsArray<> to know the exact array types recognized as \em array by this traits
 */
template <typename TExpr1, typename TExpr2>
inline std::enable_if_t<Details::op::CanBeAddedOrSubtracted<TExpr1, TExpr2>::Value,
                        VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Sub>>
operator-(TExpr1 const & lhs, TExpr2 const & rhs)
{
  return VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Sub>(lhs, rhs);
}

/** Multiplication between a \c VariableLengthVector and a scalar.
 * This operation is generic and takes one array and one number (on either
 * side).
 * \return an expression template proxy object.
 * \throw None As no allocation will be performed.
 * \relates itk::VariableLengthVector
 * \sa \c mpl::IsArray<> to know the exact array types recognized as \em array by this traits
 */
template <typename TExpr1, typename TExpr2>
inline std::enable_if_t<Details::op::CanBeMultiplied<TExpr1, TExpr2>::Value,
                        VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Mult>>
operator*(TExpr1 const & lhs, TExpr2 const & rhs)
{
  return VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Mult>(lhs, rhs);
}

/** Division of a \c VariableLengthVector by a scalar.
 * This operation is generic and takes one array and one number.
 * \return an expression template proxy object.
 * \throw None As no allocation will be performed.
 * \relates itk::VariableLengthVector
 * \sa \c mpl::IsArray<> to know the exact array types recognized as \em array by this traits
 */
template <typename TExpr1, typename TExpr2>
inline std::enable_if_t<Details::op::CanBeDivided<TExpr1, TExpr2>::Value,
                        VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Div>>
operator/(TExpr1 const & lhs, TExpr2 const & rhs)
{
  return VariableLengthVectorExpression<TExpr1, TExpr2, Details::op::Div>(lhs, rhs);
}

/** Serialization of \c VariableLengthVectorExpression
 * \relates itk::VariableLengthVectorExpression
 */
template <typename TExpr1, typename TExpr2, typename TBinaryOp>
std::ostream &
operator<<(std::ostream & os, VariableLengthVectorExpression<TExpr1, TExpr2, TBinaryOp> const & v)
{
  os << '[';
  if (v.Size() != 0)
  {
    os << v[0];
    for (unsigned int i = 1, N = v.Size(); i != N; ++i)
    {
      os << ", " << v[i];
    }
  }
  return os << ']';
}

/** Returns vector's Euclidean Norm.
 * \tparam TExpr must be an array
 * \sa \c mpl::IsArray<> to know the exact array types recognized as \em array by this traits
 * \relates itk::VariableLengthVectorExpression
 */
template <typename TExpr>
inline std::enable_if_t<mpl::IsArray<TExpr>::Value, typename TExpr::RealValueType>
GetNorm(TExpr const & v)
{
  return static_cast<typename TExpr::RealValueType>(std::sqrt(static_cast<double>(GetSquaredNorm(v))));
}

/** Returns vector's squared Euclidean Norm.
 * \tparam TExpr must be an array
 * \sa \c mpl::IsArray<> to know the exact array types recognized as \em array by this traits
 * \relates itk::VariableLengthVectorExpression
 */
template <typename TExpr>
inline std::enable_if_t<mpl::IsArray<TExpr>::Value, typename TExpr::RealValueType>
GetSquaredNorm(TExpr const & v)
{
  using RealValueType = typename TExpr::RealValueType;
  RealValueType sum = 0.0;
  for (unsigned int i = 0, N = v.Size(); i < N; ++i)
  {
    const RealValueType value = v[i];
    sum += value * value;
  }
  return sum;
}

/**\name Serialization */
//@{
/** Serialization of \c VariableLengthVector
 * \relates itk::VariableLengthVector
 */
template <typename TValue>
std::ostream &
operator<<(std::ostream & os, const VariableLengthVector<TValue> & arr)
{
  const unsigned int length = arr.Size();
  const int          last = static_cast<unsigned int>(length) - 1;

  os << '[';
  for (int i = 0; i < last; ++i)
  {
    os << arr[i] << ", ";
  }
  if (length >= 1)
  {
    os << arr[last];
  }
  os << ']';
  return os;
}
//@}

/**\name Standard compliance functions */
//@{
/** \c swap() overload for \c VariableLengthVector
 * \throw None
 * \relates itk::VariableLengthVector
 * \internal
 * This overload follows C++ standard naming convention. This is required to
 * permit \c VariableLengthVector to be exchanged by standard algorithms that
 * take advantage of Koening Namespace Lookup (a.k.a. Argument Dependant
 * Lookup). e.g.
 \code
 template <typename T> f(T & l, T & r)
 {
     using std::swap;
     swap(l,r);
     ...
 }
 * \endcode
 */
template <typename T>
inline void
swap(VariableLengthVector<T> & l_, VariableLengthVector<T> & r_) noexcept
{
  l_.Swap(r_);
}
//@}

} // namespace itk

#include "itkNumericTraitsVariableLengthVectorPixel.h"

#ifndef ITK_MANUAL_INSTANTIATION
#  include "itkVariableLengthVector.hxx"
#endif

#endif
