При описании массивов используются: тип nat ( натуральное число ), макрос ARRAY_TEST ( для проверки правильности при обращении к массивам ) и макрос CCArrRef ( для сокращения записи ): typedef unsigned int nat; #ifdef ARRAY_TEST void outOfRange ( const char * name, nat size, nat index ); #endif #define CCArrRef const CArrRefШаблон классов CArrRef представляет собой ссылку на константный массив: template <class T> class CArrRef
{
void operator= ( CCArrRef & );
protected:
union { const T * con; T * var; } _data;
nat _size;
public:
CArrRef () : _size(0) { _data.con = 0; }
CArrRef ( const T * d, nat n ) : _size(n) { _data.con = d; }
CArrRef ( CCArrRef<T> & a ) : _data(a._data), _size(a._size) {}
// Указатель на i-ый элемент:
const T * operator() ( nat i = 0 ) const { return _size > i ? _data.con + i : 0; }
#ifdef ARRAY_TEST
void error ( nat n, nat i ) const { outOfRange ( "CArrRef", n, i ); }
CArrRef ( CCArrRef<T> & a, nat i, nat n ) : _size(n) { _data.con = a(i); if ( a._size < i + n ) error ( a._size, i + n ); }
// Ссылка на i-ый элемент:
const T & operator[] ( nat i ) const { if ( _size <= i ) error ( _size, i ); return _data.con[i]; }
// Ссылка на i-ый элемент от конца:
const T & las ( nat i = 0 ) const { if ( _size <= i ) error ( _size, i ); return _data.con[_size-1-i]; }
// Ссылка на предыдущий элемент в цикле:
const T & cprev ( nat i ) const { if ( _size <= i ) error ( _size, i ); return _data.con[i>0 ? i-1:_size-1]; }
const T & cprev ( nat i, nat k ) const { if ( _size <= i ) error ( _size, i ); return _data.con[(i+_size-k)%_size]; }
// Ссылка на следущий элемент в цикле:
const T & cnext ( nat i ) const { if ( _size <= i ) error ( _size, i ); return _data.con[i+1<_size?i+1:0]; }
const T & cnext ( nat i, nat k ) const { if ( _size <= i ) error ( _size, i ); return _data.con[(i+k)%_size]; }
#else
CArrRef ( CCArrRef<T> & a, nat i, nat n ) : _size(n) { _data.con = a(i); }
// Ссылка на i-ый элемент:
const T & operator[] ( nat i ) const { return _data.con[i]; }
// Ссылка на i-ый элемент от конца:
const T & las ( nat i = 0 ) const { return _data.con[_size-1-i]; }
// Ссылка на предыдущий элемент в цикле:
const T & cprev ( nat i ) const { return _data.con[i>0 ? i-1:_size-1]; }
const T & cprev ( nat i, nat k ) const { return _data.con[(i+_size-k)%_size]; }
// Ссылка на следущий элемент в цикле:
const T & cnext ( nat i ) const { return _data.con[i+1<_size?i+1:0]; }
const T & cnext ( nat i, nat k ) const { return _data.con[(i+k)%_size]; }
#endif
// Количество элементов
nat size () const { return _size; }
};
Шаблон классов MutCArrRef представляет собой изменяемую ссылку на константный массив:
template <class T> class MutCArrRef : public CArrRef<T>
{
void operator= ( const MutCArrRef & );
public:
void reset ( const T * d, nat n )
{
_data.con = d;
_size = n;
}
void reset ( CCArrRef<T> & a )
{
_data.con = a();
_size = a.size();
}
};
Шаблон классов ArrRef представляет собой ссылку на неконстантный массив:
template <class T> class ArrRef : public CArrRef<T>
{
public:
ArrRef () {}
ArrRef ( T * d, nat n ) : CArrRef<T>( d, n ) {}
CCArrRef<T> & operator * () const { return *this; }
// Указатель на i-ый элемент:
T * operator() ( nat i = 0 ) { return _size > i ? _data.var + i : 0; }
const T * operator() ( nat i = 0 ) const { return _size > i ? _data.var + i : 0; }
#ifdef ARRAY_TEST
void error ( nat n, nat i ) const { outOfRange ( "ArrRef", n, i ); }
ArrRef ( ArrRef<T> a, nat i, nat n ) : CArrRef<T>( a(i), n ) { if ( a._size < i + n ) error ( a._size, i + n ); }
// Ссылка на i-ый элемент:
T & operator[] ( nat i ) { if ( _size <= i ) error ( _size, i ); return _data.var[i]; }
// Ссылка на i-ый элемент от конца:
T & las ( nat i = 0 ) { if ( _size <= i ) error ( _size, i ); return _data.var[_size-1-i]; }
// Ссылка на предыдущий элемент в цикле:
T & cprev ( nat i ) { if ( _size <= i ) error ( _size, i ); return _data.var[i>0 ? i-1:_size-1]; }
T & cprev ( nat i, nat k ) { if ( _size <= i ) error ( _size, i ); return _data.var[(i+_size-k)%_size]; }
// Ссылка на следущий элемент в цикле:
T & cnext ( nat i ) { if ( _size <= i ) error ( _size, i ); return _data.var[i+1<_size?i+1:0]; }
T & cnext ( nat i, nat k ) { if ( _size <= i ) error ( _size, i ); return _data.var[(i+k)%_size]; }
// Ссылка на i-ый элемент:
const T & operator[] ( nat i ) const { if ( _size <= i ) error ( _size, i ); return _data.var[i]; }
// Ссылка на i-ый элемент от конца:
const T & las ( nat i = 0 ) const { if ( _size <= i ) error ( _size, i ); return _data.var[_size-1-i]; }
// Ссылка на предыдущий элемент в цикле:
const T & cprev ( nat i ) const { if ( _size <= i ) error ( _size, i ); return _data.var[i>0 ? i-1:_size-1]; }
const T & cprev ( nat i, nat k ) const { if ( _size <= i ) error ( _size, i ); return _data.var[(i+_size-k)%_size]; }
// Ссылка на следущий элемент в цикле:
const T & cnext ( nat i ) const { if ( _size <= i ) error ( _size, i ); return _data.var[i+1<_size?i+1:0]; }
const T & cnext ( nat i, nat k ) const { if ( _size <= i ) error ( _size, i ); return _data.var[(i+k)%_size]; }
#else
ArrRef ( ArrRef<T> a, nat i, nat n ) : CArrRef<T>( a(i), n ) {}
// Ссылка на i-ый элемент:
T & operator[] ( nat i ) { return _data.var[i]; }
// Ссылка на i-ый элемент от конца:
T & las ( nat i = 0 ) { return _data.var[_size-1-i]; }
// Ссылка на предыдущий элемент в цикле:
T & cprev ( nat i ) { return _data.var[i>0 ? i-1:_size-1]; }
T & cprev ( nat i, nat k ) { return _data.var[(i+_size-k)%_size]; }
// Ссылка на следущий элемент в цикле:
T & cnext ( nat i ) { return _data.var[i+1<_size?i+1:0]; }
T & cnext ( nat i, nat k ) { return _data.var[(i+k)%_size]; }
// Ссылка на i-ый элемент:
const T & operator[] ( nat i ) const { return _data.var[i]; }
// Ссылка на i-ый элемент от конца:
const T & las ( nat i = 0 ) const { return _data.var[_size-1-i]; }
// Ссылка на предыдущий элемент в цикле:
const T & cprev ( nat i ) const { return _data.var[i>0 ? i-1:_size-1]; }
const T & cprev ( nat i, nat k ) const { return _data.var[(i+_size-k)%_size]; }
// Ссылка на следущий элемент в цикле:
const T & cnext ( nat i ) const { return _data.var[i+1<_size?i+1:0]; }
const T & cnext ( nat i, nat k ) const { return _data.var[(i+k)%_size]; }
#endif
// Операторы присваивания
ArrRef & operator= ( CCArrRef<T> & p )
{
const nat n = _min ( _size, p.size() );
for ( nat i = 0; i < n; ++i ) _data.var[i] = p[i];
return *this;
}
ArrRef & operator= ( const ArrRef & a )
{
return *this = *a;
}
// Изменение порядка следования элементов на обратный
ArrRef & reverse ()
{
if ( _size < 2 ) return *this;
const nat n = _size - 1;
const nat m = _size / 2;
for ( nat i = 0; i < m; ++i ) _swap ( _data.var[i], _data.var[n-i] );
return *this;
}
// Заполнение всех элементов заданным значением
ArrRef & fill ( const T & t )
{
for ( nat i = 0; i < _size; ++i ) _data.var[i] = t;
return *this;
}
// Выполнение оператора <= для всех элементов массива
template <class S> ArrRef & operator << ( S & s )
{
for ( nat i = 0; i < _size; ++i ) _data.var[i] <= s;
return *this;
}
};
Шаблон классов FixArrRef представляет собой ссылку на массив постоянной длины:
template <class T, nat n> class FixArrRef : public ArrRef<T>
{
protected:
FixArrRef ( T * d ) : ArrRef<T>( d, n ) {}
public:
explicit FixArrRef ( ArrRef<T> a, nat i = 0 ) : ArrRef<T> ( a, i, n ) {}
FixArrRef & operator= ( const FixArrRef & a )
{
for ( nat i = 0; i < n; ++i ) _data.var[i] = a[i];
return *this;
}
FixArrRef & operator+= ( const FixArrRef & a )
{
for ( nat i = 0; i < n; ++i ) _data.var[i] += a[i];
return *this;
}
FixArrRef & operator-= ( const FixArrRef & a )
{
for ( nat i = 0; i < n; ++i ) _data.var[i] -= a[i];
return *this;
}
friend inline void _swap ( FixArrRef & a1, FixArrRef & a2 )
{
for ( nat i = 0; i < n; ++i ) _swap ( a1[i], a2[i] );
}
};
Шаблон классов FixArray представляет собой массив постоянной длины:
template <class T, nat n> class FixArray : public FixArrRef<T>
{
T stor[n];
FixArray ( const FixArray & );
public:
FixArray () : FixArrRef<<T, n> ( stor ) {}
FixArray & operator= ( const FixArray & a )
{
for ( nat i = 0; i < n; ++i ) stor[i] = a.stor[i];
return *this;
}
FixArray & operator+= ( const FixArray & a )
{
for ( nat i = 0; i < n; ++i ) stor[i] += a[i];
return *this;
}
FixArray & operator-= ( const FixArray & a )
{
for ( nat i = 0; i < n; ++i ) stor[i] -= a[i];
return *this;
}
FixArray & operator*= ( const T & t )
{
for ( nat i = 0; i < n; ++i ) stor[i] *= t;
return *this;
}
// Заполнение всех элементов заданным значением
FixArray & fill ( const T & t )
{
ArrRef<T>::fill ( t );
return *this;
}
};
Шаблон классов DynArrRef предназначен для создания ссылок на массивы с изменяемым размером.
Размер массива меняется при помощи виртуальной функции resize:
template <class T> class DynArrRef : public ArrRef<T>
{
protected:
DynArrRef ( T * d, nat n ) : ArrRef<T>( d, n ) {}
public:
virtual DynArrRef & resize ( nat n = 0 ) = 0;
DynArrRef & resize ( nat n, const T & a )
{
resize ( n );
for ( nat i = 0; i < _size; ++i ) _data.var[i] = a;
return *this;
}
DynArrRef & operator= ( CCArrRef<T> & r )
{
if ( _data.var == r() ) return *this;
if ( _size != r.size() ) resize ( r.size() );
for ( nat i = 0; i < _size; ++i ) _data.var[i] = r[i];
return *this;
}
DynArrRef & operator= ( const DynArrRef & a )
{
return *this = *a;
}
};
Шаблон классов DynArray предназначен для создания динамических массивов, т.е. они могут менять свой размер
во время выполнения программы. В его конструкторе можно указать к-во элементов.
Функция-член resize меняет размер массива на указанный, при этом значения элементов теряются, даже в случае,
когда новый размер равен предыдущему.
Дружественная функция _swap меняет содержимое двух массивов.
template <class T> class DynArray : public DynArrRef<T>
{
DynArray ( const DynArray & );
public:
explicit DynArray ( nat n = 0 ) : DynArrRef<T> ( n > 0 ? new T[n] : 0, n ) {}
explicit DynArray ( CCArrRef<T> & r ) : DynArrRef<T> ( new T[r.size()], r.size() )
{
for ( nat i = 0; i < _size; ++i ) _data.var[i] = r[i];
}
DynArray ( nat n, const T & a ) : DynArrRef<T> ( n > 0 ? new T[n] : 0, n )
{
for ( nat i = 0; i < _size; ++i ) _data.var[i] = a;
}
~DynArray () { delete[] _data.var; }
DynArray & operator= ( CCArrRef<T> & r )
{
if ( _data.var == r() ) return *this;
if ( _size != r.size() ) resize ( r.size() );
for ( nat i = 0; i < _size; ++i ) _data.var[i] = r[i];
return *this;
}
DynArray & operator= ( const DynArray & a )
{
return *this = *a;
}
virtual DynArrRef<T> & resize ( nat n = 0 )
{
delete[] _data.var;
_data.var = 0; // на случай исключения в new
if ( ( _size = n ) > 0 ) _data.var = new T[n];
return *this;
}
DynArray & swap ( DynArray & a )
{
_swap ( _size, a._size );
_swap ( _data, a._data );
return *this;
}
friend inline void _swap ( DynArray & a1, DynArray & a2 )
{
a1.swap ( a2 );
}
};
Шаблон CmbArray является комбинированным массивом, т.е. в зависимости от размера его элементы
могут находится в стеке или в "куче". Параметр шаблона N определяет размер встроенного массива.
Заметим, что в предыдущем шаблоне DynArray функция-член resize всегда вызывает для старых элементов массива деструктор,
а для новых элементов - конструктор. Для шаблона CmbArray это происходит не всегда. Например, если размеры
массива меняются в пределах N, то значения элементов не меняются.
template <class T, nat N> class CmbArray : public DynArrRef<T>
{
T stor[N];
CmbArray ( const CmbArray & );
public:
explicit CmbArray ( nat n = 0 ) : DynArrRef<T> ( n > N ? new T[n] : stor, n ) {}
explicit CmbArray ( CCArrRef<T> & r ) : DynArrRef<T> ( r.size() > N ? new T[r.size()] : stor, r.size() )
{
for ( nat i = 0; i < _size; ++i ) _data.var[i] = r[i];
}
CmbArray ( nat n, const T & a ) : DynArrRef<<T> ( n > N ? new T[n] : stor, n )
{
for ( nat i = 0; i < _size; ++i ) _data.var[i] = a;
}
~CmbArray () { if ( _data.var != stor ) delete[] _data.var; }
CmbArray & operator= ( CCArrRef<T> & r )
{
if ( _data.var == r() ) return *this;
resize ( r.size() );
for ( nat i = 0; i < _size; ++i ) _data.var[i] = r[i];
return *this;
}
CmbArray & operator= ( const CmbArray & a )
{
return *this = *a;
}
CmbArray & operator -= ( const CmbArray & a )
{
const nat n = _min ( _size, a._size );
for ( nat i = 0; i < n; ++i ) _data.var[i] -= a[i];
return *this;
}
virtual DynArrRef<T> & resize ( nat n = 0 )
{
if ( _size == n ) return *this;
if ( _data.var != stor )
{
delete[] _data.var;
_data.var = stor;
}
if ( ( _size = n ) > N ) _data.var = new T[_size];
return *this;
}
};
Шаблон классов SuiteRef предназначен для создания ссылок на последовательные наборы однотипных элементов.
Функция-член add добавляет в конец массива указанный элемент. Функция-член inc ( increase ) без параметра увеличивает размер набора на 1 и возвращает ссылку на добавленный элемент. Функция-член inc ( increase ) с параметром увеличивает размер набора на величину параметра. Функция-член insert вставляет один элемент на указанную позицию. Элементы расположенные после него сдвигаются. Функция-член dec ( decrease ) уменьшает размер набора на n ( по умолчанию на 1 ). Функция-член del удаляет элемент по указанному индексу. Если он не последний в наборе, то его место занимает последний элемент. Функция-член delAndShift удаляет группу элементов начиная с указанного индекса, а стоящие после них элементы сдвигаются. Функция-член delFirEqu удаляет первый элемент равный указанному. Если он не последний в наборе, то его место занимает последний элемент. Функция-член addAftLas добавляет множество элементов в конец набора. template <class T> class SuiteRef : public DynArrRef<T>
{
SuiteRef ( const SuiteRef & );
void _del ( nat i )
{
if ( i < --_size ) _data.var[i] = _data.var[_size];
}
virtual void resizeAndCopy ( nat n ) = 0;
protected:
nat real_size;
SuiteRef ( T * d, nat n, nat m ) : DynArrRef<T>( d, n ), real_size(m) {}
public:
SuiteRef & operator= ( CCArrRef<T> & r )
{
if ( _data.var == r() ) return *this;
resize ( r.size() );
for ( nat i = 0; i < _size; ++i ) _data.var[i] = r[i];
return *this;
}
SuiteRef & operator= ( const SuiteRef & a )
{
return *this = *a;
}
virtual DynArrRef<T> & resize ( nat n = 0 )
{
if ( n > real_size ) resizeAndCopy ( n );
else _size = n;
return *this;
}
SuiteRef & add ( const T & t )
{
inc() = t;
return *this;
}
SuiteRef & addIfHasNot ( const T & t )
{
for ( nat i = 0; i < _size; ++i ) if ( _data.var[i] == t ) return *this;
inc() = t;
return *this;
}
T & inc ()
{
if ( _size == real_size ) resizeAndCopy ( _size + 1 );
else ++_size;
return _data.var[_size-1];
}
SuiteRef & inc ( nat n )
{
if ( _size + n > real_size ) resizeAndCopy ( _size + n );
else _size += n;
return *this;
}
T & insert ( nat i )
{
if ( i < _size )
{
if ( _size == real_size ) resizeAndCopy ( _size + 1 );
else ++_size;
for ( nat j = _size; --j > i; ) _data.var[j] = _data.var[j-1];
}
else
{
if ( i >= real_size ) resizeAndCopy ( i + 1 );
else _size = i + 1;
}
return _data.var[i];
}
SuiteRef & dec ( nat n = 1 )
{
_size = _size > n ? _size - n : 0;
return *this;
}
SuiteRef & del ( nat i )
{
if ( i < _size ) _del ( i );
#ifdef ARRAY_TEST
else outOfRange ( "SuiteRef::del", _size, i );
#endif ARRAY_TEST
return *this;
}
SuiteRef & delAndShift ( nat i, nat n = 1 )
{
if ( ! n ) return *this;
if ( i < _size )
{
n = _min ( _size - i, n );
_size -= n;
#if _MSC_VER > 1200 // MS VC 6.0
for ( ; i < _size; ++i ) copyFunc ( _data.var[i], _data.var[i+n] );
#else
for ( ; i < _size; ++i ) _data.var[i] = _data.var[i+n];
#endif
}
#ifdef ARRAY_TEST
else outOfRange ( "SuiteRef::delAndShift", _size, i );
#endif ARRAY_TEST
return *this;
}
bool delFirEqu ( const T & t )
{
for ( nat i = 0; i < _size; ++i )
{
if ( _data.var[i] == t ) _del ( i );
return true;
}
return false;
}
SuiteRef & addAftLas ( CCArrRef<T> & a )
{
const nat s = _size;
inc ( a.size() );
for ( nat i = s; i < _size; ++i ) _data.var[i] = a[i-s];
return *this;
}
};
Шаблон классов Suite предназначен для создания последовательных наборов однотипных элементов.
Дружественная функция _swap меняет содержимое двух наборов. template <class T> class Suite : SuiteRef<T>
{
Suite ( const Suite & );
virtual void resizeAndCopy ( nat n )
{
real_size = _max ( real_size + n, 8u );
T * tmp = new T[real_size];
#if _MSC_VER > 1200 // MS VC 6.0
for ( nat i = 0; i < _size; ++i ) copyFunc ( tmp[i], _data.var[i] );
#else
for ( nat i = 0; i < _size; ++i ) tmp[i] = _data.var[i];
#endif
delete[] _data.var;
_data.var = tmp;
_size = n;
}
public:
Suite () : SuiteRef<T>(0, 0, 0) {}
explicit Suite ( nat n, nat m = 0 ) : SuiteRef<T> ( 0, m, _max ( n, m ) )
{
if ( real_size > 0 ) _data.var = new T[real_size];
}
~Suite () { delete[] _data.var; }
Suite & operator= ( CCArrRef<T> & r )
{
if ( _data.var == r() ) return *this;
_size = r.size();
if ( real_size < _size )
{
real_size = _size;
delete[] _data.var;
_data.var = 0; // на случай исключения в new
_data.var = new T[_size];
}
for ( nat i = 0; i < _size; ++i ) _data.var[i] = r[i];
return *this;
}
Suite & operator= ( const Suite & a )
{
return *this = *a;
}
Suite & swap ( Suite & a )
{
_swap ( real_size, a.real_size );
_swap ( _size, a._size );
_swap ( _data, a._data );
return *this;
}
friend inline void _swap ( Suite & a1, Suite & a2 )
{
a1.swap ( a2 );
}
};
#if _MSC_VER > 1200 // MS VC 6.0
template <class T> inline void copyFunc ( T & a, T & b ) { a = b; }
template <class T> inline void copyFunc ( Suite <T> & a, Suite <T> & b ) { _swap ( a, b ); }
template <class T> inline void copyFunc ( DynArray<T> & a, DynArray<T> & b ) { _swap ( a, b ); }
#endif
Шаблон классов CmbSuite также предназначен для создания последовательных наборов однотипных элементов,
но в отличии от шаблона Suite он является комбинированным аналогично CmbArray:
template <class T, nat N> class CmbSuite : public SuiteRef<T>
{
T stor[N];
CmbSuite ( const CmbSuite & );
virtual void resizeAndCopy ( nat n )
{
real_size = _max ( real_size + n, 8u );
T * tmp = new T[real_size];
#if _MSC_VER > 1200 // MS VC 6.0
for ( nat i = 0; i < _size; ++i ) copyFunc ( tmp[i], _data.var[i] );
#else
for ( nat i = 0; i < _size; ++i ) tmp[i] = _data.var[i];
#endif
if ( _data.var != stor ) delete[] _data.var;
_data.var = tmp;
_size = n;
}
public:
CmbSuite () : SuiteRef<T>(stor, 0, N) {}
explicit CmbSuite ( nat n, nat m = 0 ) : SuiteRef<T> ( stor, m, _max ( N, n, m ) )
{
if ( real_size > N ) _data.var = new T[real_size];
}
~CmbSuite () { if ( _data.var != stor ) delete[] _data.var; }
CmbSuite & operator= ( CCArrRef<T> & r )
{
if ( _data.var == r() ) return *this;
_size = r.size();
if ( real_size < _size )
{
real_size = _size;
if ( _data.var != stor )
{
delete[] _data.var;
_data.var = stor; // на случай исключения в new
}
_data.var = new T[_size];
}
for ( nat i = 0; i < _size; ++i ) _data.var[i] = r[i];
return *this;
}
CmbSuite & operator= ( const CmbSuite & a )
{
return *this = *a;
}
};
Шаблон классов LtdSuiteRef предназначен для создания ссылок на набор элементов ограниченного размера.
template <class T> class LtdSuiteRef : public SuiteRef<T>
{
virtual void resizeAndCopy ( nat n )
{
#ifdef ARRAY_TEST
if ( n > real_size ) outOfRange ( "LtdSuiteRef::resizeAndCopy", real_size, n );
#endif
_size = real_size;
}
public:
LtdSuiteRef ( ArrRef<T> & a, nat i, nat n ) : SuiteRef<T>( a(i), 0, n )
{
#ifdef ARRAY_TEST
if ( a.size() < i + n ) outOfRange ( "LtdSuiteRef", a.size(), i + n );
#endif
}
LtdSuiteRef & operator= ( CCArrRef<T> & r )
{
_size = r.size();
#ifdef ARRAY_TEST
if ( _size > real_size ) outOfRange ( "LtdSuiteRef::operator=", real_size, _size );
#endif
if ( _size > real_size ) _size = real_size;
for ( nat i = 0; i < _size; ++i ) _data.var[i] = r[i];
return *this;
}
LtdSuiteRef & operator= ( const LtdSuiteRef & a )
{
return *this = *a;
}
};
В результате получаем следующую иерархию классов:
CArrRef -> MutCArrRef
|
|
ArrRef -> FixArrRef -> FixArray
|
|
DynArrRef -> DynArray, CmbArray
|
|
SuiteRef -> Suite, CmbSuite
|
|
LtdSuiteRef
Семь из них являются интерфейсными ( или ссылками на массив ) и пять - контейнерными классами.
Такое большое к-во классов вызвано стремлением, по возможности, избегать применение операторов new и delete.
Исходники находятся в файле ShevArray.h. Смотрите также раздел Операции с массивами. Наверх |