/* * * Copyright (C) 1997-2021, OFFIS e.V. * All rights reserved. See COPYRIGHT file for details. * * This software and supporting documentation were developed by * * OFFIS e.V. * R&D Division Health * Escherweg 2 * D-26121 Oldenburg, Germany * * * Module: ofstd * * Author: Andreas Barth * * Purpose: * Defines a template list class with interfaces similar to the C++ Standard * */ #ifndef OFLIST_H #define OFLIST_H // Usage (only non standard): // OFListInsert(InputIterator_type, T_type, c, pos, first, last) // Inserts the elements of type T in // range [first, last) into list c, // OFListRemoveIf(Predicate_Type, T_type, c, pred) // Erases all elements of type T in the list referred by // an iterator i where pred(*i) == true. // Predicate_Type is the function type of pred // // Additional Remarks: // In some template functions one template parameter is another function. // Some compilers cannot determine automatically the type of template // function parameters, so you must give them a hint casting // the parameter function to the correct type (e.g. NeXT gcc 2.5.8) #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */ #include "dcmtk/ofstd/oftypes.h" #include "dcmtk/ofstd/ofcast.h" #include "dcmtk/ofstd/ofdefine.h" #ifndef HAVE_CLASS_TEMPLATE #error Your C++ compiler cannot handle class templates: #endif #ifdef HAVE_STL_LIST // It is possible to use the standard template library list class since the // interface is nearly identical. // Important: If you want to use the standard template library (STL), no // variable within a namespace using a class of the STL shall have a name // of one class of the STL #include #ifdef HAVE_STD_NAMESPACE #define OFList std::list #define OFListIterator(x) std::list< x >::iterator #define OFListConstIterator(x) std::list< x >::const_iterator #else #define OFList list #define OFListIterator(x) list< x >::iterator #define OFListConstIterator(x) list< x >::const_iterator #endif #define OFListInsert(InputIterator, T, c, pos, first, last) (c).insert((pos), (first), (last)) #define OFListRemoveIf(Predicate, T, c, pred) (c).remove_if((pred)) // workaround for "implicit typename" warning on gcc 3.x #define OFLIST_TYPENAME OFTypename #else #ifdef HAVE_ITERATOR_HEADER #include #endif // #define INCLUDE_CASSERT // #define INCLUDE_CSTDDEF // #include "dcmtk/ofstd/ofstdinc.h" #include #define OFLIST_TYPENAME BEGIN_EXTERN_C #ifdef HAVE_SYS_TYPES_H /* needed e.g. on Solaris for definition of size_t */ #include #endif END_EXTERN_C // OFListLinkBase, OFListLink and OFListBase are classes for internal // use only and shall not be used. /* non-template double linked list. Base class of OFListLink. * Implicitly used by OFList, should not be called by users. */ struct OFListLinkBase { OFListLinkBase * next; OFListLinkBase * prev; OFBool dummy; OFListLinkBase(): next(NULL), prev(NULL), dummy(OFFalse) { } virtual ~OFListLinkBase() {} private: /* undefined */ OFListLinkBase(const OFListLinkBase&); /* undefined */ OFListLinkBase& operator=(const OFListLinkBase&); }; /* non-template list. Base class fo OFList. * Implicitly used by OFList, should not be called by users. */ class DCMTK_OFSTD_EXPORT OFListBase { protected: OFListLinkBase * afterLast; size_t listSize; void base_recalcListSize(); public: OFListBase(); virtual ~OFListBase(); OFListLinkBase * base_begin() const { return afterLast->next; } OFListLinkBase * base_end() const { return afterLast; } OFBool base_empty() const { return afterLast == afterLast->next; } size_t base_size() const { return listSize; } OFListLinkBase * base_insert(OFListLinkBase * pos, OFListLinkBase * newElem); OFListLinkBase * base_erase(OFListLinkBase * pos); void base_splice(OFListLinkBase * pos, OFListLinkBase * begin, OFListLinkBase * end); void base_clear(); private: /* undefined */ OFListBase(const OFListBase&); /* undefined */ OFListBase& operator=(const OFListBase&); }; /* template class for double linked list entries. * Implicitly used by OFList, should not be called by users. */ template struct OFListLink : public OFListLinkBase { T info; OFListLink(const T& i) : OFListLinkBase(), info(i) { } virtual ~OFListLink() {} private: /* undefined */ OFListLink(const OFListLink&); /* undefined */ OFListLink& operator=(const OFListLink&); }; // Definition of OFList and OFIterator template class OFList; /** iterator class for OFList. An iterator is a generalization of a pointer * and allows a C++ program to work with different containers independently * from their internal structure. Instances of this template class should * be declared as OFListIterator(T) instead of OFListIterator. This * allows to re-map OFList to the STL list class if available. */ template class OFIterator { friend class OFList; protected: /// list node referenced by the iterator OFListLinkBase * node; /** constructor. * @param x list node referenced by the iterator */ OFIterator(OFListLinkBase * x) : node(x) { } public: /// member typedef for T typedef T value_type; /// member typedef for T* typedef T* pointer; /// member typedef for T& typedef T& reference; #ifdef HAVE_BIDIRECTIONAL_ITERATOR_CATEGORY /// member typedef declaring the category typedef STD_NAMESPACE bidirectional_iterator_tag iterator_category; #endif /** default constructor. Creates an iterator referencing nothing. * In general, iterators should always be copy-constructed * in user code. */ OFIterator() : node(NULL) { } /** copy constructor */ OFIterator(const OFIterator& x) : node(x.node) { }; /** copy assignment operator */ OFIterator& operator=(const OFIterator& x) { node = x.node; return *this; } /** comparison of two iterators. The iterators are equal if and only if * they reference the same element, independent from the element values. * @param x iterator to be compared * @return OFTrue if equal, OFFalse otherwise. */ OFBool operator==(const OFIterator& x) const { return node == x.node; } /** comparison of two iterators. The iterators are equal if and only if * they reference the same element, independent from the element values. * @param x iterator to be compared * @return OFTrue if not equal, OFFalse otherwise. */ OFBool operator!=(const OFIterator& x) const { return node != x.node; } /** dereferences the iterator. May only be called if iterator references * a valid element of a list. * @return reference to the element "pointed to" by the iterator. */ T& operator*() const { assert(!node->dummy); return (OFstatic_cast(OFListLink *,node))->info; } /** dereferences the iterator. May only be called if iterator references * a valid element of a list. * @return reference to the element "pointed to" by the iterator. */ T* operator->() const { return &(**this); } /** moves the iterator to the next element of the list. * The list is circular: the first element follows after the end of the list. * May only be called if iterator references a valid element or the end of a list. * @return reference to the incremented iterator. */ OFIterator& operator++() { node = node->next; return *this; } /** moves the iterator to the next element of the list. * The list is circular: the first element follows after the end of the list. * May only be called if iterator references a valid element or the end of a list. * This is the post-increment operator. * @return previous iterator state, by value */ OFIterator operator++(int) { OFIterator tmp(*this); node = node->next; return tmp; } /** moves the iterator to the previous element of the list. * The list is circular: the end of the list follows before the first element. * May only be called if iterator references a valid element or the end of a list. * @return reference to the decremented iterator. */ OFIterator& operator--() { node = node->prev; return *this; } /** moves the iterator to the previous element of the list. * The list is circular: the end of the list follows before the first element. * May only be called if iterator references a valid element or the end of a list. * This is the post-decremented operator. * @return previous iterator state, by value */ OFIterator operator--(int) { OFIterator tmp(*this); node = node->prev; return tmp; } }; /** double linked list template class. The interface is a subset of the STL * list class. */ template class OFList : private OFListBase { public: /** inserts an element into the list before the given position. * @param position iterator to position before which the element is inserted * @param x value from which the new list entry is copy-constructed * @return iterator pointing to the new element in the list */ OFIterator insert(OFIterator position, const T& x) { return OFIterator(OFListBase::base_insert(position.node, new OFListLink(x))); } private: /** inserts a copy of the given list into the current list. * @param oldList list to be copied */ void copy(const OFList& oldList) { OFIterator vfirst(oldList.begin()); OFIterator vend(oldList.end()); OFIterator vpos(this->end()); while (vfirst != vend) { insert(vpos, *vfirst); ++vfirst; } } /** counts the elements in the list and adjusts the listSize * member variable. */ void recalcListSize() { OFListBase::base_recalcListSize(); } public: /** default constructor */ OFList() : OFListBase() { } /** copy constructor */ OFList(const OFList& oldList):OFListBase() { copy(oldList); } /** returns an iterator referencing the first element in the list. * If the list is empty, then begin() == end(). * @return iterator to first element of list, by value. */ OFIterator begin() const { return OFIterator(OFListBase::base_begin()); } /** returns an iterator which points to the past-to-end element * of the list. * @return iterator to past-to-end, by value. */ OFIterator end() const { return OFIterator(OFListBase::base_end()); } /** returns true if list is empty. * @return OFTrue if list is empty, OFFalse otherwise. */ OFBool empty() const { return OFListBase::base_empty(); } /** returns number of elements in the list. * @return number of elements */ size_t size() const { return OFListBase::base_size(); } /** returns a reference to the first element in the list. * May only be called if list is non-empty. * @return first element in list, by reference */ T& front() { return *begin(); } /** returns a constant reference to the first element in the list. * May only be called if list is non-empty. * @return first element in list, by constant reference */ const T& front() const { return *begin(); } /** returns a reference to the last element in the list. * May only be called if list is non-empty. * @return last element in list, by reference */ T& back() { return *(--end()); } /** returns a constant reference to the last element in the list. * May only be called if list is non-empty. * @return last element in list, by constant reference */ const T& back() const { return *(--end()); } /** inserts before the first element of the list. * @param x value from which the new list entry is copy constructed */ void push_front(const T& x) { insert(begin(), OFconst_cast(T&, x)); } /* const cast away to keep some old compilers happy */ /** removes the first element of the list. * May only be called if list is non-empty. * All iterators pointing to the removed element become invalid. */ void pop_front() { erase(begin()); } /** inserts after the last element of the list. * @param x value from which the new list entry is copy constructed */ void push_back(const T& x) { insert(end(), OFconst_cast(T&, x)); } /* const cast away to keep some old compilers happy */ /** removes the last element of the list. * May only be called if list is non-empty. * All iterators pointing to the removed element become invalid. */ void pop_back() { erase(--end()); } /** inserts n elements with value x into the list, before the given position. * @param position iterator to position before which the elements are inserted * @param n number of entries to be created * @param x value from which the new list entries are copy-constructed */ void insert(OFIterator position, size_t n, const T& x) { while(n) { --n; OFListBase::base_insert(position.node, new OFListLink(x)); } } /** removes the element at the given position from the list. * All iterators pointing to the removed element become invalid. * @return iterator pointing to the element after the removed one */ OFIterator erase(OFIterator position) { return OFIterator(OFListBase::base_erase(position.node)); } /** removes all elements in the range [position,last) from the list. * All iterators pointing to the removed elements become invalid. * @param position iterator to the first element to be deleted * @param last iterator pointing to the element after the last element to be removed * @return iterator pointing to the element after the last removed element */ OFIterator erase(OFIterator position, OFIterator last) { while (position != last) position = erase(position); return last; } /** removes all elements from the list. * All iterators pointing to elements in the list become invalid. */ void clear() { OFListBase::base_clear(); } /** moves the contents of list x into the current list before the * given position. * @param position iterator to position before which the elements are inserted * @param x list from which the elements are taken, becomes empty */ void splice(OFIterator position, OFList& x) { splice(position, x, x.begin(), x.end()); } /** inserts one element from list x into the current list and removes it from x * @param position iterator to position before which the element is inserted * @param x list from which the element is taken * @param i iterator to element in list x which is to be moved */ void splice(OFIterator position, OFList& x, OFIterator i) { OFIterator change(i); ++i; splice(position, x, change, i); } /** inserts elements in the range [first, last) before position and * removes the elements from x * @param position iterator to position before which the elements are inserted * @param x list from which the elements are taken * @param first iterator to first element in list x to be moved * @param last iterator to element after last element in list x to be moved */ void splice(OFIterator position, OFList& x, OFIterator first, OFIterator last) { OFListBase::base_splice(position.node, first.node, last.node); x.recalcListSize(); } /** removes all elements from the list referred by an iterator i where * *i == value * @param value value to be compared with list contents */ void remove(const T& value) { OFIterator first = begin(); OFIterator last = end(); while(first != last) { if (*first == value) first = erase(first); else ++first; } } /** copy assignment operator * @param arg the list to copy from * @return *this */ OFList& operator=(const OFList& arg) { clear(); copy(arg); return *this; } }; #ifdef HAVE_FUNCTION_TEMPLATE #define OFListInsert(InputIterator, T, c, pos, first, last) OF_ListInsert((c), (pos), (first), (last)) #define OFListRemoveIf(Predicate, T, c, pred) OF_ListRemoveIf((c), (pred)) #elif defined(HAVE_STATIC_TEMPLATE_METHOD) #define OFListInsert(InputIterator, T, c, pos, first, last) OF_ListInsertClass::OF_ListInsert((c), (pos), (first), (last)) #define OFListRemoveIf(Predicate, T, c, pred) OF_ListRemoveIfClass::OF_ListRemoveIf((c), (pred)) #else #error Your C++ Compiler is not capable of compiling this code #endif // Insert the elements in range [first, last) into list template #if defined(HAVE_STATIC_TEMPLATE_METHOD) && !defined(HAVE_FUNCTION_TEMPLATE) class OF_ListInsertClass { public: static #endif void OF_ListInsert(OFList& c, OFIterator position, InputIterator first, InputIterator last) { while(first != last) { c.insert(position, *first); ++first; } } #if defined(HAVE_STATIC_TEMPLATE_METHOD) && !defined(HAVE_FUNCTION_TEMPLATE) }; #endif // Erases all elements in the list referred by an iterator i where // pred(*i) == true template #if defined(HAVE_STATIC_TEMPLATE_METHOD) && !defined(HAVE_FUNCTION_TEMPLATE) class OF_ListRemoveIfClass { public: static #endif void OF_ListRemoveIf(OFList& c, Predicate pred) { OFIterator first = c.begin(); OFIterator last = c.end(); while (first != last) { if (pred(*first)) first = c.erase(first); else ++first; } } #if defined(HAVE_STATIC_TEMPLATE_METHOD) && !defined(HAVE_FUNCTION_TEMPLATE) }; #endif #define OFListIterator(x) OFIterator< x > #define OFListConstIterator(x) OFIterator< x > #endif #endif