Списки (продолжение)

Классы ShevItem и ShevList предназначены в основном для использования, как базовые классы, хотя в простейших случаях можно обойтись без наследования, используя член info. В большинстве других случаев можно применить шаблоны, которые представлены ниже:

template <class T> class ListItem : public T, public ShevItem
{
public:
    ListItem () {}
    explicit ListItem ( const T & t, int i = -123456789 ) : T(t), ShevItem(i) {}
    T & base () { return *this; }
};

template <class T> class ListItemA : public ShevItem
{
public:
    T a;
    ListItemA () {}
    explicit ListItemA ( const T & t, int i = -123456789 ) : a(t), ShevItem(i) {}
    operator const T & () const { return a; }
};

template <class T> class List : public ShevList
{
// Запрет конструктора копии и оператора присваивания:
    List ( List & );
    void operator = ( List & );
public:
    List() {}

    const T * fir() const { return (const T *) ShevList::fir(); }
    const T * cur() const { return (const T *) ShevList::cur(); }
    const T * las() const { return (const T *) ShevList::las(); }

    T * fir ( Predicate1 & pre ) { return (T *) ShevList::fir(pre); }
    T * las ( Predicate1 & pre ) { return (T *) ShevList::las(pre); }

    const T * fir ( Predicate1 & pre ) const { return (const T *) ShevList::fir(pre); }
    const T * las ( Predicate1 & pre ) const { return (const T *) ShevList::las(pre); }

    T * fir ()  { return (T *) ShevList::fir (); }
    T * cur ()  { return (T *) ShevList::cur (); }
    T * las ()  { return (T *) ShevList::las (); }
    T * top ()  { return (T *) ShevList::top (); }
    T * end ()  { return (T *) ShevList::end (); }
    T * prev()  { return (T *) ShevList::prev(); }
    T * next()  { return (T *) ShevList::next(); }
    T * cprev() { return (T *) ShevList::cprev(); }
    T * cnext() { return (T *) ShevList::cnext(); }

// Сделать текущим данный элемент ( небезопасная функция ):
    List & jump ( T * i ) { return (List&) ShevList::jump(i); }
// Добавить в список один элемент
    List & addBefFir ( T * i ) { return (List&) ShevList::addBefFir(i); } // перед первым
    List & addBefCur ( T * i ) { return (List&) ShevList::addBefCur(i); } // перед текущим и сделать его текущим
    List & addAftCur ( T * i ) { return (List&) ShevList::addAftCur(i); } // после текущего и сделать его текущим
    List & addAftLas ( T * i ) { return (List&) ShevList::addAftLas(i); } // после последнего элемента
// Добавить из другого списка
    List & addAllBefFir ( List & list ) { return (List&) ShevList::addAllBefFir(list); } // все элементы в начало
    List & addAllBefCur ( List & list ) { return (List&) ShevList::addAllBefCur(list); } // все элементы перед текущим
    List & addAllAftCur ( List & list ) { return (List&) ShevList::addAllAftCur(list); } // все элементы после текущего
    List & addAllAftLas ( List & list ) { return (List&) ShevList::addAllAftLas(list); } // все элементы в конец

    T * addNewBefFir ( List & list )
    {
        if ( list.las() )
            list.ShevList::movLasBefFir ( *this );
        else
            ShevList::addBefFir ( new T );
        return fir();
    }

    T * addNewAftLas ( List & list )
    {
        if ( list.las() )
            list.ShevList::movLasAftLas ( *this );
        else
            ShevList::addAftLas ( new T );
        return las();
    }

    List & invert     () { return (List&) ShevList::invert (); }
    List & makeCurFir () { return (List&) ShevList::makeCurFir (); }
    List & makeCurLas () { return (List&) ShevList::makeCurLas (); }
    List & makeFir ( T * p ) { return (List&) ShevList::makeFir ( p ); }
    List & makeLas ( T * p ) { return (List&) ShevList::makeLas ( p ); }
    List & sort123    () { return (List&) ShevList::sort123 (); }
    List & sort321    () { return (List&) ShevList::sort321 (); }

    List & movFirBefFir ( List & list ) { return (List&) ShevList::movFirBefFir ( list ); }
    List & movFirBefCur ( List & list ) { return (List&) ShevList::movFirBefCur ( list ); }
    List & movFirAftCur ( List & list ) { return (List&) ShevList::movFirAftCur ( list ); }
    List & movFirAftLas ( List & list ) { return (List&) ShevList::movFirAftLas ( list ); }
    List & movCurBefFir ( List & list ) { return (List&) ShevList::movCurBefFir ( list ); }
    List & movCurBefCur ( List & list ) { return (List&) ShevList::movCurBefCur ( list ); }
    List & movCurAftCur ( List & list ) { return (List&) ShevList::movCurAftCur ( list ); }
    List & movCurAftLas ( List & list ) { return (List&) ShevList::movCurAftLas ( list ); }
    List & movLasBefFir ( List & list ) { return (List&) ShevList::movLasBefFir ( list ); }
    List & movLasBefCur ( List & list ) { return (List&) ShevList::movLasBefCur ( list ); }
    List & movLasAftCur ( List & list ) { return (List&) ShevList::movLasAftCur ( list ); }
    List & movLasAftLas ( List & list ) { return (List&) ShevList::movLasAftLas ( list ); }

    List & movFirBefFir ( nat n, List & list ) { return (List&) ShevList::movFirBefFir ( n, list ); }
    List & movLasAftLas ( nat n, List & list ) { return (List&) ShevList::movLasAftLas ( n, list ); }
    List & movAllBefFir ( List & list ) { return (List&) ShevList::movAllBefFir ( list ); }
    List & movAllBefCur ( List & list ) { return (List&) ShevList::movAllBefCur ( list ); }
    List & movAllAftCur ( List & list ) { return (List&) ShevList::movAllAftCur ( list ); }
    List & movAllAftLas ( List & list ) { return (List&) ShevList::movAllAftLas ( list ); }
// Обмен элементами внутри списка:
    ShevList & swapCurAndFir () { return (List&) ShevList::swapCurAndFir (); }
    ShevList & swapCurAndLas () { return (List&) ShevList::swapCurAndLas (); }
    ShevList & swapFirAndLas () { return (List&) ShevList::swapFirAndLas (); }
// Обмен элементами между двумя списками:
    List & swapCurAndCur ( List & list ) { return (List&) ShevList::swapCurAndCur ( list ); } // Обмен текущими элементами
    List & swapAllAndAll ( List & list ) { return (List&) ShevList::swapAllAndAll ( list ); } // Обмен всеми элементами
// Для всех элементов присвоить члену info значение i:
    List & setAllInfo ( int i ) { return (List&) ShevList::setAllInfo(i); }
// Удаление элементов из списка
    List & delFir () { return (List&) ShevList::delFir (); }
    List & delCur () { return (List&) ShevList::delCur (); }
    List & delLas () { return (List&) ShevList::delLas (); }

    template <class F> List & delSel ( F & filter )
    {
        if ( top() ) for(;;)
        { 
            if ( filter ( *cur() ) )
            {
                if ( delCur_() ) break;
                continue;
            }
            if ( ! next() ) break; 
        }
        return *this;
    }

    template <class T2> List & operator += ( const T2 & p )
    {
        if ( top() ) do { *cur() += p; } while ( next() );  return *this;
    }

    template <class T2> List & operator -= ( const T2 & p )
    {
        if ( top() ) do { *cur() -= p; } while ( next() );  return *this;
    }

    template <class T2> List & operator *= ( const T2 & p )
    {
        if ( top() ) do { *cur() *= p; } while ( next() );  return *this;
    }

    template <class T2> List & operator /= ( const T2 & p )
    {
        if ( top() ) do { *cur() /= p; } while ( next() );  return *this;
    }

    List & resize ( nat n )
    {
        while ( size() > n ) ShevList::delLas();
        while ( size() < n ) ShevList::addAftLas ( new T );
        return *this;
    }

    List & resize ( nat n, List & stor )
    {
        stor.addAllBefFir(*this).movFirBefFir ( n, *this );
        while ( size() < n ) ShevList::addAftLas ( new T );
        return *this;
    }
};

