////////////////////////////////////////////////////////////////////////////////
/** 
  \file
  \brief \ru Одномерный массив объектов.
         \en One-dimensional array of objects. \~

*/
////////////////////////////////////////////////////////////////////////////////

#ifndef __TEMPL_S_ARRAY_H
#define __TEMPL_S_ARRAY_H


#include <math_x.h>
#include <io_define.h>
#include <math_define.h>
#include <tool_quick_sort.h>
#include <tool_err_handling.h>
#include <vector>
#include <cstring>
#include <utility>
#include <algorithm>


FORVARD_DECL_TEMPLATE_TYPENAME( class SArray );
FORVARD_DECL_TEMPLATE_TYPENAME( bool   set_array_size (       SArray<Type> &, size_t newSize, bool clear ) );
FORVARD_DECL_TEMPLATE_TYPENAME( Type * add_n_to_array (       SArray<Type> &, size_t n ) );
FORVARD_DECL_TEMPLATE_TYPENAME( size_t find_in_array  ( const SArray<Type> &, const Type & object ) );
FORVARD_DECL_TEMPLATE_TYPENAME( bool   fill_array     (       SArray<Type> &, size_t fillCount, const Type & fillData ) );
FORVARD_DECL_TEMPLATE_TYPENAME( bool   fill_array_zero(       SArray<Type> &, size_t fillCount, size_t startIndex ) );
FORVARD_DECL_TEMPLATE_TYPENAME( reader & CALL_DECLARATION operator >> ( reader & in,        SArray<Type> & ref ) );
FORVARD_DECL_TEMPLATE_TYPENAME( writer & CALL_DECLARATION operator << ( writer & out, const SArray<Type> & ref ) );
FORVARD_DECL_TEMPLATE_TYPENAME( reader & CALL_DECLARATION operator >> ( reader & in,        SArray<Type> *& ptr ) );
FORVARD_DECL_TEMPLATE_TYPENAME( writer & CALL_DECLARATION operator << ( writer & out, const SArray<Type> * ptr ) );


//------------------------------------------------------------------------------
// \ru Функция сравнения для сортировки упорядочивает элементы по возрастанию (элементы должны иметь функции > и <). 
// \en The comparison function for sorting orders elements in ascending (elements should have functions > and  <). \~
// ---
template <class Type>
inline int CompareSArrayItems( const Type * f1, const Type * f2 ) {
  return (*f1 > *f2) ? 1 : ((*f1 < *f2) ? -1 : 0);
}


//-----------------------------------------------------------------------------
/** \brief \ru Массив простых структур данных.
           \en Array of plain old data structures (POD). \~
  \details \ru Шаблонный массив, работающий только с простыми (POD) данными, которые 
  могут копироваться или перемещаться в памяти методом memcpy без нарушения целостности объекта. 
  Например, в массиве нельзя хранить объекты, динамически выделяющие память или 
  классы с указателями, а также классы с виртуальными функциями. \n
           \en A template array working with POD-only data that can be copied or moved in 
  memory by 'memcpy' maintaining the validity of the object. For sample, the array should 
  not contain objects which dynamically allocate memory, or classes with virtual functions.
           \~  
  \ingroup Base_Tools_Containers
*/
// ---
template <class Type>
class SArray {
public:
  typedef Type value_type;
  typedef Type const & const_reference;
  typedef Type       & reference;
protected :
  size_t  count; ///< \ru Количество элементов в массиве. \en The number of elements in array. 
  size_t  upper; ///< \ru Под какое количество элементов выделена память. \en The number of elements the memory is allocated for. 
  uint16  delta; ///< \ru Приращение по количеству элементов при выделении дополнительной памяти. \en Increment by the number of elements while the allocation of additional memory. 
private :
  Type *  parr; ///< \ru Указатель на первый элемент массива. \en A pointer to the first array element. 

public :
  /// \ru Конструктор. \en Constructor. 
  explicit SArray( size_t i_max = 0, uint16 i_delta = 1 );
  /// \ru Конструктор копирования. \en Copy constructor. 
  SArray( const SArray<Type> & );
  /// \ru Конструктор копирования. \en Copy constructor. 
  explicit SArray( const std::vector<Type> & );
  /// \ru Деструктор. \en Destructor. 
  virtual ~SArray() { set_array_size( *this, 0, true/*clear*/ ); }
  
public:
  /// \ru Количество элементов, под которое зарезервирована память. \en The number of elements the memory is allocated for.
          size_t  Upper() const                  { return upper; }
  /// \ru Получить приращение по количеству элементов при выделении дополнительной памяти. \en Get the increment by the number of elements while the allocation of additional memory. 
          uint16  Delta() const                  { return delta; }
  /// \ru Установить приращение по количеству элементов при выделении дополнительной памяти (1 - автоприращение). \en Set the increment by the number of elements while the allocation of additional memory (1 - autoincrement). 
          void    Delta( uint16 newDelta ) { delta = newDelta; }
  /// \ru Установить максимальное из приращений. \en Set the maximum increment. 
          void    SetMaxDelta( uint16 newDelta ) { if ( delta < newDelta ) delta = newDelta; }

  /// \ru Функции, выделяющие потенциально большие участки памяти, возвращают результат операции (успех/ошибка).
  /// \en Functions that allocate potentially large memory, return an operation result (success/error). 
          bool    SetSize( size_t newSize, bool clear/*=true*/ );       ///< \ru Установить новый размер массива. \en Set the new size of an array. 
          bool    Reserve( size_t n, bool addAdditionalSpace = true );  ///< \ru Зарезервировать место под столько элементов. \en Reserve space for a given number of elements. 

