// Created on: 2001-01-29 // Created by: Alexander GRIGORIEV // Copyright (c) 2001-2014 OPEN CASCADE SAS // // This file is part of Open CASCADE Technology software library. // // This library is free software; you can redistribute it and/or modify it under // the terms of the GNU Lesser General Public License version 2.1 as published // by the Free Software Foundation, with special exception defined in the file // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT // distribution for complete text of the license and disclaimer of any warranty. // // Alternatively, this file may be used under the terms of Open CASCADE // commercial license or contractual agreement. #ifndef LDOM_DeclareSequence_HeaderFile #define LDOM_DeclareSequence_HeaderFile #ifndef _Standard_Macro_HeaderFile #include "Standard_Macro.hxx" #endif // Declaration of Sequence (numbered list) class. // Remarks on the current implementation: // // 1. Methods First() and Last() added // 2. The method InsertAt(anIndex) replaces InsertBefore and InsertAfter. // This method never throws exception "OutOfRange". Its behaviour: // anIndex <= 1 => equivalent to Prepend() // anIndex > Length() => equivalent to Append() // else => equivalent to InsertBefore. // ******************************************************************* // use the following somewhere in a header file; // ClassName - name of the list class to create // Type - type of members of the list // ******************************************************************* #define DECLARE_SEQUENCE(ClassName, Type) \ \ class ClassName \ { \ public: \ inline ClassName(); \ inline ClassName(const ClassName& anOther); \ inline ClassName& operator=(const ClassName& anOther); \ inline int Length() const; \ inline const Type& First() const; \ inline const Type& Last() const; \ inline const Type& Value(const int) const; \ inline Type& ChangeValue(const int); \ inline const Type& operator()(const int) const; \ inline Type& operator()(const int); \ \ Standard_EXPORT virtual ~ClassName(); \ Standard_EXPORT void Append(const Type& aVal); \ Standard_EXPORT void Prepend(const Type& aVal); \ Standard_EXPORT void InsertAt(const int, const Type& aVal); \ Standard_EXPORT void Clear(); \ Standard_EXPORT void Remove(const int); \ \ private: \ class Node \ { \ private: \ Type myValue; \ Node* myPrev; \ Node* myNext; \ \ public: \ Node(const Type& aValue, Node* aPrv, Node* aNxt) \ : myValue(aValue), \ myPrev(aPrv), \ myNext(aNxt) \ { \ } \ const Type& Value() const \ { \ return myValue; \ } \ Type& ChangeValue() \ { \ return myValue; \ } \ friend class ClassName; \ }; \ \ Standard_EXPORT const void* FindItem(const int) const; \ Standard_EXPORT void Assign(const ClassName& anOther); \ \ Node* myFirst; \ Node* myLast; \ Node* myCurrent; \ int myICur; \ int myLength; \ }; \ \ inline ClassName::ClassName() \ : myFirst(NULL), \ myLast(NULL), \ myCurrent(NULL), \ myICur(0), \ myLength(0) \ { \ } \ \ inline ClassName::ClassName(const ClassName& anOther) \ : myFirst(NULL) \ { \ Assign(anOther); \ } \ \ inline ClassName& ClassName::operator=(const ClassName& anOther) \ { \ Assign(anOther); \ return *this; \ } \ \ inline int ClassName::Length() const \ { \ return myLength; \ } \ \ inline const Type& ClassName::First() const \ { \ return myFirst->Value(); /* exception if out of range */ \ } \ \ inline const Type& ClassName::Last() const \ { \ return myLast->Value(); /* exception if out of range */ \ } \ \ inline const Type& ClassName::Value(const int anI) const \ { \ const Node* anItem = (const Node*)FindItem(anI); \ return anItem->Value(); /* exception if out of range */ \ } \ \ inline Type& ClassName::ChangeValue(const int anI) \ { \ Node* anItem = (Node*)FindItem(anI); \ return anItem->ChangeValue(); /* exception if out of range */ \ } \ \ inline const Type& ClassName::operator()(const int anI) const \ { \ return Value(anI); \ } \ \ inline Type& ClassName::operator()(const int anI) \ { \ return ChangeValue(anI); \ } // ******************************************************************* // use the following in a translation unit (*.cxx); // // ******************************************************************* #define IMPLEMENT_SEQUENCE(ClassName, Type) \ const void* ClassName::FindItem(const int anI) const \ { \ if (anI < 1 || anI > myLength) \ return NULL; \ int aCounter; \ Node* aCurrent = (Node*)myCurrent; \ bool aDir(false); \ if (aCurrent == NULL) \ { \ aCurrent = myFirst; \ aCounter = anI - 1; \ aDir = true; \ } \ else \ { \ aCounter = std::abs(anI - myICur); \ if (anI <= aCounter) \ { \ aCurrent = myFirst; \ aCounter = anI - 1; \ aDir = true; \ } \ else if (myLength - anI < aCounter) \ { \ aCurrent = myLast; \ aCounter = myLength - anI; \ } \ else if (anI > myICur) \ aDir = true; \ } \ if (aDir) \ while (aCounter--) \ aCurrent = aCurrent->myNext; \ else \ while (aCounter--) \ aCurrent = aCurrent->myPrev; \ (int&)myICur = anI; \ (Node*&)myCurrent = aCurrent; \ return aCurrent; \ } \ \ ClassName::~ClassName() \ { \ Clear(); \ } \ \ void ClassName::Append(const Type& aVal) \ { \ Node* anItem = new Node(aVal, myLast, NULL); \ if (myLength == 0) \ myFirst = anItem; \ else \ myLast->myNext = anItem; \ myLast = anItem; \ myLength++; \ } \ \ void ClassName::Prepend(const Type& aVal) \ { \ Node* anItem = new Node(aVal, NULL, myFirst); \ if (myLength == 0) \ myLast = anItem; \ else \ myFirst->myPrev = anItem; \ myFirst = anItem; \ myLength++; \ if (myICur > 0) \ myICur++; \ } \ \ void ClassName::InsertAt(const int anI, const Type& aVal) \ { \ if (anI <= 1) \ Prepend(aVal); \ else if (anI > myLength) \ Append(aVal); \ else if (FindItem(anI)) \ { \ Node* anItem = new Node(aVal, myCurrent->myPrev, myCurrent); \ myCurrent->myPrev = anItem; \ if (anItem->myPrev) \ anItem->myPrev->myNext = anItem; \ myLength++; \ myICur++; \ } \ } \ \ void ClassName::Clear() \ { \ while (myFirst) \ { \ Node* aCurr = myFirst->myNext; \ delete myFirst; \ myFirst = aCurr; \ } \ myFirst = myLast = myCurrent = NULL; \ myLength = 0; \ myICur = 0; \ } \ \ void ClassName::Remove(const int anI) \ { \ Node* anItem = (Node*)FindItem(anI); \ if (anItem) \ { \ if (myCurrent->myPrev) \ { \ myCurrent->myPrev->myNext = myCurrent->myNext; \ } \ if (myCurrent->myNext) \ { \ myCurrent->myNext->myPrev = myCurrent->myPrev; \ myCurrent = myCurrent->myNext; \ } \ else \ { \ myCurrent = myCurrent->myPrev; \ myICur--; \ } \ if (myFirst == anItem) \ myFirst = myFirst->myNext; \ if (myLast == anItem) \ myLast = myLast->myPrev; \ delete anItem; \ myLength--; \ } \ } \ \ void ClassName::Assign(const ClassName& anOther) \ { \ Clear(); \ if (anOther.Length() == 0) \ return; \ myFirst = new Node(anOther.First(), NULL, NULL); \ Node* aPrevious = myFirst; \ myLength = 1; \ while (myLength < anOther.Length()) \ { \ myLength++; \ Node* aCurrent = new Node(anOther.Value(myLength), aPrevious, NULL); \ aPrevious = aPrevious->myNext = aCurrent; \ } \ myLast = aPrevious; \ } #endif