Шаблоны ListItem и ListItemA создают производные классы от ShevItem. Шаблон List делает производные классы от ShevList. В качестве параметра для него нужно задавать класс производный от ShevItem.

Иногда нужно передать список в функцию для того, чтобы его можно было просматривать, но не изменять. Для этого предназначен класс ShowList и производные от него:

class ShowList
{
    const ShevItem *       cPtr; // указатель на текущий элемент списка
    const ShevItem * const fPtr; // указатель на первый элемент списка
    const ShevItem * const lPtr; // указатель на последний элемент списка
    const unsigned int listSize; // количество элементов в списке
public:
    ShowList ( const ShevList & p ) : cPtr(p.cPtr), fPtr(p.fPtr), lPtr(p.lPtr), listSize(p.listSize) {}
// Количество элементов в списке:
    unsigned int size () const { return listSize; }
// Количество элементов с заданным свойством
    unsigned int count ( Predicate1 & ) const;
// Первый элемент с заданным свойством:
    const ShevItem * fir ( Predicate1 & ) const;
// Последний элемент с заданным свойством:
    const ShevItem * las ( Predicate1 & ) const;
// Текущий элемент первый?
    bool curIsFir () const { return cPtr == fPtr; }
// Текущий элемент последний?
    bool curIsLas () const { return cPtr == lPtr; }
// Имеется ли списке данный элемент?
    bool has ( const ShevItem * ) const;
// Доступ к отдельному элементу списка
    const ShevItem * fir () const { return fPtr; }
    const ShevItem * cur () const { return cPtr; }
    const ShevItem * las () const { return lPtr; }
// Сделать текущим первый элемент
    const ShevItem * top () { return cPtr = fPtr; }
// Сделать текущим последний элемент
    const ShevItem * end () { return cPtr = lPtr; }
// Сделать текущим предыдущий элемент
    const ShevItem * prev () { return cPtr != fPtr ? cPtr = cPtr->prevPtr : 0; }
// Сделать текущим следующий элемент
    const ShevItem * next () { return cPtr != lPtr ? cPtr = cPtr->nextPtr : 0; }
// Сделать текущим предыдущий элемент в цикле
    const ShevItem * cprev () { return cPtr = (cPtr==fPtr) ? lPtr : cPtr->prevPtr; }
// Сделать текущим следующий элемент в цикле
    const ShevItem * cnext () { return cPtr = (cPtr==lPtr) ? fPtr : cPtr->nextPtr; }
// Сделать текущим данный элемент ( небезопасная функция ):
    void jump ( const ShevItem * m ) { cPtr = m; }
// Сделать текущим первый элемент с заданным свойством:
    bool findFir ( Predicate1 & );
// Сделать текущим последний элемент с заданным свойством:
    bool findLas ( Predicate1 & );
};