          void    Flush    () { count = 0; }                            ///< \ru Обнулить количество элементов. \en Set the number of elements to null. 
          void    HardFlush() { Flush(); Adjust(); }                    ///< \ru Освободить всю память. \en Free the whole memory. 
          void    Adjust();                                             ///< \ru Удалить лишнюю память. \en Free the unnecessary memory. 
          Type *  Add();                                                ///< \ru Добавить элемент в конец массива. \en Add an element to the end of the array. 
          Type *  AddItems ( size_t n );                                ///< \ru Добавить n элементов в конец массива. \en Add n elements to the end of the array. 
          Type *  Add      ( const Type & );                            ///< \ru Добавить элемент в конец массива. \en Add an element to the end of the array. 
          Type *  AddAt    ( const Type & ent, size_t index ) { return InsertInd( index, ent ); } ///< \ru Вставить элемент по индексу. \en Insert an element by the index. 
          Type *  AddAfter ( const Type &, size_t index );              ///< \ru Добавить элемент после указанного. \en Add an element after the specified one. 
          Type *  InsertObj( const Type & index, const Type & ent );    ///< \ru Вставить элемент перед указанным. \en Insert an element before the specified one. 
          Type *  InsertInd( size_t index, const Type & );              ///< \ru Вставить элемент перед указанным. \en Insert an element before the specified one. 
          Type *  InsertInd( size_t index );                            ///< \ru Вставить пустой элемент перед указанным. \en Insert the empty element before the specified one. 
          void    Remove( Type * firstItr, Type * lastItr );            ///< \ru Удалить элементы из массива начиная с позиции firstItr до lastItr-1 включительно. \en Delete elements from the array from firstItr to lastItr-1 inclusively. 
          void    RemoveInd( size_t firstIdx, size_t lastIdx );         ///< \ru Удалить элементы из массива начиная с индекса firstIdx до lastIdx-1 включительно. \en Delete elements from the array from firstIdx to lastIdx-1 inclusively. 
          void    RemoveInd( size_t idx );                              ///< \ru Удалить элемент из массива по индексу. \en Delete an element from array by the index. 
          size_t  RemoveObj( const Type & delObject );                  ///< \ru Удалить элемент из массива. \en Delete an element from array. 
          bool    Fill( size_t fillCount, const Type & fillData );      ///< \ru Заполнить массив значениями. \en Fill an array. 
          bool    FillZero( size_t fillCount, size_t startIndex = 0 );  ///< \ru Заполнить массив байтами содержащими 0. \en Fill an array by bites consisting of 0. 
          size_t  FindIt   ( const Type & ) const;                      ///< \ru Вернуть индекс элемента в массиве. \en Return an index of the element in the array. 
          bool    IsExist  ( const Type & ) const;                      ///< \ru true если элемент найден. \en true if the element is found. 
          size_t  Count()    const { return count; }                    ///< \ru Дать количество элементов массива. \en Get the number of elements in array. 
          ptrdiff_t MaxIndex() const { return ((ptrdiff_t)count - 1); } ///< \ru Дать количество элементов массива. \en Get the number of elements in array. 

          bool    SetCArray( const Type * o, size_t count );            ///< \ru Присвоить значения из c-массива. \en Assign the value from the c-array. 

          void    Swap     ( SArray & arr );                            ///< \ru Обменять местами данные массивов. \en Swap data of arrays. 

  SArray<Type> &  operator =  ( const SArray<Type> & );           ///< \ru Оператор присваивания. \en Assignment operator. 
  SArray<Type> &  operator =  ( const std::vector<Type> & );      ///< \ru Оператор присваивания. \en Assignment operator. 
  SArray<Type> &  operator += ( const SArray<Type> & );           ///< \ru Оператор слияния. \en Merging operator. 
  SArray<Type> &  operator += ( const std::vector<Type> & );      ///< \ru Оператор слияния. \en Merging operator. 
          bool    operator == ( const SArray<Type>& w ) const;    ///< \ru Оператор равенства. \en Equality operator. 

  /// \ru Оператор доступа по индексу. \en Access by index operator. 
          Type &  operator []( size_t loc ) const;

  typedef int     (*CompFunc)( const Type *, const Type * ); ///< \ru Шаблон функции сортировки. \en A template of sorting function. 
  void            Sort ( CompFunc comp = CompareSArrayItems<Type> );  ///< \ru Сортировать массив. По умолчанию сортирует в порядке возрастания. \en Sort the array. Sort in ascending order by default. 

  const   Type *  GetAddr() const { return parr; }            ///< \ru Выдать адрес начала массива. \en Get the address of the beginning of the array. 
  const   Type *  GetEndAddr() const { return parr + count; }  ///< \ru Выдать указатель конца (следующим за крайним). \en Get a pointer of the end (which follows the last element). 

    /**
      \name \ru Унификация с контейнерами STL.
            \en Unification with STL-compatible containers. \~
      \{
    */

public: 
          bool    empty() const { return 0 == count; }          ///< \ru Проверить не пустой ли массив (т.е. не равен ли его размер 0). \en Test whether vector is empty (i.e. whether its size is 0).
          size_t  size() const { return count; }              ///< \ru Дать количество элементов массива. \en Get the number of elements in array. 
          void    reserve( size_t n ) { Reserve( n, false ); }  ///< \ru Зарезервировать место под столько элементов. \en Reserve space for a given number of elements. 
          void    resize( size_t n, Type val = Type() );        ///< \ru Изменить размер массива. \en Resizes the container so that it contains n elements. 
          size_t  capacity() const { return Upper(); }          ///< \ru Под какое количество элементов выделена память? \en What is the number of elements the memory is allocated for? 
          void    push_back( const Type & e ) { Add( e ); }     ///< \ru Добавить элемент в конец массива. \en Add an element to the end of the array. 
          void    pop_back() { RemoveInd( MaxIndex() ); }       ///< \ru Удалить элемент из конца массива. \en Removes the last element in the array, reducing the array size by one.
          template <class Iterator>
          void    insert( Iterator pos, const Type & e );       ///< \ru Вставить элемент перед указанным. \en Insert an element before the specified one. 
          template <class Iterator>
          void    erase( Iterator pos );                        ///< \ru Удалить элемент из массива по индексу. \en Delete an element from array by the index. 
          template <class Iterator>
          void    erase( Iterator first, Iterator last );       ///< \ru Удалить элементы из массива начиная с индекса first до last-1 включительно. \en Delete elements from the array from first to last-1 inclusively. 
          void    clear() { Flush(); }                          ///< \ru Обнулить количество элементов. \en Set the number of elements to null. 
          void    shrink_to_fit() { Adjust(); }                 ///< \ru Удалить лишнюю память. \en Free the unnecessary memory (Reduce capacity).  

          template <class Iterator>
          void    assign ( Iterator first, Iterator last ); ///< \ru Присвоить массиву новое содержимое, заменив его текущее содержимое. \en Assign new contents to the array, replacing its current contents.
          void    assign ( size_t n, const Type & val ) { resize( n, val ); } ///< \ru Присвоить массиву новое содержимое, заменив его текущее содержимое. \en Assign new contents to the array, replacing its current contents.

  const   Type *  begin()   const { return parr; }          ///< \ru Получить указатель на первый элемент массива. \en Get the pointer to the first array element. 
          Type *  begin()         { return parr; }          ///< \ru Получить указатель на первый элемент массива. \en Get the pointer to the first array element. 
  const   Type *  end()     const { return parr + count; }  ///< \ru Получить указатель на участок памяти после массива. \en Get the pointer to the piece of memory after the array. 
          Type *  end()           { return parr + count; }  ///< \ru Получить указатель на участок памяти после массива. \en Get the pointer to the piece of memory after the array.   
  const   Type *  cbegin()  const { return parr; }          ///< \ru Получить указатель на первый элемент массива. \en Get the pointer to the first array element. 
  const   Type *  cend()    const { return parr + count; }  ///< \ru Получить указатель на участок памяти после массива. \en Get the pointer to the piece of memory after the array. 
  const   Type &  front()   const;
          Type &  front();
  const   Type &  back()    const;
          Type &  back();

    /**
      \}
    */

protected :
  bool    CatchMemory();          ///< \ru Захватить память. \en Catch memory. 
  bool    AddMemory( size_t n );  ///< \ru Обеспечить место под n элементов, независимо от AutoDelta. \en Provide memory for n elements, independently from AutoDelta. 
  size_t  AutoDelta() const { return ::KsAutoDelta( count, delta ); } ///< \ru Вычислить автоприращение. \en Calculate autoincrement. 
  
