e8f0fa2d27
- C3d aggiornamento delle librerie.
739 lines
33 KiB
C++
739 lines
33 KiB
C++
////////////////////////////////////////////////////////////////////////////////
|
|
/**
|
|
\file
|
|
\brief \ru Двумерный массив объектов.
|
|
\en Two-dimensional array of objects. \~
|
|
|
|
*/
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifndef __TEMPL_ARRAY2_H
|
|
#define __TEMPL_ARRAY2_H
|
|
|
|
|
|
#include <stdlib.h>
|
|
#include <io_define.h>
|
|
#include <tool_quick_sort.h>
|
|
#include <string.h>
|
|
#include <utility>
|
|
#include <tool_err_handling.h>
|
|
|
|
|
|
class reader;
|
|
class writer;
|
|
|
|
FORVARD_DECL_TEMPLATE_TYPENAME( class Array2 );
|
|
FORVARD_DECL_TEMPLATE_TYPENAME( reader & operator >> ( reader & in, Array2<Type> & ptr ) );
|
|
FORVARD_DECL_TEMPLATE_TYPENAME( writer & operator << ( writer & out, const Array2<Type> & ref ) );
|
|
FORVARD_DECL_TEMPLATE_TYPENAME( reader & operator >> ( reader & in, Array2<Type> *& ptr ) );
|
|
FORVARD_DECL_TEMPLATE_TYPENAME( writer & operator << ( writer & out, const Array2<Type> * ptr ) );
|
|
FORVARD_DECL_TEMPLATE_TYPENAME( bool realloc_line ( Type *& line, size_t oldSize, size_t newSize ) );
|
|
FORVARD_DECL_TEMPLATE_TYPENAME( bool assign_to_array( Array2<Type> &, const Array2<Type> & src ) );
|
|
FORVARD_DECL_TEMPLATE_TYPENAME( bool set_array_size ( Array2<Type> &, size_t lSize, size_t cSize ) );
|
|
FORVARD_DECL_TEMPLATE_TYPENAME( bool insert_column_to_array ( Array2<Type> &, size_t ind ) );
|
|
FORVARD_DECL_TEMPLATE_TYPENAME( bool add_column_to_array ( Array2<Type> & ) );
|
|
FORVARD_DECL_TEMPLATE_TYPENAME( void remove_column_from_array( Array2<Type> &, size_t ind ) );
|
|
FORVARD_DECL_TEMPLATE_TYPENAME( void zero_array( Array2<Type> & ) );
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
/** \brief \ru Двумерный массив объектов.
|
|
\en Two-dimensional array of objects. \~
|
|
\details \ru Двумерный массив объектов. \n
|
|
\en Two-dimensional array of objects. \n \~
|
|
\ingroup Base_Tools_Containers
|
|
*/
|
|
// ---
|
|
template <class Type>
|
|
class Array2 {
|
|
protected :
|
|
Type ** parr; ///< \ru Указатель на первый элемент массива (элементами массива являются указатели на содержимое строк). \en Pointer to first element of array (elements of array are pointers to contents of rows).
|
|
size_t l; ///< \ru Количество строк массива. \en Count of rows in the array.
|
|
size_t c; ///< \ru Количество столбцов массива (то есть длина каждой строки). \en Count of columns of array (i.e. length of each row).
|
|
|
|
protected:
|
|
/// \ru Конструктор по заданной размерности. \en The constructor by a given dimension.
|
|
Array2( size_t lsz, size_t csz );
|
|
public:
|
|
/// \ru Конструктор. \en Constructor.
|
|
Array2() : parr( 0 ), l( 0 ), c( 0 ) {}
|
|
/// \ru Конструктор ограниченной размерности. \en The constructor of restricted dimension.
|
|
Array2( const uint16 & lsz, const uint16 & csz );
|
|
/// \ru Конструктор копирования. \en Copy-constructor.
|
|
explicit Array2( const Array2<Type> & );
|
|
/// \ru Деструктор. \en Destructor.
|
|
~Array2() { set_array_size( *this, 0, 0 ); }
|
|
|
|
public:
|
|
/// \ru Создать массив заданной размерности (возвращает NULL в случае неудачи).
|
|
/// \en Create an array of a given dimension (returns NULL in case of failure).
|
|
static Array2<Type> * Create( size_t lSize, size_t cSize );
|
|
|
|
public: // Общие методы матриц (двумерных массивов)
|
|
size_t Lines () const { return l; } ///< \ru Количество строк. \en Count of rows.
|
|
size_t Columns() const { return c; } ///< \ru Количество столбцов. \en Count of columns.
|
|
size_t Count () const { return (l*c); } ///< \ru Количество элементов. \en Count of elements.
|
|
c3d::IndicesPair GetSize() const { return c3d::IndicesPair( l, c ); } ///< \ru Дать размер массива. \en Give the size of the array.
|
|
bool SetSize( c3d::IndicesPair sz ) { return SetSize( sz.first, sz.second ); } ///< \ru Установить размер. \en Set size.
|
|
bool SetSize( size_t lsz, size_t csz ); ///< \ru Установить размер. \en Set size.
|
|
bool SetSize( size_t n ) { return SetSize( n, n ); } ///< \ru Установить размер. \en Set size.
|
|
|
|
/// \ru Получить элемент массива. \en Get an element of the array.
|
|
const Type & GetElem( size_t ln, size_t cn ) const;
|
|
/// \ru Установить элемент массива. \en Set an element of the array.
|
|
void SetElem( size_t ln, size_t cn, const Type & v );
|
|
/// \ru Оператор доступа по индексам. \en Access by indices operator.
|
|
const Type & operator () ( size_t i, size_t j ) const;
|
|
/// \ru Расписать массив нулями. \en Assign zeros to array.
|
|
Array2<Type> & SetZero() { zero_array( *this ); return *this; }
|
|
/// \ru Функция присваивания. \en An assignment function.
|
|
bool Init( const Array2<Type> & src ) { return assign_to_array( *this, src ); }
|
|
/// \ru Оператор присваивания. \en The assignment operator.
|
|
Array2<Type> & operator = ( const Array2<Type> & src ) { Init( src ); return *this; }
|
|
/// \ru Поменять местами строки. \en Swap lines.
|
|
bool SwapLines( size_t ln1, size_t ln2 );
|
|
|
|
public:
|
|
/// \ru Оператор доступа по индексам. \en Access by indices operator.
|
|
Type & operator () ( size_t i, size_t j );
|
|
/// \ru Выдать адрес начала строки. \en Get an address of the row start.
|
|
const Type * GetLine( size_t i = 0 ) const;
|
|
/// \ru Выдать адрес начала строки. \en Get an address of the row start.
|
|
Type * SetLine( size_t i = 0 );
|
|
/// \ru Инициировать элемент. \en Initiate an element.
|
|
void Init( size_t ln, size_t cn, const Type & v );
|
|
|
|
/// \ru Функции, выделяющие потенциально большие участки памяти, возвращают результат операции (успех/ошибка).
|
|
/// \en Functions that allocate potentially large memory, return the operation result (success/error).
|
|
bool InsertColumn( size_t i = 0 ); ///< \ru Вставить столбец перед указанным. \en Insert column before the specified one.
|
|
bool AddColumn(); ///< \ru Добавить столбец в конец массива. \en Add column to the end of the array.
|
|
void RemoveColumn( size_t i = 0 ); ///< \ru Удалить столбец из массива. \en Delete column from array.
|
|
|
|
bool InsertLine ( size_t i = 0 ); ///< \ru Вставить строку перед указанной. \en Insert row before the specified one.
|
|
bool AddLine(); ///< \ru Добавить строку в конец массива. \en Add row to the end of the array.
|
|
void RemoveLine ( size_t i = 0 ); ///< \ru Удалить строку из массива. \en Delete row from array.
|
|
protected :
|
|
bool CatchLinePointers( size_t newCount ); ///< \ru Взять память под заданное кол-во указателей на строки. \en Allocate memory for the given count of pointers to rows.
|
|
|
|
/// \ru Оператор чтения. \en Read operator.
|
|
TEMPLATE_FRIEND reader & operator >> TEMPLATE_SUFFIX ( reader & in, Array2<Type> & ptr );
|
|
/// \ru Оператор записи. \en Write operator.
|
|
TEMPLATE_FRIEND writer & operator << TEMPLATE_SUFFIX ( writer & out, const Array2<Type> & ref );
|
|
/// \ru Оператор чтения. \en Read operator.
|
|
TEMPLATE_FRIEND reader & operator >> TEMPLATE_SUFFIX ( reader & in, Array2<Type> *& ptr );
|
|
/// \ru Оператор записи. \en Write operator.
|
|
TEMPLATE_FRIEND writer & operator << TEMPLATE_SUFFIX ( writer & out, const Array2<Type> * ptr );
|
|
|
|
/// \ru Перезахватить память под одну строку. \en Reallocate memory for one row.
|
|
TEMPLATE_FRIEND bool realloc_line TEMPLATE_SUFFIX ( Type *& line, size_t oldSize, size_t newSize );
|
|
/// \ru Скопировать массив. \en Copy an array.
|
|
TEMPLATE_FRIEND bool assign_to_array TEMPLATE_SUFFIX ( Array2<Type> &, const Array2<Type> & src );
|
|
/// \ru Установить размер массива. \en Set the size of the array.
|
|
TEMPLATE_FRIEND bool set_array_size TEMPLATE_SUFFIX ( Array2<Type> &, size_t lSize, size_t cSize );
|
|
/// \ru Вставить колонку перед указанной и заполнить ее нулями. \en Insert column before the specified one and fill it with zeros.
|
|
TEMPLATE_FRIEND bool insert_column_to_array TEMPLATE_SUFFIX ( Array2<Type> &, size_t ind );
|
|
/// \ru Добавить в массив колонку и заполнить ее нулями. \en Add column to array and fill it with zeros.
|
|
TEMPLATE_FRIEND bool add_column_to_array TEMPLATE_SUFFIX ( Array2<Type> & );
|
|
/// \ru Удалить колонку из массива. \en Delete column from array.
|
|
TEMPLATE_FRIEND void remove_column_from_array TEMPLATE_SUFFIX ( Array2<Type> &, size_t ind );
|
|
/// \ru Заполнить массив нулями. \en Fill the array with zeros.
|
|
TEMPLATE_FRIEND void zero_array TEMPLATE_SUFFIX ( Array2<Type> & );
|
|
|
|
#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 * Array2<Type>::operator new( size_t size ) {
|
|
return ::Allocate( size, typeid(Array2<Type>).name() );
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// \ru Перегрузка оператора delete. \en Overloading of the "delete" operator.
|
|
// ---
|
|
template <class Type>
|
|
inline void Array2<Type>::operator delete( void * ptr, size_t size ) {
|
|
::Free( ptr, size, typeid(Array2<Type>).name() );
|
|
}
|
|
#endif // __DEBUG_MEMORY_ALLOCATE_FREE_
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// \ru конструктор массива \en constructor of an array
|
|
// ---
|
|
template <class Type>
|
|
inline Array2<Type>::Array2( size_t lSize, size_t cSize )
|
|
: parr( 0 )
|
|
, l ( 0 )
|
|
, c ( 0 )
|
|
{
|
|
if ( !::set_array_size( *this, lSize, cSize ) && !ExceptionMode::IsEnabled() )
|
|
throw std::bad_alloc(); // \ru Бросить исключение при любом режиме. \en Throw exception in case of any mode.
|
|
|
|
PRECONDITION( !!parr || (lSize == 0 && cSize == 0) );
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// \ru конструктор массива \en constructor of an array
|
|
// ---
|
|
template <class Type>
|
|
inline Array2<Type>::Array2( const uint16 & lSize, const uint16 & cSize )
|
|
: parr( 0 )
|
|
, l ( 0 )
|
|
, c ( 0 )
|
|
{
|
|
if ( !::set_array_size( *this, lSize, cSize ) && !ExceptionMode::IsEnabled() )
|
|
throw std::bad_alloc(); // \ru Бросить исключение при любом режиме. \en Throw exception in case of any mode.
|
|
|
|
PRECONDITION( !!parr || (lSize == 0 && cSize == 0) );
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// \ru конструктор копирования \en copy-constructor
|
|
// ---
|
|
template <class Type>
|
|
inline Array2<Type>::Array2( const Array2<Type> & source )
|
|
: parr( 0 )
|
|
, l ( 0 )
|
|
, c ( 0 )
|
|
{
|
|
if ( !::assign_to_array( *this, source ) && !ExceptionMode::IsEnabled() )
|
|
throw std::bad_alloc(); // \ru Бросить исключение при любом режиме. \en Throw exception in case of any mode.
|
|
|
|
PRECONDITION( !!parr || (l == 0 && c == 0) );
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// \ru Создать массив заданной размерности. \en Create an array of a given dimension.
|
|
// ---
|
|
template <class Type>
|
|
inline Array2<Type> * Array2<Type>::Create( size_t lSize, size_t cSize )
|
|
{
|
|
Array2<Type> * arr = NULL;
|
|
if ( lSize * cSize < c3d::MATRIX_MAX_COUNT ) {
|
|
try {
|
|
arr = new Array2<Type>( lSize, cSize );
|
|
}
|
|
catch ( const std::bad_alloc & ) {
|
|
arr = NULL;
|
|
}
|
|
}
|
|
return arr;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// \ru Установить размер массива \en Set the size of the array
|
|
// ---
|
|
template <class Type>
|
|
inline bool Array2<Type>::SetSize( size_t lSize, size_t cSize ) {
|
|
return ::set_array_size( *this, lSize, cSize );
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// \ru Получить элемент массива. \en Get an element of the array.
|
|
// ---
|
|
template <class Type>
|
|
const Type & Array2<Type>::GetElem( size_t ln, size_t cn ) const {
|
|
PRECONDITION( !!parr && ln < l && cn < c );
|
|
return parr[ln][cn];
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// \ru Установить элемент массива. \en Set an element of the array.
|
|
// ---
|
|
template <class Type>
|
|
void Array2<Type>::SetElem( size_t ln, size_t cn, const Type & v ) {
|
|
PRECONDITION( !!parr && ln < l && cn < c );
|
|
if ( !!parr && ln < l && cn < c )
|
|
parr[ln][cn] = v;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// \ru Оператор доступа по индексам. \en Access by indices operator.
|
|
// ---
|
|
template <class Type>
|
|
const Type & Array2<Type>::operator() ( size_t i, size_t j ) const {
|
|
PRECONDITION( i < l && j < c );
|
|
return parr[i][j];
|
|
}
|
|
|
|
/// \ru Оператор доступа по индексам. \en Access by indices operator.
|
|
template <class Type>
|
|
Type & Array2<Type>::operator() ( size_t i, size_t j ) {
|
|
PRECONDITION( i < l && j < c );
|
|
return parr[i][j];
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// \ru Выдать адрес начала строки. \en Get an address of the row start.
|
|
// ---
|
|
template <class Type>
|
|
const Type * Array2<Type>::GetLine( size_t i ) const {
|
|
PRECONDITION( i < l );
|
|
if ( i < l )
|
|
return parr[i];
|
|
return NULL;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// \ru Выдать адрес начала строки. \en Get an address of the row start.
|
|
// ---
|
|
template <class Type>
|
|
Type * Array2<Type>::SetLine( size_t i ) {
|
|
PRECONDITION( i < l );
|
|
if ( i < l )
|
|
return parr[i];
|
|
return NULL;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// \ru Инициировать элемент. \en Initiate an element.
|
|
// ---
|
|
template <class Type>
|
|
void Array2<Type>::Init( size_t ln, size_t cn, const Type & v ) {
|
|
PRECONDITION( !!parr && ln < l && cn < c );
|
|
if ( !!parr && ln < l && cn < c )
|
|
parr[ln][cn] = v;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// \ru Поменять местами строки. \en Swap lines.
|
|
// ---
|
|
template <class Type>
|
|
inline bool Array2<Type>::SwapLines( size_t ln1, size_t ln2 )
|
|
{
|
|
if ( !!parr && ln1 < l && ln2 < l ) {
|
|
Type * tmp = parr[ln1];
|
|
parr[ln1] = parr[ln2];
|
|
parr[ln2] = tmp;
|
|
return true;
|
|
}
|
|
PRECONDITION( false );
|
|
return false;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// \ru вставить столбец перед указанным \en insert column before the specified one
|
|
// ---
|
|
template <class Type>
|
|
inline bool Array2<Type>::InsertColumn( size_t ind ) {
|
|
return insert_column_to_array( *this, ind );
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// \ru добавить столбец в конец массива \en add column to the end of the array
|
|
// ---
|
|
template <class Type>
|
|
inline bool Array2<Type>::AddColumn() {
|
|
return add_column_to_array( *this );
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// \ru удалить столбец \en delete column
|
|
// ---
|
|
template <class Type>
|
|
inline void Array2<Type>::RemoveColumn( size_t ind ) {
|
|
remove_column_from_array( *this, ind );
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// \ru вставить строку перед указанной и заполнить ее нулями \en insert row before the specified one and fill it with zeros
|
|
// \ru если ind больше количества строк, то просто добавить строку в конец массива \en if 'ind' is greater than count of rows then simply add row to the end of the array
|
|
// ---
|
|
template <class Type>
|
|
inline bool Array2<Type>::InsertLine( size_t ind )
|
|
{
|
|
bool res = true;
|
|
size_t oldL = l; // \ru прежнее кол-во строк \en previous count of rows
|
|
if ( AddLine() ) { // \ru кол-во строк увеличилось на 1 \en count of rows is increased by 1
|
|
|
|
if ( ind < oldL ) {
|
|
// \ru переставить новую строку с последнего места на указанное \en swap the new row from last position with row of the specified position
|
|
Type * newLine = parr[l - 1];
|
|
// \ru переместить хвост на один элемент дальше \en move the tale by one element
|
|
memmove( parr + ind + 1, parr + ind, (oldL - ind) * SIZE_OF_POINTER );
|
|
|
|
parr[ind] = newLine; // \ru теперь это будет строка с индексом ind \en now it is the row with 'ind' index
|
|
}
|
|
}
|
|
else
|
|
res = false;
|
|
return res;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// \ru добавить строку в конец массива и заполнить ее нулями \en add to the end of the array and fill it with zeros
|
|
// ---
|
|
template <class Type>
|
|
inline bool Array2<Type>::AddLine()
|
|
{
|
|
bool res = CatchLinePointers( l + 1 );
|
|
if ( res ) { // \ru добавить память для одного указателя на строку \en add memory for one pointer to row
|
|
// \ru (l увеличится на 1) \en (l will be increased by 1)
|
|
Type * newLine = 0; // \ru указатель на содержимое новой строки \en pointer to contents of new row
|
|
if ( c ) {
|
|
res = realloc_line( newLine, 0/*oldSize*/, c/*newSize*/ ); // \ru захватить память под строку \en allocate memory for one row
|
|
if ( res )
|
|
memset( newLine, 0, c * sizeof(Type) );
|
|
}
|
|
parr[l - 1] = newLine; // \ru записать указатель в массив \en store pointer to the array
|
|
}
|
|
return res;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// \ru удалить строку из массива \en delete row from the array
|
|
// ---
|
|
template <class Type>
|
|
inline void Array2<Type>::RemoveLine( size_t ind )
|
|
{
|
|
PRECONDITION( ind < l );
|
|
|
|
if ( ind < l ) {
|
|
realloc_line( parr[ind], c/*oldSize*/, 0/*newSize*/ ); // \ru освободить память, занятую строкой \en free memory occupied by row
|
|
|
|
// \ru передвинуть хвост ближе к началу на один элемент \en move tale closer to start by one element
|
|
size_t tail = l - (ind + 1);
|
|
if ( tail ) // \ru если это не последний указатель \en if it is not the last pointer,
|
|
memmove( parr + ind, parr + ind + 1, tail * SIZE_OF_POINTER );
|
|
|
|
CatchLinePointers( l - 1/*newCount*/ ); // \ru освободить память из-под последнего указателя на строку \en then free memory for last pointer to row
|
|
}
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// \ru Взять память под заданное кол-во указателей на строки \en Allocate memory for the given count of pointers to rows
|
|
// \ru Если кол-во строк уменьшается, то память из-под лишних строк уже должна быть освобождена ! \en If count of rows decreases, then memory from excess rows has to be already released !
|
|
// ---
|
|
template <class Type>
|
|
inline bool Array2<Type>::CatchLinePointers( size_t newCount )
|
|
{
|
|
if ( l != newCount )
|
|
{
|
|
// \ru половина адресного пространства для 64- и 32-разрядного приложения \en a half of address space for 64- and 32-bit application
|
|
if ( ::TestNewSize( SIZE_OF_POINTER, newCount ) )
|
|
{
|
|
try {
|
|
#ifdef __REALLOC_ARRAYS_STATISTIC_
|
|
void * oldParr = parr;
|
|
size_t oldSize = l;
|
|
#endif // __REALLOC_ARRAYS_STATISTIC_
|
|
|
|
#ifdef USE_REALLOC_IN_ARRAYS
|
|
parr = (Type**)REALLOC_ARRAY_SIZE( parr, newCount * SIZE_OF_POINTER, false/*clear*/ );
|
|
// \ru ИР parr = (Type**) ::realloc( parr, newCount * SIZE_OF_POINTER ); \en ИР parr = (Type**) ::realloc( parr, newCount * SIZE_OF_POINTER );
|
|
#else
|
|
Type ** p_tmp = newCount ? new Type*[newCount] : 0;
|
|
|
|
if ( parr ) {
|
|
if ( p_tmp )
|
|
memcpy( p_tmp, parr, std_min(l, newCount) * SIZE_OF_POINTER );
|
|
|
|
delete[] parr;
|
|
}
|
|
|
|
parr = p_tmp;
|
|
#endif // USE_REALLOC_IN_ARRAYS
|
|
|
|
l = newCount;
|
|
|
|
#ifdef __REALLOC_ARRAYS_STATISTIC_
|
|
REALLOC_ARRAY_STATISTICS( oldParr, oldSize * SIZE_OF_POINTER, parr, newCount * SIZE_OF_POINTER, 2/*Array2*/ );
|
|
#endif // __REALLOC_ARRAYS_STATISTIC_
|
|
}
|
|
catch ( const std::bad_alloc & ) {
|
|
C3D_CONTROLED_THROW;
|
|
return false;
|
|
}
|
|
catch ( ... ) {
|
|
if ( newCount == 0 ) {// \ru Не смогли удалить parr. \en Failed to delete parr.
|
|
parr = NULL;
|
|
l = c = 0;
|
|
}
|
|
C3D_CONTROLED_THROW;
|
|
return false;
|
|
}
|
|
}
|
|
else {
|
|
PRECONDITION( false ); // \ru не бывает столько памяти \en incorrect size of memory
|
|
C3D_CONTROLED_THROW_EX( std::bad_alloc() );
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// \ru Перезахватить память под одну строку. \en Reallocate memory for one row.
|
|
// ---
|
|
template <class Type>
|
|
inline bool realloc_line( Type *& line, size_t oldSize, size_t newSize )
|
|
{
|
|
if ( oldSize != newSize )
|
|
{
|
|
size_t sizeOfType = sizeof(Type);
|
|
|
|
// \ru половина адресного пространства для 64- и 32-разрядного приложения \en a half of address space for 64- and 32-bit application
|
|
if ( ::TestNewSize( sizeOfType, newSize ) )
|
|
{
|
|
try {
|
|
#ifdef __REALLOC_ARRAYS_STATISTIC_
|
|
void * oldParr = line;
|
|
#endif // __REALLOC_ARRAYS_STATISTIC_
|
|
|
|
#ifdef USE_REALLOC_IN_ARRAYS
|
|
line = (Type *) REALLOC_ARRAY_SIZE( line, newSize * sizeOfType, false/*clear*/ );
|
|
#else
|
|
Type * p_tmp = newSize ? new Type[newSize] : 0;
|
|
|
|
if ( line )
|
|
{
|
|
if ( p_tmp )
|
|
memcpy( p_tmp, line, std_min(oldSize, newSize) * sizeOfType );
|
|
|
|
delete [] line;
|
|
}
|
|
|
|
line = p_tmp;
|
|
#endif // USE_REALLOC_IN_ARRAYS
|
|
|
|
#ifdef __REALLOC_ARRAYS_STATISTIC_
|
|
REALLOC_ARRAY_STATISTICS( oldParr, oldSize * sizeOfType, line, newSize * sizeOfType, 2/*Array2*/ );
|
|
#endif // __REALLOC_ARRAYS_STATISTIC_
|
|
}
|
|
catch ( const std::bad_alloc & ) {
|
|
C3D_CONTROLED_THROW;
|
|
return false;
|
|
}
|
|
catch ( ... ) {
|
|
if ( newSize == 0 )// \ru Не смогли удалить line. \en Failed to delete line.
|
|
line = NULL;
|
|
C3D_CONTROLED_THROW;
|
|
return false;
|
|
}
|
|
}
|
|
else {
|
|
PRECONDITION( false ); // \ru не бывает столько памяти \en incorrect size of memory
|
|
C3D_CONTROLED_THROW_EX( std::bad_alloc() );
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// \ru Присвоить массиву новое содержимое, заменив его текущее содержимое.
|
|
// \en Assign new contents to the array, replacing its current contents.
|
|
// ---
|
|
template <class Type>
|
|
bool assign_to_array( Array2<Type> & arr, const Array2<Type> & source )
|
|
{
|
|
if ( set_array_size( arr, source.l, source.c ) ) {
|
|
if ( arr.l && arr.c ) {
|
|
Type ** aParr = arr.parr;
|
|
Type ** sParr = source.parr;
|
|
size_t n = arr.c * sizeof(Type);
|
|
for ( size_t i = 0; i < arr.l; i++, aParr++, sParr++ )
|
|
::memcpy( *aParr, *sParr, n );
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
// ---
|
|
template <class Type>
|
|
bool set_array_size( Array2<Type> & arr, size_t lSize, size_t cSize )
|
|
{
|
|
bool res = false;
|
|
|
|
if ( lSize*cSize <= c3d::MATRIX_MAX_COUNT ) {
|
|
size_t i, oldL = arr.l;
|
|
res = true;
|
|
|
|
if ( arr.l != lSize ) {
|
|
// \ru Если кол-во строк уменьшается - освободить память из-под лишних строк \en If count of rows decreases then release memory from excess rows
|
|
if ( arr.c && oldL && lSize < oldL ) {
|
|
size_t removeLines = oldL - lSize;
|
|
for ( i = 1; i <= removeLines; i++ )
|
|
realloc_line( arr.parr[oldL-i], arr.c/*oldSize*/, 0/*newSize*/ ); // \ru освободить память, занятую строкой \en free memory occupied by row
|
|
}
|
|
|
|
// \ru Взять память под заданное кол-во указателей на строки (изменится arr.l) \en Allocate memory for the given count of pointers to rows (arr.l tro be changed)
|
|
res = arr.CatchLinePointers( lSize );
|
|
for ( i = oldL; res && i < arr.l/*\ru уже изменено \en already changed */; i++ )
|
|
arr.parr[i] = 0; // \ru обнулить добавленные указатели \en set added pointers to null
|
|
}
|
|
|
|
if ( arr.c != cSize ) {
|
|
// \ru Перезахватить память под каждую строку \en Reallocate memory for each row
|
|
for ( i = 0; res && i < arr.l/*\ru уже изменено \en already changed */; i++ )
|
|
res = realloc_line( arr.parr[i], arr.c/*oldSize*/, cSize/*newSize*/ );
|
|
|
|
if ( res )
|
|
arr.c = cSize;
|
|
}
|
|
else if ( arr.l > oldL && arr.c > 0 ) { // \ru BUG_46010 KYA K12 А кто будет выделять память для новых строк \en BUG_46010 KYA K12 And who will allocate memory for new rows
|
|
Type * newLine = 0; // \ru указатель на содержимое новой строки \en pointer to contents of new row
|
|
for ( i = oldL; res && i < arr.l; i++ ) {
|
|
newLine = NULL;
|
|
res = ::realloc_line( newLine, 0, arr.c ); // \ru захватить память под строку \en allocate memory for one row
|
|
if ( res ) {
|
|
::memset( newLine, 0, arr.c * sizeof(Type) );
|
|
arr.parr[i] = newLine; // \ru записать указатель в массив \en store pointer to the array
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
PRECONDITION( res );
|
|
return res;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// \ru Вставить колонку перед указанной и заполнить ее нулями \en Insert column before specified one and fill it with zeros
|
|
// \ru если ind больше количества колонок, то просто добавить колонку в конец массива \en if 'ind' is greater than count of columns, then simply add the column to the end of the array
|
|
// ---
|
|
template <class Type>
|
|
bool insert_column_to_array( Array2<Type> & arr, size_t ind )
|
|
{
|
|
bool res = true;
|
|
if ( arr.l ) {
|
|
size_t oldC = arr.c; // \ru прежнее кол-во колонок \en previous count of columns
|
|
if ( add_column_to_array( arr ) ) { // \ru добавить колонку в конец строк (увеличилось arr.c) \en add column to the end of rows (arr.c increased)
|
|
if ( ind < oldC ) {
|
|
size_t tail = oldC - ind; // \ru кол-во колонок, которые нужно сдвинуть \en count of columns to be moved
|
|
for ( size_t i = 0; i < arr.l; i++ ) {
|
|
Type * line = arr.parr[i];
|
|
// \ru передвинуть хвосты всех строк ближе к концу на один элемент (при этом \en move tales of all rows by one element closer to end (thus
|
|
// \ru затрем добавленный обнуленный элемент) \en erase added nullified element)
|
|
memmove( line + ind + 1, line + ind, tail * sizeof(Type) );
|
|
// \ru обнулить элемент ind \en set 'ind' element to null
|
|
memset( line + ind, 0, sizeof(Type) );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
res = false;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// \ru Добавить в массив колонку (последнюю) и обнулить ее. \en Add (last) column to array and fill it with zeros.
|
|
// ---
|
|
template <class Type>
|
|
bool add_column_to_array( Array2<Type> & arr )
|
|
{
|
|
bool res = true;
|
|
if ( arr.l ) {
|
|
// \ru увеличить память под каждой строкой на 1 элемент \en increase memory under each row by 1 element
|
|
size_t newSize = arr.c + 1;
|
|
for ( size_t i = 0; res && i < arr.l; i++ ) {
|
|
res = realloc_line( arr.parr[i]/*\ru здесь может меняться!!! \en can be changed!!! */, arr.c/*oldSize*/, newSize );
|
|
// \ru обнулить добавленную ячейку (последний элемент в строке) \en set added cell (last element in row) to zero
|
|
if ( res )
|
|
memset( arr.parr[i] + arr.c/*\ru еще не увеличенное \en not yet increased */, 0, sizeof(Type) );
|
|
}
|
|
if ( res )
|
|
arr.c = newSize;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// \ru Убрать из массива колонку по индексу. \en Delete column from array by the index.
|
|
// ---
|
|
template <class Type>
|
|
void remove_column_from_array( Array2<Type> & arr, size_t ind )
|
|
{
|
|
PRECONDITION( ind < arr.c );
|
|
|
|
if ( ind < arr.c ) {
|
|
// \ru передвинуть хвосты всех строк ближе к началу на один элемент \en move tales of all rows closer to start by one element
|
|
size_t tail = arr.c - (ind + 1);
|
|
if ( tail ) { // \ru это не последняя колонка в строке \en this is not last column in row
|
|
for ( size_t i = 0; i < arr.l; i++ ) {
|
|
Type *line = arr.parr[i];
|
|
memmove( line + ind, line + ind + 1, tail * sizeof(Type) );
|
|
}
|
|
}
|
|
|
|
// \ru уменьшить память под каждой строкой на 1 элемент \en decrease memory under each row by 1 element
|
|
size_t newSize = arr.c - 1;
|
|
for ( size_t i = 0; i < arr.l; i++ )
|
|
realloc_line( arr.parr[i], arr.c/*oldSize*/, newSize );
|
|
|
|
arr.c = newSize;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// \ru Заполнить массив нулями. \en Fill the array with zeros.
|
|
// ---
|
|
template <class Type>
|
|
void zero_array( Array2<Type> & arr )
|
|
{
|
|
size_t n = arr.c * sizeof(Type);
|
|
if ( n ) {
|
|
Type ** parr = arr.parr;
|
|
for ( size_t i = 0; i < arr.l; i++, parr++ )
|
|
memset( *parr, 0, n );
|
|
}
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
/** \brief \ru Транспонирование матрицы.
|
|
\en Transpose a matrix. \~
|
|
\details \ru Транспонирование матрицы. \n
|
|
\en Transpose a matrix. \n \~
|
|
\ingroup Base_Tools_Containers
|
|
*/
|
|
// ---
|
|
template <class Type>
|
|
void Transpose( const Array2<Type> & srcMtr, Array2<Type> & dstMtr )
|
|
{
|
|
const size_t l = srcMtr.Lines();
|
|
const size_t c = srcMtr.Columns();
|
|
dstMtr.SetSize( c, l );
|
|
for ( size_t nc = 0; nc < c; nc++ ) {
|
|
for ( size_t nl = 0; nl < l; nl++ )
|
|
dstMtr( nc, nl ) = srcMtr( nl, nc );
|
|
}
|
|
}
|
|
|
|
|
|
#endif // __TEMPL_ARRAY2_H
|