Files
Extern/C3d/Include/templ_sfp_array.h
SaraP 86f4bb48be Extern :
- C3d aggiornamento delle librerie ( 117960).
2023-10-12 08:53:50 +02:00

536 lines
22 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
////////////////////////////////////////////////////////////////////////////////
/**
\file
\brief \ru Упорядоченный массив указателей.
\en Ordered array of pointers. \~
*/
////////////////////////////////////////////////////////////////////////////////
#ifndef __TEMPL_SFP_ARRAY_H
#define __TEMPL_SFP_ARRAY_H
#include <templ_p_array.h>
#include <templ_s_array.h>
////////////////////////////////////////////////////////////////////////////////
//
// \ru упорядоченный массив указателей \en ordered array of pointers
// \ru одинаковые объекты не добавляются \en the similar objects are not added
//
////////////////////////////////////////////////////////////////////////////////
FORVARD_DECL_TEMPLATE_TYPENAME( class SFPArray );
FORVARD_DECL_TEMPLATE_TYPENAME( Type * add_to_array ( SFPArray<Type> &, Type * ent, size_t & indexEnt ) );
FORVARD_DECL_TEMPLATE_TYPENAME( size_t find_from_array ( const SFPArray<Type> &, const Type * ent ) );
FORVARD_DECL_TEMPLATE_TYPENAME( Type * find_from_array_by_key( const SFPArray<Type> &, void * key, size_t & index ) );
FORVARD_DECL_TEMPLATE_TYPENAME( void qp_sort ( SFPArray<Type> &, bool always ) );
FORVARD_DECL_TEMPLATE_TYPENAME( reader & CALL_DECLARATION operator >> ( reader & in, SFPArray<Type> & ref ) );
FORVARD_DECL_TEMPLATE_TYPENAME( writer & CALL_DECLARATION operator << ( writer & out, const SFPArray<Type> & ref ) );
template <class Type>
class SFPArray : private PArray<Type> {
public:
typedef int (*CompareFunc)( const Type * left, const Type * right ); // \ru функция сравнения для поиска и наполнения \en a comparison function for search and filling
typedef int (*SearchFunc) ( const Type * d1, void * key ); // \ru функция сравнения для поиска \en a comparison function for search
typedef void (*AssignFunc) ( Type *& oldObj, const Type * newObj ); // \ru функция присвоения \en an assignment function
CompareFunc fCompare_m; // \ru функция сравнения \en a comparison function
SearchFunc fSearch_m; // \ru функция поиска \en a search function
protected:
// \ru признак сортированности массива \en attribute of an array being sorted
bool m_sort;
// \ru при сортировке выкидывать одинаковые \en throw out the same elements while sorting
bool m_keepEq;
public :
SFPArray( size_t maxCnt
, uint16 delt
, CompareFunc fc
, SearchFunc fs
, bool shouldDelete
, bool keepEq
)
: PArray<Type>( maxCnt, delt, shouldDelete )
, fCompare_m ( fc ) // \ru функция сравнения \en a comparison function
, fSearch_m ( fs ) // \ru функция поиска \en a search function
, m_sort ( true )
, m_keepEq ( keepEq )
{}
using PArray<Type>::OwnsElem;
using PArray<Type>::Delta;
using PArray<Type>::Flush;
using PArray<Type>::HardFlush;
using PArray<Type>::Adjust;
using PArray<Type>::RemoveInd;
using PArray<Type>::Count;
using PArray<Type>::MaxIndex;
using PArray<Type>::operator[];
using PArray<Type>::Reserve;
using PArray<Type>::SetSize;
using PArray<Type>::GetLast;
using PArray<Type>::empty;
using PArray<Type>::size;
using PArray<Type>::reserve;
using PArray<Type>::capacity;
using PArray<Type>::begin;
using PArray<Type>::end;
using PArray<Type>::front;
using PArray<Type>::back;
using PArray<Type>::clear;
Type * Add( Type * ); // \ru добавить элемент с упорядочиванием по массиву \en add element with sorting
Type * Add( Type *, size_t & indexEnt );// \ru добавить элемент с упорядочиванием по массиву, возвращает индекс \en add element with sorting, returns index of the element.
void AddSimple( Type * ent ) { m_sort = false; PArray<Type>::Add( ent ); } // \ru Доступ к функции базового класса - добавить элемент в конец массива \en An access to the function of the base class - add an element to the end of the array
// \ru найти элемент в упорядоченном массиве \en find an element in ordered array
size_t Find( const Type * );
// \ru найти элемент по ключевым полям \en find an element by the key fields
Type * FindByKey( void * key, size_t & index );
// \ru удалить элемент из массива \en delete an element from array
Type * RemoveObj( Type * delObject, DelType=defDelete );
// \ru true если элемент найден \en true if the element was found
bool IsExist( const Type * );
// \ru сортировать массив, если не сортирован \en sort array if it is not sorted
void Sort();
// \ru проверить на соответствие сортировке элемент массива \en check that an element of the array corresponds to the sorting
// \ru если меняли значение полей Type - условие сортировки может быть не выполнено \en if the values of fields Type have been changed then the comparison condition may be not performed
// \ru если это так - флаг сортировки у массива снимается \en if it is so then the flag of sorting is switched off
void SortCheckByIndex( size_t index );
TEMPLATE_FRIEND Type * add_to_array TEMPLATE_SUFFIX ( SFPArray<Type> &, Type * ent, size_t & indexEnt );
TEMPLATE_FRIEND size_t find_from_array TEMPLATE_SUFFIX ( const SFPArray<Type> &, const Type * ent );
TEMPLATE_FRIEND Type * find_from_array_by_key TEMPLATE_SUFFIX ( const SFPArray<Type> &, void * key, size_t & index );
TEMPLATE_FRIEND void qp_sort TEMPLATE_SUFFIX ( SFPArray<Type> &, bool always );
private:
OBVIOUS_PRIVATE_COPY( SFPArray );
// \ru Т.к. наследование private, то сделаем здесь операторы чтения-записи \en Since there is a private inheritance, then make here operators of reading/writing
//ID K8 KNOWN_OBJECTS_RW_REF_OPERATORS( SFPArray<Type> )
// \ru OV_x64 но коду не нашел реализации операторов чтения/записи \en OV_x64 implementation of reading/writing operators was not found
TEMPLATE_FRIEND reader & CALL_DECLARATION operator >> TEMPLATE_SUFFIX ( reader & in, SFPArray<Type> & ref );
TEMPLATE_FRIEND writer & CALL_DECLARATION operator << TEMPLATE_SUFFIX ( writer & out, const SFPArray<Type> & ref );
#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 * SFPArray<Type>::operator new( size_t size ) {
return ::Allocate( size, typeid(SFPArray<Type>).name() );
}
//------------------------------------------------------------------------------
// \ru Перегрузка оператора delete. \en Overloading of the "delete" operator.
// ---
template <class Type>
inline void SFPArray<Type>::operator delete( void * ptr, size_t size ) {
::Free( ptr, size, typeid(SFPArray<Type>).name() );
}
#endif // __DEBUG_MEMORY_ALLOCATE_FREE_
//-------------------------------------------------------------------------------
// \ru добавить элемент с упорядочиванием по массиву \en add element with sorting
// ---
template <class Type>
inline Type* SFPArray<Type>::Add( Type* el ) {
size_t index;
qp_sort( *this, false );
return add_to_array( *this, el, index );
}
//-------------------------------------------------------------------------------
// \ru добавить элемент с упорядочиванием по массиву, возвращает индекс \en add element with sorting, returns index of the element
// ---
template <class Type>
inline Type* SFPArray<Type>::Add( Type* el, size_t & indexEl ) {
qp_sort( *this, false );
return add_to_array( *this, el, indexEl );
}
//-------------------------------------------------------------------------------
// \ru поиск объекта в массиве \en search of an element in array
// ---
template <class Type>
inline size_t SFPArray<Type>::Find( const Type * el ) {
qp_sort( *this, false );
return find_from_array( *this, el );
}
//-------------------------------------------------------------------------------
// \ru найти элемент по ключевым полям \en find an element by the key fields
// ---
template <class Type>
inline Type * SFPArray<Type>::FindByKey( void * key, size_t & index ) {
qp_sort( *this, false );
return find_from_array_by_key( *this, key, index );
}
//------------------------------------------------------------------------------
// \ru удалить элемент из массива \en delete an element from array
// ---
template <class Type>
inline Type * SFPArray<Type>::RemoveObj( Type *delObject, DelType del ) {
PRECONDITION( PArray<Type>::nowDeletedElem == nullptr ); // \ru Bременно, для отладки \en Temporarily, for debugging
qp_sort( *this, false );
size_t i = find_in_array( *this, delObject );
return ( i != SYS_MAX_T ) ? RemoveInd(i, del) : nullptr;
}
//------------------------------------------------------------------------------
// \ru true если элемент найден \en true if the element was found
// ---
template <class Type>
inline bool SFPArray<Type>::IsExist( const Type * el ) {
qp_sort( *this, false );
return find_in_array( *this, el ) != SYS_MAX_T;
}
//-------------------------------------------------------------------------------
// \ru сортировать массив, если не сортирован \en sort array if it is not sorted
// ---
template <class Type>
inline void SFPArray<Type>::Sort() {
qp_sort( *this, true );
}
//------------------------------------------------------------------------------
// \ru проверить на соответствие сортировке элемент массива \en check that an element of the array corresponds to the sorting
// \ru если меняли значение полей Type - условие сортировки может быть не выполнено \en if the values of fields Type have been changed then the comparison condition may be not performed
// \ru если это так - флаг сортировки у массива снимается \en if it is so then the flag of sorting is switched off
// ---
template <class Type>
inline void SFPArray<Type>::SortCheckByIndex( size_t /*OV_x64 int*/ index ) {
if ( Count() )
{
size_t /*OV_x64 int*/ maxIndex = Count() - 1; // \ru проверено count > 0 \en chacked that count > 0
//if ( 0 <= index && index <= maxIndex ) OV - Expression '0 <= index' is always true. Unsigned type value is always >= 0.
if ( index <= maxIndex )
{
Type * el = (*this)[index];
// \ru проверяем середину интервала \en check the middle of the interval
if ( 0 < index && index < maxIndex ) {
if ( (*fCompare_m)( (*this)[index-1], el ) >= 0
||
(*fCompare_m)( el, (*this)[index+1] ) >= 0
)
m_sort = false;
}
else
// \ru левая граница \en the left boundary
if ( index == 0 ) {
if ( (*fCompare_m)( el, (*this)[1] ) >= 0 )
m_sort = false;
}
else //index == maxIndex
// \ru правая граница \en the right boundary
if ( (*fCompare_m)( (*this)[index-1], el ) >= 0 )
m_sort = false;
}
}
}
//-------------------------------------------------------------------------------
// \ru добавление объекта в массив с упорядочиванием \en adding an object to the array with ordering
// ---
template <class Type>
Type * add_to_array( SFPArray<Type> & arr, Type * el, size_t & indexEl ) {
size_t mr = arr.count - 1;
size_t mxc = mr; // \ru правое \en right
size_t ml = 0; // \ru левое \en left
int resCmp = 0;
size_t mc = 0;
// \ru специальные случаи \en special cases
// \ru массив пустой - просто добавляем \en the array is empty - simply add
// \ru проверку на пустоту массива нельзя переносить за проверку границ - \en a check for array emptyness should not be moved outside a boundary check -
// \ru можно вылететь (из-за mxc = -1) \en the error may occur (because of mxc = -1)
if ( !arr.count ) {
arr.PArray<Type>::Add( el );
indexEl = 0;
return arr[0]; //arr.parr;
}
// \ru SA K6 элемент за границами массива - добавляем \en SA K6 an element is out of bounds - add it
resCmp = (*arr.fCompare_m)( el, arr[0] );
if ( resCmp < 0 ) {
arr.Insert( 0, el );
indexEl = 0;
return arr[0]; //arr.parr;
}
else
if ( 0 == resCmp ) {
indexEl = 0;
return 0;
}
// \ru есть всего один \en only one exists
if ( arr.count == 1 ) {
arr.PArray<Type>::Add( el );
indexEl = 0;
return arr[1];
}
// \ru проверка правой границы \en a check of the right bound
resCmp = (*arr.fCompare_m)( arr[mxc], el );
if ( resCmp < 0 ) {
arr.PArray<Type>::Add( el );
indexEl = mxc + 1;
return arr[indexEl]; //arr.parr + indexEl;
}
else
if ( 0 == resCmp ) {
indexEl = mxc;
return 0;
}
// \ru общий случай - элементов больше двух \en the common case - the number of elements is more than two
if ( arr.count > 2 ) {
// \ru результаты сравнения элементов с левой и правой границей \en the results of comparison between the elements and bounds
// \ru сделаны для минимизации вызовов функций сравнений - они могут \en it is done in order to minimize the number of comparison functions calls - they may
// \ru быть дорогими по времени выполнения \en be too time-consuming
// \ru пока не нашли - ищем \en seek until do not find
while ( ml + 1 < mr ) {
// \ru ищем СРЕДНИЙ индекс \en seek for the MIDDLE index
mc = ( ml + mr ) / 2;
// \ru сравниваем СРЕДНЕЕ с присланным \en compare the MIDDLE element and the sent element
resCmp = (*arr.fCompare_m)( arr[mc], el );
if ( resCmp > 0 ) { // \ru mc БОЛЬШЕ пришедшего, но mn МЕНЬШЕ пришедшего - поиск слева \en 'mc' is GREATER than the sent one and 'mn' is LESS than the sent one - search on the left
mr = mc;
}
else if ( resCmp < 0 ) { // \ru mc МЕНЬШЕ пришедшего - поиск справа \en 'mc' is LESS than the sent one - search on the right
ml = mc;
}
else {
// \ru такой элемент уже есть - добавления не происходит \en such element already exists - nothing to add
indexEl = mc;
return 0;
}
} // end while
arr.Insert( mr, el );
indexEl = mr;
return arr[mr];//arr.parr + mr;
}
// \ru SA K6 элемент не за границами массива и массив содержит 2 элемента \en SA K6 an element is not outside the array's bounds and the array consists of 2 elements
if ( arr.count == 2 ) {
arr.Insert( 1, el );
indexEl = 1;
return arr[1]; // arr.parr + 1;
}
indexEl = 0;
return 0;
}
//-------------------------------------------------------------------------------
// \ru поиск объекта в массиве \en search of an element in array
// \ru поиск ведется методом половинных делений \en a search is performed by the bisection method
// ---
template <class Type>
size_t find_from_array( const SFPArray<Type> & arr, const Type * el )
{
C3D_ASSERT( arr.fCompare_m ); // \ru без функции сравнения массив бессмысленнен \en the array is useless without comparison function
// \ru общий случай - элементов больше двух \en the common case - the number of elements is more than two
int res = 0;
if ( arr.count > 11 )
{
size_t mr = arr.count - 1; // \ru проверено count >= 1 \en count >= 1 validated
size_t mxc = mr;
size_t ml = 0;
while ( ml + 1 < mr ) { // \ru пока не нашли - ищем \en seek until do not find
size_t mc = ( ml + mr ) / 2;
res = (*arr.fCompare_m)( arr[mc], el );
switch ( res ) {
case 1 : mr = mc; break;
case -1 : ml = mc; break;
case 0 : return mc;
}
}
// \ru проверка по границам \en check by bounds
res = (*arr.fCompare_m)( arr[0], el );
switch ( res ) {
case 0 : return 0;
case 1 : return SYS_MAX_T;
case -1 : break;
}
res = (*arr.fCompare_m)( arr[mxc], el );
switch ( res ) {
case 0 : return mxc;
default : return SYS_MAX_T;
}
}
else {
// \ru специальные случаи count == >0 & < 11 \en special cases count == >0 & < 11
for( size_t i = 0, count = (size_t)arr.count; i < count; i++ ) {
switch ( (*arr.fCompare_m)( arr[i], el ) ) {
case 0 : return i;
case 1 : return SYS_MAX_T;
case -1 : break;
}
}
}
return SYS_MAX_T;
}
//-------------------------------------------------------------------------------
//
// ---
template <class Type>
Type * find_from_array_by_key( const SFPArray<Type> & arr, void * key, size_t & index )
{
PRECONDITION( arr.fSearch_m && key ); // \ru без функции сравнения массив бессмысленнен \en the array is useless without comparison function
// \ru общий случай - элементов больше двух \en the common case - the number of elements is more than two
int res = 0;
if ( arr.count > 11 ) {
size_t mr = arr.count - 1; // \ru проверено count >= 1 \en count >= 1 validated
size_t mxc = mr;
size_t ml = 0;
while ( ml + 1 < mr ) { // \ru пока не нашли - ищем \en seek until do not find
size_t mc = ( ml + mr ) / 2;
res = (*arr.fSearch_m)( arr[mc], key );
switch ( res ) {
case 1 : mr = mc; break;
case -1 : ml = mc; break;
case 0 : index = mc; return arr[mc];
}
}
// \ru проверка по границам \en check by bounds
res = (*arr.fSearch_m)( arr[0], key );
switch ( res ) {
case 0 : index = 0; return arr[0];
case 1 : index = SYS_MAX_T; return nullptr;
case -1 : break;
}
res = (*arr.fSearch_m)( arr[mxc], key );
switch ( res ) {
case 0 : index = mxc; return arr[mxc];
default : index = SYS_MAX_T; return nullptr;
}
}
else {
// \ru специальные случаи count == >0 & < 11 \en special cases count == >0 & < 11
for( size_t i = 0, count = (size_t)arr.count; i < count; i++ ) {
switch ( (*arr.fSearch_m)( arr[i], key ) ) {
case 0 : index = i; return arr[i];
case 1 : index = SYS_MAX_T; return nullptr;
case -1 : break;
}
}
}
index = SYS_MAX_T;
return nullptr;
}
//-----------------------------------------------------------------------------
// \ru Н.Вирт "Алгоритмы и структуры данных" 2е издание, Санкт-Петербург, 2001г., стр.111 \en see N.Wirth "Algorithms and Data Structures"
// ---
template <class Type>
void qp_sort_r( SFPArray<Type> & arr, ptrdiff_t minInd, ptrdiff_t maxInd )
{
//OV_x64 =====================
if ( arr.Count() > 1 )
{
if ( minInd == -1 ) minInd = 0;
if ( maxInd == -1 || maxInd > arr.MaxIndex() ) maxInd = arr.MaxIndex(); // \ru проверено count > 0 \en chacked that count > 0
//OV_x64 =====================
ptrdiff_t i = minInd, j = maxInd;
ptrdiff_t im = (i + j)/2;
Type * middle = arr[im];
do {
while( (*arr.fCompare_m)( arr[i], middle ) < 0 ) i++;
while( (*arr.fCompare_m)( middle, arr[j] ) < 0 ) j--;
if ( i <= j ) {
if ( i != j ) {
Type * wi = arr[i];
arr[i] = arr[j];
arr[j] = wi;
}
i++;
j--;
}
} while( !(i > j) );
if ( minInd < j )
qp_sort_r( arr, minInd, j );
if ( i < maxInd )
qp_sort_r( arr, i, maxInd );
}
}
//-------------------------------------------------------------------------------
//
// ---
template <class Type>
void qp_sort( SFPArray<Type> & arr, bool always )
{
if ( !arr.m_sort || always ) {
//OV_x64 =====================
if ( arr.Count() > 1 )
{
//OV_x64 =====================
size_t maxIndex = arr.MaxIndex(); // \ru проверено count > 1 \en chacked that count > 1
qp_sort_r( arr, 0, maxIndex );
// \ru удаление одинаковых \en deletion of similar objects
if ( !arr.m_keepEq )
for ( size_t /*OV_x64 int*/ i = maxIndex; i >= 1; i-- ) { // maxIndex > 0
int resCmp = (*arr.fCompare_m)( arr[i], arr[i-1] );
switch ( resCmp ) {
case 1 : break;
case 0 : arr.RemoveInd( i ); break;
case -1 : PRECONDITION( false ); break;
}
}
}
arr.m_sort = true;
}
}
#endif // __TEMPL_SFP_ARRAY_H