  /// \ru Перезахватить память. \en Reallocate memory. 
  TEMPLATE_FRIEND bool    set_array_size  TEMPLATE_SUFFIX (       SArray<Type> &, size_t newSize, bool clear );
  /// \ru Добавить памяти под n элментов массива и вернуть указатель на начало выделеного участка памяти. \en Add memory for n elements of the array and return a pointer to the beginning of the selected piece of memory. 
  TEMPLATE_FRIEND Type *  add_n_to_array  TEMPLATE_SUFFIX (       SArray<Type> &, size_t n );
  /// \ru Найти элемент в массиве. \en Find an element in the array. 
  TEMPLATE_FRIEND size_t  find_in_array   TEMPLATE_SUFFIX ( const SArray<Type> &, const Type & object );
  /// \ru Заполнить fillCount элементов массива копиями объекта fillData. \en Fill fillCount elements of the array by copies of the object fillData. 
  TEMPLATE_FRIEND bool    fill_array      TEMPLATE_SUFFIX (       SArray<Type> &, size_t fillCount, const Type & fillData );
  /// \ru Заполнить fillCount элементов массива нулями. \en Fill fillCount elements of the array by nulls. 
  TEMPLATE_FRIEND bool    fill_array_zero TEMPLATE_SUFFIX (       SArray<Type> &, size_t fillCount, size_t startIndex );

  /// \ru Оператор чтения. \en Read operator. 
  TEMPLATE_FRIEND reader & CALL_DECLARATION operator >> TEMPLATE_SUFFIX ( reader & in,        SArray<Type> & ref );
  /// \ru Оператор записи. \en Write operator. 
  TEMPLATE_FRIEND writer & CALL_DECLARATION operator << TEMPLATE_SUFFIX ( writer & out, const SArray<Type> & ref );
  /// \ru Оператор чтения. \en Read operator. 
  TEMPLATE_FRIEND reader & CALL_DECLARATION operator >> TEMPLATE_SUFFIX ( reader & in,        SArray<Type> *& ptr );
  /// \ru Оператор записи. \en Write operator. 
  TEMPLATE_FRIEND writer & CALL_DECLARATION operator << TEMPLATE_SUFFIX ( writer & out, const SArray<Type> * ptr );

#ifdef __DEBUG_MEMORY_ALLOCATE_FREE_
public:
  void * operator new    ( size_t );
  void   operator delete ( void *, size_t );
#endif // __DEBUG_MEMORY_ALLOCATE_FREE_
};


#ifdef __DEBUG_MEMORY_ALLOCATE_FREE_
//------------------------------------------------------------------------------
// \ru Перегрузка оператора new. \en Overloading of the "new" operator. 
// ---
template <class Type>
inline void * SArray<Type>::operator new( size_t size ) {
  return ::Allocate( size, typeid(SArray<Type>).name() );
}

//------------------------------------------------------------------------------
// \ru Перегрузка оператора delete. \en Overloading of the "delete" operator. 
// ---
template <class Type>
inline void SArray<Type>::operator delete( void * ptr, size_t size ) {
  ::Free( ptr, size, typeid(SArray<Type>).name() );
}
#endif // __DEBUG_MEMORY_ALLOCATE_FREE_


//------------------------------------------------------------------------------
// \ru Конструктор массива \en Constructor of an array 
// ---
template <class Type>
inline SArray<Type>::SArray( size_t i_max, uint16 i_delta )
  : count( 0 )
  , upper( 0 )
  , delta( i_delta )
  , parr ( 0 ) // i_max ? (Type*)new char[ i_max * sizeof(Type) ] : 0 )
{
  if ( !set_array_size( *this, i_max, true/*\ru clear - здесь неважно \en clear - it is not necessary here */ ) && !ExceptionMode::IsEnabled() )
    throw std::bad_alloc(); // \ru Бросить исключение при любом режиме. \en Throw exception in case of any mode.
}


//------------------------------------------------------------------------------
// \ru Конструктор копирования массива \en Copy-constructor of an array 
// ---
template <class Type>
inline SArray<Type>::SArray( const SArray<Type> & o )
  : count( 0 )
  , upper( 0 )
  , delta( o.delta )
  , parr ( 0 )
{
  if ( o.upper ) {
    // \ru operator = копирует только o.count элементов, а нужно все до o.upper \en the operator = copies only o.count elements, but there must be copied all elements to o.upper 
    if ( set_array_size( *this, o.upper, true/*\ru clear - здесь неважно \en clear - it is not necessary here */ ) ) {
      memcpy( static_cast<void *>(parr), static_cast<const void *>(o.parr), o.upper * sizeof(Type) );
      count = o.count;
    }
    else if ( !ExceptionMode::IsEnabled() )
      throw std::bad_alloc(); // \ru Бросить исключение при любом режиме. \en Throw exception in case of any mode.
  }
}


//------------------------------------------------------------------------------
// \ru Конструктор копирования массива \en Copy-constructor of an array 
// ---
template <class Type>
inline SArray<Type>::SArray( const std::vector<Type> & o )
  : count( 0 )
  , upper( 0 )
  , delta( 1 )
  , parr ( 0 )
{
  const size_t oCount = o.size();
  if ( oCount ) {
    // \ru operator = копирует только o.count элементов, а нужно все до o.upper \en the operator = copies only o.count elements, but there must be copied all elements to o.upper 
    if ( set_array_size(*this, oCount, true/*\ru clear - здесь неважно \en clear - it is not necessary here */) ) {
      memcpy( parr, &o[0], oCount * sizeof(Type) );
      count = oCount;
    }
    else if ( !ExceptionMode::IsEnabled() )
      throw std::bad_alloc(); // \ru Бросить исключение при любом режиме. \en Throw exception in case of any mode.
  }
}

//------------------------------------------------------------------------------
// \ru Оператор доступа по индексу. \en Access by index operator. 
// ---
template <class Type>
inline Type & SArray<Type>::operator []( size_t loc ) const
{
  return parr[loc];
}

//------------------------------------------------------------------------------
// \ru Доступ к первому элементу. \en Access to th first element. 
// ---
template <class Type>
inline const Type & SArray<Type>::front() const
{
  PRECONDITION( !empty() );
  return *parr;
}

//------------------------------------------------------------------------------
// \ru Доступ к первому элементу. \en Access to th first element. 
// ---
template <class Type>
inline Type & SArray<Type>::front()
{
  PRECONDITION( !empty() );
  return *parr;
}


//------------------------------------------------------------------------------
// \ru Доступ к последнему элементу. \en Access to th last element. 
// ---
template <class Type>
inline const Type & SArray<Type>::back() const
{
  PRECONDITION( !empty() );
  return *( parr + count - 1 );
}

//------------------------------------------------------------------------------
// \ru Доступ к последнему элементу. \en Access to th last element. 
// ---
template <class Type>
inline Type &SArray<Type>::back()
{
  PRECONDITION( !empty() );
  return *( parr + count - 1 );
}