template <class T> class Show : public ShowList
{
public:
    Show ( const List<T> & p ) : ShowList ( p ) {}
// Доступ к отдельному элементу списка
    const T * fir () const { return (const T *) ShowList::fir(); }
    const T * cur () const { return (const T *) ShowList::cur(); }
    const T * las () const { return (const T *) ShowList::las(); }
// Первый элемент с заданным свойством:
    const T * fir ( Predicate1 & p ) const { return (const T *) ShowList::fir(); }
// Последний элемент с заданным свойством:
    const T * las ( Predicate1 & p ) const { return (const T *) ShowList::las(); }
// Сделать текущим первый элемент
    const T * top () { return (const T *) ShowList::top(); }
// Сделать текущим последний элемент
    const T * end () { return (const T *) ShowList::end(); }
// Сделать текущим предыдущий элемент
    const T * prev () { return (const T *) ShowList::prev(); }
// Сделать текущим следующий элемент
    const T * next () { return (const T *) ShowList::next(); }
// Сделать текущим предыдущий элемент в цикле
    const T * cprev () { return (const T *) ShowList::cprev(); }
// Сделать текущим следующий элемент в цикле
    const T * cnext () { return (const T *) ShowList::cnext(); }
// Сделать текущим данный элемент ( небезопасная функция ):
    void jump ( const T * m ) { ShowList::jump ( m ); }
};

Интерфейс класса ShowList аналогичен интерфейсу класса ShevList, но имеет только те методы, которые не меняют список и его элементы.

Исходники находятся в файлах ShevList.h и ShevList.cpp

Начало