//------------------------------------------------------------------------------
// \ru Указать новый размер массива. \en Set the new size of an array.
// \ru если clear = true, то массив очистится !!! \en if 'clear' is true than the array will be cleared !!! 
// \ru если clear = true, то присвоить count=0 и старое содержимое не копировать \en if clear = true then set count=0 and do not copy the old content 
// ---
template <class Type>
inline bool SArray<Type>::SetSize( size_t newSize, bool clear ) {
  return set_array_size( *this, newSize, clear );
}


//------------------------------------------------------------------------------
// \ru Зарезервировать место под n элементов. \en Reserve memory for n elements. 
// ---
template <class Type>
inline bool SArray<Type>::Reserve( size_t n, bool addAdditionalSpace ) {
  if ( addAdditionalSpace ) {
    size_t nn = count + n;
    if ( upper < nn )
      return set_array_size( *this, nn, false/*clear*/ );
  }
  else {
    // \ru Захватить память, если требуется памяти больше, чем есть сейчас. \en if there is required more memory that exists at the moment catch it.
    if ( upper < n )
      return set_array_size( *this, n, false/*clear*/ );
    else {
      // C3D_ASSERT( upper <= n ); // Use SetSize!!!
    }
  }
  return true;
}


//------------------------------------------------------------------------------
// \ru Добавить память под n элементов. \en Add memory for n elements.
// ---
template <class Type>
inline bool SArray<Type>::AddMemory( size_t n ) {
  if ( upper - count < n )
    return set_array_size( *this, count + n, false/*clear*/ );
  return true;
}


//------------------------------------------------------------------------------
// \ru Изменить размер массива. \en Resizes the container so that it contains n elements. 
// ---
template <class Type>
inline void SArray<Type>::resize( size_t n, Type val )
{
  if ( n > count ) {
    size_t n0 = count;
    if ( AddItems( n - count ) != 0 ) {
      if ( parr != nullptr ) {
        for ( size_t k = n0; k < n; ++k )
          parr[k] = val;
      }
    }
  }
  else if ( n < count ) {
    count = n;
    Adjust();
  }
}


//------------------------------------------------------------------------------
// \ru отсечь неиспользуемую часть \en cut the useless part 
// ---
template <class Type>
inline void SArray<Type>::Adjust() {
  if ( count < upper )
    set_array_size( *this, count, false/*clear*/ );
}


//------------------------------------------------------------------------------
// \ru добавить 1 элемент в конец массива и вернуть указатель на него \en add 1 element to the end of the array and return a pointer to it 
// ---
template <class Type>
inline Type * SArray<Type>::Add() {
  if ( CatchMemory() )
    return &parr[ count++ ];
  return nullptr;
}


//------------------------------------------------------------------------------
// \ru добавить n элементов в конец массива и вернуть указатель на первый добавленный \en add n elements to the end of the array and return a pointer to the first of added elements 
// ---
template <class Type>
inline Type * SArray<Type>::AddItems( size_t n ) {
  return add_n_to_array( *this, n );
}


//------------------------------------------------------------------------------
// \ru добавить 1 элемент в конец массива \en add 1 element to the end of array 
// ---
template <class Type>
inline Type * SArray<Type>::Add( const Type & ent ) 
{
  if ( CatchMemory() )
    return static_cast<Type *>( memcpy(static_cast<void *>(parr+count++), static_cast<const void *>(&ent), sizeof(Type)) );
  return nullptr;
}


//------------------------------------------------------------------------------
// \ru добавить 1 элемент после заданного \en add 1 element after the given one 
// ---
template <class Type>
inline Type * SArray<Type>::AddAfter( const Type & ent, size_t index ) {
  PRECONDITION( index < count );
  if ( index < count && CatchMemory() ) {

    memmove( parr + index + 2, parr + index + 1, sizeof(Type)*(count - index - 1) );
    count++;

    return (Type*)memcpy( parr + index + 1, &ent, sizeof(Type) );
  }
  return nullptr;
}


//------------------------------------------------------------------------------
// \ru вставить 1 элемент перед указанным \en insert 1 element before the specified one 
// ---
template <class Type>
inline Type * SArray<Type>::InsertInd( size_t index, const Type & ent ) {
  PRECONDITION( index <= count );
  if ( index <= count && CatchMemory() ) { // \ru добавить памяти, если все использовано \en add memory if whole allocated memory is used 

    if ( index >= count )
      index = count;
    else {
      // \ru передвинем вправо все элементы массива с последнего до указанного \en move to the right all elements of the array from the last to the specified one 
      memmove( parr + index + 1, parr + index, (count - index) * sizeof(Type) );
    }
    count++;

    return (Type*)memcpy( parr + index, &ent, sizeof(Type) );  // \ru записываем новый элемент \en writing new element 
  }
  return nullptr;
}


//------------------------------------------------------------------------------
// \ru вставить пустой элемент перед указанным \en insert the empty element before the specified one. 
// ---
template <class Type>
inline Type * SArray<Type>::InsertInd( size_t index ) {
  PRECONDITION( index <= count );
  if ( index <= count && CatchMemory() ) { // \ru добавить памяти, если все использовано \en add memory if whole allocated memory is used 

  // \ru передвинем вправо все элементы массива с последнего до указанного \en move to the right all elements of the array from the last to the specified one 
    memmove( parr + index + 1, parr + index, (count - index) * sizeof(Type) );
    count++;

    return (Type*)( parr + index );  // \ru записываем новый элемент \en writing new element 
  }
  return nullptr;
}


//------------------------------------------------------------------------------
// \ru вставить элемент перед указанным \en insert element before the specified one 
// ---
template <class Type>
inline Type * SArray<Type>::InsertObj( const Type & ind, const Type & ent ) {
  size_t index = FindIt(ind);
  return ( index != SYS_MAX_T) ? InsertInd( index, ent ) : 0;
}


//------------------------------------------------------------------------------
// \ru вернуть индекс элемента в массиве \en return an index of the element in the array 
// ---
template <class Type>
inline size_t SArray<Type>::FindIt( const Type & object ) const {
  return find_in_array( *this, object );
}


//------------------------------------------------------------------------------
// \ru true если элемент найден \en true if the element was found 
// ---
template <class Type>
inline bool SArray<Type>::IsExist( const Type & object ) const {
  return find_in_array( *this, object ) != SYS_MAX_T;
}


//------------------------------------------------------------------------------
// \ru удалить элемент из массива \en delete an element from array 
// ---
template <class Type>
inline size_t SArray<Type>::RemoveObj( const Type & delObject )
{
  size_t ind = FindIt( delObject );
  if ( ind != SYS_MAX_T )
    RemoveInd( ind );
  return ind;
}


//------------------------------------------------------------------------------
// \ru удалить элемент из массива \en delete an element from array 
// ---
template <class Type>
inline void SArray<Type>::RemoveInd( size_t idx ) 
{
  // RemoveInd( idx, idx+1 );
  if ( parr && idx < count ) {
    Type * ptr = parr + idx;
    Remove( ptr, ptr+1 );
  }
}


//------------------------------------------------------------------------------
// \ru Вставить элемент перед указанным. \en Insert an element before the specified one. 
// ---
template <class Type>
template <class Iterator>
void SArray<Type>::insert( Iterator pos, const Type & e )
{
  if ( !begin() ) {
    reserve( 1 );
    pos = begin();
  }
  if ( begin() ) {
    const ptrdiff_t k = std::distance( (Iterator)begin(), pos );
    if ( k >= 0 && k <= (ptrdiff_t)count )
      InsertInd( k, e );
  }
}


//------------------------------------------------------------------------------
// \ru Удалить элемент из массива по индексу. \en Delete an element from array by the index. 
// ---
template <class Type>
template <class Iterator>
void SArray<Type>::erase( Iterator pos )
{
  if ( begin() ) {
    const ptrdiff_t k = std::distance( (Iterator)begin(), pos );
    if ( k >= 0 && k < (ptrdiff_t)count )
      RemoveInd( k );
  }
}

//------------------------------------------------------------------------------
// \ru Удалить элементы из массива начиная с индекса first до last-1 включительно. \en Delete elements from the array from first to last-1 inclusively. 
// ---
template <class Type>
template <class Iterator>
void SArray<Type>::erase( Iterator first, Iterator last )
{
  if ( begin() ) {
    const ptrdiff_t k1 = std::distance( (Iterator)begin(), first );
    const ptrdiff_t k2 = std::distance( (Iterator)begin(), last );

    if ( k1 >= 0 && k1 < k2 && k2 <= (ptrdiff_t)count ) {
      RemoveInd( k1, k2 );
    }
  }
}


//------------------------------------------------------------------------------
// \ru Удалить группу элементов начиная с firstIdx до lastIdx-1 включительно \en Delete the group of elements from firstIdx to lastIdx-1 inclusively 
// ---
template <class Type>
inline void SArray<Type>::RemoveInd( size_t firstIdx, size_t lastIdx ) {
  if ( parr )
    Remove( parr+firstIdx, parr+lastIdx );
}


//------------------------------------------------------------------------------
// \ru Удалить элементы из массива начиная с позиции firstItr до lastItr-1 включительно \en Delete elements from the array from firstItr to lastItr-1 inclusively 
// ---
template <class Type>
inline void SArray<Type>::Remove( Type * firstItr, Type * lastItr )
{  
  PRECONDITION( firstItr >= parr && firstItr < lastItr && (lastItr - parr) <= (ptrdiff_t)count );
  if ( firstItr >= parr && firstItr < lastItr ) {
    ptrdiff_t copyCount = ( parr + count ) - lastItr;
    if ( copyCount >= 0 ) {
      if ( copyCount > 0 )
        memmove( static_cast<void *>( firstItr ), static_cast<const void *>( lastItr ), copyCount * sizeof( Type ) );
      count -= ( lastItr - firstItr );
    }
  }
}


//------------------------------------------------------------------------------
// \ru заполнить массив значениями \en fill an array 
// ---
template <class Type>
inline bool SArray<Type>::Fill( size_t fillCount, const Type & fillData ) {
  return fill_array( *this, fillCount, fillData );
}


//------------------------------------------------------------------------------
// \ru заполнить массив байтами содержащими 0 \en fill an array by bites consisting of 0 
// \ru размер полученного массива устанавливается в fillCount + startIndex \en a size of the obtained array is set to fillCount + startIndex. 
// ---
template <class Type>
inline bool SArray<Type>::FillZero( size_t fillCount, size_t startIndex ) {
  return fill_array_zero( *this, fillCount, startIndex );
}


//------------------------------------------------------------------------------
// \ru присвоение массива массиву \en assignment of an array to array 
// ---
template <class Type>
inline SArray<Type> & SArray<Type>::operator = ( const SArray<Type> & o ) {
  if ( this != &o ) { // \ru при присваивании самому себе delete делать нельзя \en when it is assigned to itself operato delete should not be used 
    Flush();
    if ( AddMemory(o.count) ) {  // \ru обеспечить память на такое кол-во элементов \en allocate memory for the given number of elements 
      count = o.count;
      if ( count && parr )
        memcpy( static_cast<void *>(parr), static_cast<const void *>(o.parr), count * sizeof(Type) );
    }
  }
  return *this;
}


//------------------------------------------------------------------------------
// \ru присвоение массива массиву \en assignment of an array to array 
// ---
template <class Type>
inline SArray<Type> & SArray<Type>::operator = ( const std::vector<Type> & o ) {
  Flush();
  if ( AddMemory(o.size()) ) {  // \ru обеспечить память на такое кол-во элементов \en allocate memory for the given number of elements 
    count = o.size();
    if ( count && parr )
      memcpy( static_cast<void *>(parr), static_cast<const void *>(&o[0]), count * sizeof(Type) );
  }
  return *this;
}


//------------------------------------------------------------------------------
// \ru присвоение массива массиву \en assignment of an array to array 
// ---
template <class Type>
inline bool SArray<Type>::SetCArray( const Type * o, size_t countC )
{
  Flush();
  bool bRes = AddMemory( countC );
  if ( bRes ) {  // \ru обеспечить память на такое кол-во элементов \en allocate memory for the given number of elements   
    count = countC;
    if ( count && parr )
      memcpy( parr, o, count * sizeof(Type) );
  }
  return bRes;
}


//-------------------------------------------------------------------------------
// \ru обменять местами данные массивов \en swap data of arrays 
// ---
template <class Type>
void SArray<Type>::Swap( SArray & arr ) {
  std::swap( count, arr.count );
  std::swap( upper, arr.upper );
  std::swap( delta, arr.delta );
  std::swap( parr,  arr.parr  );
}


//------------------------------------------------------------------------------
// \ru добавление массива к массиву \en add the array to the array 
// ---
template <class Type>
inline SArray<Type> & SArray<Type>::operator += ( const SArray<Type> & o ) {
  if ( o.size() ) {
    size_t addSize = o.size();
    if ( AddMemory(addSize) ) {  // \ru обеспечить память на такое кол-во элементов \en allocate memory for the given number of elements 
      if ( parr )
        memcpy( static_cast<void *>(parr + count), static_cast<const void *>(o.parr), addSize * sizeof(Type) );
      count += addSize;
    }
  }
  return *this;
}


//------------------------------------------------------------------------------
// \ru добавление массива к массиву \en add the array to the array 
// ---
template <class Type>
inline SArray<Type> & SArray<Type>::operator += ( const std::vector<Type> & o ) {
  if ( o.size() ) {
    size_t addSize = o.size();
    if ( AddMemory(addSize) ) {  // \ru обеспечить память на такое кол-во элементов \en allocate memory for the given number of elements 
      if ( parr )
        memcpy( static_cast<void *>(parr + count), static_cast<const void *>(&o[0]), addSize * sizeof(Type) );
      count += addSize;
    }
  }
  return *this;
}


//------------------------------------------------------------------------------
// \ru Если вся память использована - захватить по больше \en If the whole memory is used then catch more memory 
// \ru (применяется перед добавлением в массив одного элемента) \en (it is used before adding one element in the array) 
// ---
template <class Type>
inline bool SArray<Type>::CatchMemory() {
  if ( upper == count )
    return set_array_size( *this, upper + AutoDelta(), false/*clear*/ );
  return true;
}


//------------------------------------------------------------------------------
// \ru сортировать массив \en sort the array 
// --- 
template <class Type>
inline void SArray<Type>::Sort( CompFunc fcmp ) {
  ::KsQSort( (void *)parr, count, sizeof(Type), (KsQSortCompFunc)fcmp );
}


//----------------------------------------------------------------------------------------
// \ru Присвоить массиву новое содержимое, заменив его текущее содержимое. 
// \en Assign new contents to the array, replacing its current contents.
//---
template <class Type>
template <class Iterator>
void SArray<Type>::assign( Iterator first, Iterator last )
{
  const ptrdiff_t newCount = std::distance( first, last );
  if ( set_array_size(*this, newCount, true) ) {
    PRECONDITION( newCount <= (ptrdiff_t)upper && count == 0 );
    for ( ; first != last; ++first, ++count ) {
      parr[count] = *first; // SKIP_SA
    }
  }
}


//------------------------------------------------------------------------------
// \ru Если захвачен не такой размер памяти, то захватить новый если clear = true, то присвоить arr.count=0 и старое содержимое не копировать.
// \en If the size of caught memory is not appropriated then allocate memory again if clear = true then set arr.count=0 and do not copy the old content. 
// ---
template <class Type>
bool set_array_size( SArray<Type> & arr, size_t newSize, bool clear )
{
  bool res = true;
  if ( newSize != arr.upper ) {
    size_t sizeOfType = sizeof(Type);

    // \ru половина адресного пространства для 64- и 32-разрядного приложения \en a half of address space for 64- and 32-bit application  
    //    if ( double(newSize) * sizeOfType < /*OV_x64 0x7FFFFFFF*/(double)SYS_MAX_ST ) { //-V113
    if ( ::TestNewSize( sizeOfType, newSize ) ) {
      try {
#ifdef __REALLOC_ARRAYS_STATISTIC_
        void * oldParr = arr.parr;
        size_t oldSize = arr.upper;
#endif // __REALLOC_ARRAYS_STATISTIC_

#ifdef USE_REALLOC_IN_ARRAYS
        //YYK V15 #77319 Некорректная отрисовка на видеокартах семейства NVIDIA Quadro, 
        //YYK V15        требуется 16-байтовое выравнивание массивов вершин и нормалей.
        //YYK V15        Исправлять приходится глобально для всех экземпляров SArray
        //YYK V15 arr.parr = (Type*) REALLOC_ARRAY_SIZE( arr.parr, newSize * sizeOfType, clear );
#ifdef C3D_WINDOWS //_MSC_VER // win
        arr.parr = (Type *)_aligned_realloc( arr.parr, newSize * sizeOfType, 16 );
#else
        arr.parr = (Type *)REALLOC_ARRAY_SIZE( arr.parr, newSize * sizeOfType, clear );
#endif // win
#else
        //YYK V15 #77319 Type * p_tmp = newSize ? (Type*)new char[ newSize * sizeOfType ] : 0;
#ifdef C3D_WINDOWS //_MSC_VER // win
        Type * p_tmp = newSize ? (Type*)_aligned_malloc( newSize * sizeOfType, 16 ) : nullptr;
#else
        Type * p_tmp = newSize ? (Type*)new char[newSize * sizeOfType] : 0;
#endif // win

        if ( !clear && arr.parr && p_tmp )
          memcpy( static_cast<void *>(p_tmp), static_cast<const void *>(arr.parr), std_min(arr.upper, newSize) * sizeOfType );

        if ( arr.parr )
          //YYK V15 #77319 delete [] (char *) arr.parr;
#ifdef C3D_WINDOWS //_MSC_VER // win
          _aligned_free( arr.parr );
#else
          delete[](char *) arr.parr;
#endif // win

        arr.parr = p_tmp;
#endif //USE_REALLOC_IN_ARRAYS

        arr.upper = newSize;

#ifdef __REALLOC_ARRAYS_STATISTIC_
        REALLOC_ARRAY_STATISTICS( oldParr, oldSize * sizeOfType, arr.parr, newSize * sizeOfType, 0/*SArray*/ );
#endif // __REALLOC_ARRAYS_STATISTIC_
      }
      catch ( const std::bad_alloc & ) {
        newSize = 0; // \ru т.к. ниже есть код с применением newSize \en because there is a code with using of newSize below 
        C3D_CONTROLED_THROW;
        res = false;
      }
      catch ( ... ) {
        if ( newSize == 0 ) { // \ru Не смогли корректно удалить arr.parr. \en Failed to delete arr.parr correctly.
          arr.parr = nullptr;
          arr.upper = newSize;
        }
        newSize = 0; // \ru т.к. ниже есть код с применением newSize \en because there is a code with using of newSize below 
        C3D_CONTROLED_THROW;
        res = false;
      }
    }
    else {
      PRECONDITION( false ); // \ru не бывает столько памяти \en incorrect size of memory 
      newSize = 0; // \ru т.к. ниже есть код с применением newSize \en because there is a code with using of newSize below 
      C3D_CONTROLED_THROW_EX( std::bad_alloc() );
      res = false;
    }
  }

  if ( clear )
    arr.count = 0;
  else
    if ( newSize < arr.count )
      arr.count = newSize;

  return res;
}


//------------------------------------------------------------------------------
// \ru добавить n элементов в конец массива и вернуть указатель на первый добавленный \en add n elements to the end of the array and return a pointer to the first of added elements 
// ---
template <class Type>
Type * add_n_to_array( SArray<Type> & to, size_t n ) {
  if ( n ) {
    if ( to.AddMemory(n) ) {  // \ru обеспечить память на такое кол-во элементов \en allocate memory for the given number of elements 
      size_t oldCount = to.count;
      to.count += n;
      return &to[oldCount];
    }
  }
  return 0;
}


//------------------------------------------------------------------------------
// \ru Внеклассные функции для сравнения содержимого объектов в методах SArray. У объектов должен быть реализован оператор сравнения на равенство.
// \en Out-of-class functions for the comparison of objects contents in the methods of SArray. There should be implemented an operator of comparison for equality in objects.
// ---
template <class Type>
bool IsEqualSArrayItems( const Type & item1, const Type & item2 ) { 
  return item1 == item2;
}

template <class Type>
inline bool IsEqualSArrayItems( const std::pair<Type,Type> & item1, const std::pair<Type,Type> & item2 ) {
  return ((item1.first == item2.first) && (item1.second == item2.second));
}


//------------------------------------------------------------------------------
//
// ---
template <class Type>
size_t find_in_array( const SArray<Type> & arr, const Type & object ) {
  for ( size_t  i = 0; i < arr.count; i++ )
    // \ru OV K6 Использование функции memcmp дает неверные результаты, если для участка кода, \en OV K6 Using of the function memcmp causes incorrect results if for a part of the code  
    // \ru где она вызывается, поставлено выравнивание 8, а размер сравниваемых данные не кратен 8. \en where it is called set the alignment 8 but the size of compared date is not a multiple of 8.  
    // \ru Пусть каждый объект сам решает как ему сравниваться с себе подобным \en Let every object define the way of comparison to the similar object 
    //OV K6     if ( !memcmp( &arr[i], &object, sizeof(Type) ) )
    if ( ::IsEqualSArrayItems( arr[i], object ) )
      return i;

  return SYS_MAX_T;
}


//-------------------------------------------------------------------------------
// \ru Оператор сравнения двух массивов. \en An operator of two arrays comparison.
/**
  \details  
  \ru Осуществляется поэлементной стравнение с возможностью перегрузки
  операции сравния с помощью метода IsEqualSArrayItems.
  \en An element-by-element comparison is performed with the ability to redefine the
  comparison operation using the overloading global function IsEqualSArrayItems.
*/
// ---
template <class Type>
inline bool SArray<Type>::operator == ( const SArray<Type> & w ) const 
{
  if ( count != w.count )
    return false;
  /*
    При размещении в памяти с выравниванием не равным 1, между элементами массива
    возможно появление "дырок" заполненного случайным мусором, т.к. сравнивать этот мусор
    нам незачем, будем сравнивать содержимое массивов поэлементно (через оператор == или 
    путем перегрузки IsEqualSArrayItems).

    While the memory allocation with alignment which is not equal 1 between elements of 
    the array  may appear "holes" filled by random trash, since there is not reason to 
    compare this trash we will compare the content of arrays element by element 
    (using the operator == of an object or by overloading the func IsEqualSArrayItems).
  */
  for ( size_t i = 0; i < count; i++ ) 
  {
    if ( !::IsEqualSArrayItems( (*this)[i], w[i] ) )
      return false;
  }

  return true;
}


//------------------------------------------------------------------------------
//
// ---
template <class Type>
bool fill_array( SArray<Type> & arr, size_t fillCount, const Type & fillData ) 
{
  arr.Flush();
  bool res = arr.AddMemory( fillCount );
  if ( res ) {  // \ru обеспечить память на такое кол-во элементов \en allocate memory for the given number of elements 
    arr.count = fillCount;
    for ( size_t i = 0; i < arr.count; i++ ) {
      arr[i] = fillData; // Потребуем наличия оператора присвоения
    }
  }
  return res;
}


//------------------------------------------------------------------------------
//
// ---
template <class Type>
bool fill_array_zero( SArray<Type> & arr, size_t fillCount, size_t startIndex ) 
{
  bool res = arr.AddMemory( fillCount + startIndex );  // \ru обеспечить память на такое кол-во элементов \en allocate memory for the given number of elements 
  if ( res ) {
    arr.count = fillCount + startIndex;       // \ru установить размер массива \en set the size of the array 
    memset( (void*)&arr[startIndex], 0, fillCount * sizeof(Type) );
  }
  return res;
}


////////////////////////////////////////////////////////////////////////////////
//
// \ru Mассив с итераторными функциями \en An Array with Iterator Functions 
//
////////////////////////////////////////////////////////////////////////////////


FORVARD_DECL_TEMPLATE_TYPENAME( class   SIArray );
FORVARD_DECL_TEMPLATE_TYPENAME( void    for_each_in_array  ( const SIArray<Type> &, typename SIArray<Type>::IteratorFunc ) );
FORVARD_DECL_TEMPLATE_TYPENAME( void    for_each_in_array  ( const SIArray<Type> &, typename SIArray<Type>::ParIteratorFunc, void * pars ) );
FORVARD_DECL_TEMPLATE_TYPENAME( size_t  first_that_in_array( const SIArray<Type> &, typename SIArray<Type>::CompareFunc,     void * pars, size_t from ) );


//-----------------------------------------------------------------------------
/** \brief \ru Одномерный массив обьектов с итераторными функциями.
           \en One-dimensional array of objects with iterator functions. \~
  \details \ru Одномерный массив обьектов, не содержащих указателей (вернее, не имеющих деструкторов).
    В массиве нельзя хранить объекты, содержащие указатели или классы с указателями, 
    а также абстрактные классы с наследниками. \n
           \en One-dimensional array of objects without pointers (i.e. without destructors).
    The array should not contain objects with pointers or classes with pointers, 
    or abstract classes with inheritors. \n \~
  \ingroup Base_Tools_Containers
*/
// ---
template <class Type>
class SIArray : public SArray<Type> {
public :
  SIArray( size_t i_max=0, uint16 i_delta=1 ) : SArray<Type>( i_max, i_delta ) {}
  SIArray( const SArray<Type> & other )       : SArray<Type>( other ) {}

  typedef void    (*IteratorFunc) ( Type & obj );
  void            ForEach( IteratorFunc func ) const;
  typedef void    (*ParIteratorFunc) ( Type & obj, void * pars );
  void            ForEach( ParIteratorFunc func, void * pars ) const;
  typedef bool    (*CompareFunc) ( Type & obj, void * pars );
  size_t          FirstThat( CompareFunc func, void * pars, size_t from = 0 ) const;

private:
  TEMPLATE_FRIEND void    for_each_in_array   TEMPLATE_SUFFIX ( const SIArray<Type> &, IteratorFunc );
  TEMPLATE_FRIEND void    for_each_in_array   TEMPLATE_SUFFIX ( const SIArray<Type> &, ParIteratorFunc, void * pars );
  TEMPLATE_FRIEND size_t  first_that_in_array TEMPLATE_SUFFIX ( const SIArray<Type> &, CompareFunc,     void * pars, size_t from );
};


//------------------------------------------------------------------------------
// \ru выполнить функцию для каждого элемента \en perform the function for every element 
// ---
template <class Type>
inline void SIArray<Type>::ForEach( IteratorFunc func ) const {
  for_each_in_array<Type>( *this, func );
}


//------------------------------------------------------------------------------
// \ru выполнить функцию с параметрами для каждого элемента \en perform the function with parameters for every element 
// ---
template <class Type>
inline void SIArray<Type>::ForEach( ParIteratorFunc func, void * pars ) const {
  for_each_in_array<Type>( *this, func, pars );
}


//------------------------------------------------------------------------------
// \ru найти элемент по условию \en find an element by condition 
// ---
template <class Type>
inline size_t SIArray<Type>::FirstThat( CompareFunc func, void* pars, size_t from ) const {
  return first_that_in_array<Type>( *this, func, pars, from );
}


//------------------------------------------------------------------------------
//
// ---
template <class Type>
void for_each_in_array( const SIArray<Type> & arr, typename SIArray<Type>::IteratorFunc func ) {
  for( size_t i = 0; i < arr.Count(); i++ )
    func( arr[i] );
}


//------------------------------------------------------------------------------
//
// ---
template <class Type>
void for_each_in_array( const SIArray<Type>& arr, typename SIArray<Type>::ParIteratorFunc func, void* pars ) {
  for( size_t i = 0; i < arr.Count(); i++ )
    func( arr[i], pars );
}


//------------------------------------------------------------------------------
//
// ---
template <class Type>
size_t first_that_in_array( const SIArray<Type> & arr, typename SIArray<Type>::CompareFunc func, void * pars, size_t from ) {
  for( size_t i = from; i < arr.Count(); i++ ) {
    if ( func(arr[i],pars) )
      return i;
  }
  return SYS_MAX_T;
}


//-----------------------------------------------------------------------------
/** \brief \ru Инициализация массива списком значений.
           \en Initialization of an array by the list of values. \~
  \details \ru Инициализация массива списком значений. \n
    Пример использования: \n
    SArray_assign<double> arr; \n
    arr = val1, val2, val3; \n
           \en Initialization of an array by the list of values. \n
    example of using: \n
    SArray_assign<double> arr; \n
    arr = val1, val2, val3; \n \~
  \ingroup Base_Tools_Containers
*/
// ---
template <class T>
class SArray_assign {
protected:
  SArray<T> m_arr; ///< \ru Массив объектов. \en An array of objects. 
public:
  /// \ru Конструктор. \en Constructor. 
  SArray_assign() : m_arr() {}
  /// \ru Конструктор. \en Constructor. 
  explicit SArray_assign( size_t k ) : m_arr( k, 1 ) {}
  /// \ru Конструктор копирования. \en Copy constructor. 
  SArray_assign( const SArray_assign & other ) : m_arr( other.m_arr ) {}
  /// \ru Оператор добавления "через запятую". \en Operator of adding "separated by commas". 
  SArray_assign & operator , (const T & t)  { Set().Add( t ); return *this; }
  /// \ru Оператор присваивания. \en The assignment operator. 
  SArray_assign & operator = (const T & t)  { Set().Flush(); Set().Add( t ); return *this; }

  operator SArray<T>   () const { return m_arr; } ///< \ru Оператор копирования данных. \en An operator of data copying. 
  operator SArray<T> & ()       { return Set(); } ///< \ru Оператор доступа. \en An access operator. 
  const SArray<T> & Get() const { return m_arr; } ///< \ru Оператор доступа. \en An access operator. 
        SArray<T> & Set()       { return m_arr; } ///< \ru Оператор доступа. \en An access operator. 
};


//-------------------------------------------------------------------------------
// \ru функции сравнения двух массивов \en functions of two arrays comparison 
// ---
template <class Type>
inline bool Eq( const SArray<Type> & ar1, const SArray<Type> & ar2 ) {
  return ( ar1 == ar2 );
}


//------------------------------------------------------------------------------
// \ru Внеклассные ф-ии для сравнения содержимого объектов в методах SArray \en Out-of-class functions for the comparison of objects contents in the methods of SArray 
// \ru должны выполнять действия, аналогичные ::memcmp( &obj1, obj2, sizeof(obj1) ) \en they should perform similar to ::memcmp( &obj1, obj2, sizeof(obj1) ) operations 
// ---
template <class Type> 
bool IsLessThanSArrayItems( const Type& obj1, const Type& obj2 ); 

inline bool IsLessThanSArrayItems( const float  &obj1, const float  &obj2 ) { return obj1 < obj2; }
inline bool IsLessThanSArrayItems( const double &obj1, const double &obj2 ) { return obj1 < obj2; }

inline bool IsLessThanSArrayItems( const int8   &obj1, const int8   &obj2 ) { return obj1 < obj2; }
inline bool IsLessThanSArrayItems( const uint8  &obj1, const uint8  &obj2 ) { return obj1 < obj2; }
inline bool IsLessThanSArrayItems( const int16  &obj1, const int16  &obj2 ) { return obj1 < obj2; }
inline bool IsLessThanSArrayItems( const uint16 &obj1, const uint16 &obj2 ) { return obj1 < obj2; }
inline bool IsLessThanSArrayItems( const int    &obj1, const int    &obj2 ) { return obj1 < obj2; }
inline bool IsLessThanSArrayItems( const uint   &obj1, const uint   &obj2 ) { return obj1 < obj2; }
#ifdef C3D_WINDOWS //_MSC_VER // Linux identical int/uint and int32/uint32 
inline bool IsLessThanSArrayItems( const int32  &obj1, const int32  &obj2 ) { return obj1 < obj2; }
inline bool IsLessThanSArrayItems( const uint32 &obj1, const uint32 &obj2 ) { return obj1 < obj2; }
#endif // C3D_WINDOWS

#if defined(PLATFORM_64) // \ru x32 совпадение типов ptrdiff_t и int \en x32 coincidence of ptrdiff_t and int types 
inline bool IsLessThanSArrayItems( const size_t    &obj1, const size_t    &obj2 ) { return obj1 < obj2; }
inline bool IsLessThanSArrayItems( const ptrdiff_t &obj1, const ptrdiff_t &obj2 ) { return obj1 < obj2; }
#endif // PLATFORM_64


//-------------------------------------------------------------------------------
// \ru функции сравнения двух массивов \en functions of two arrays comparison 
// ---
template <class Type>
inline bool Less( const SArray<Type> & ar1, const SArray<Type> & ar2 ) {
  ptrdiff_t count1 = ar1.Count();
  ptrdiff_t count2 = ar2.Count();

  // \ru OV K6 При размещении в памяти с выравниванием не равным 1, между элементами массива \en OV K6 While the memory allocation with alignment which is not equal 1 between elements of the array  
  // \ru возможно появление "дырок" заполненного случайным мусором, т.к. сравнивать этот мусор \en may appear "holes" filled by random trash, since there is not reason to compare this trash 
  // \ru нам ни к чему, будем сравнивать содержимое массивов поэлементно \en we will compare contents of arrays element by element 
  //OV K6 return ::memcmp( ar1.GetAddr(), ar2.GetAddr(), sizeof(Type) * count1 ) < 0;
  for ( ptrdiff_t i = 0, c = std_min(count1, count2); i < c; i++ ) {
    const Type & obj1 = ar1[i]; 
    const Type & obj2 = ar2[i]; 
    if ( !::IsEqualSArrayItems( obj1, obj2 ) )
      // \ru встретили различающиеся элементы \en there are different elements 
      return IsLessThanSArrayItems( obj1, obj2 );
  }

  if ( count1 < count2 )
    return true;

  return false; // \ru массивы полностью идентичны \en arrays are fully identical 
}

//------------------------------------------------------------------------------
// Добавить точки массива в другой массив
// ---
template<typename T, template<typename V> class C>
void AddArrayToArray( const C<T> & fromList, // Источник добавления элементов.
                            C<T> & toList,   // Расширяемый массив.
                            bool   fromBegin,// Начинать брать элементы с начала или конца fromList
                            bool   toBegin ) // Добавлять элементы в начало или в конец toList.
{
  ptrdiff_t from1Count = fromList.size();
  ptrdiff_t i;
  if ( fromBegin ) { // добавить в прямом направлении
    for ( i = 1; i < from1Count; i++ ) {
      if ( toBegin ) // добавить в начало
        toList.insert( toList.begin(), fromList[i] );
      else // добавить в конец
        toList.push_back( fromList[i] );
    }
  }
  else { // добавить в обратном направлении
    for ( i = from1Count-2; i >= 0 && i < from1Count; i-- ) {
      if ( toBegin ) // добавить в начало
        toList.insert( toList.begin(), fromList[i] );
      else
        toList.push_back( fromList[i] );
    }
  }
}

#endif // __TEMPL_S_ARRAY_H
