/******************************************************************************* * Copyright IBM Corp. and others 1996 * * This program and the accompanying materials are made available under * the terms of the Eclipse Public License 2.0 which accompanies this * distribution and is available at https://www.eclipse.org/legal/epl-2.0/ * or the Apache License, Version 2.0 which accompanies this distribution * and is available at https://www.apache.org/licenses/LICENSE-2.0. * * This Source Code may also be made available under the following Secondary * Licenses when the conditions for such availability set forth in the * Eclipse Public License, v. 2.0 are satisfied: GNU General Public License, * version 2 with the GNU Classpath Exception [1] and GNU General Public * License, version 2 with the OpenJDK Assembly Exception [2]. * * [1] https://www.gnu.org/software/classpath/license.html * [2] https://openjdk.org/legal/assembly-exception.html * * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 OR GPL-2.0-only WITH OpenJDK-assembly-exception-1.0 *******************************************************************************/ /***************************************************************************/ /* */ /* File name: llistof.h */ /* Purpose: Definition of the LinkedListOf template class. */ /* */ /***************************************************************************/ #ifndef CS2_LLISTOF_H #define CS2_LLISTOF_H #define IN_CS2_LLISTOF_H #include "cs2/cs2.h" #include "cs2/allocator.h" #ifdef CS2_ALLOCINFO #define allocate(x) allocate(x, __FILE__, __LINE__) #define deallocate(x,y) deallocate(x, y, __FILE__, __LINE__) #define reallocate(x,y,z) reallocate(x, y, z, __FILE__, __LINE__) #endif namespace CS2 { #define CS2_LL_TEMP template <class ADataType, class Allocator> #define CS2_LL_DECL LinkedListOf <ADataType, Allocator> template <class ADataType, class Allocator> class LinkedListOf : private Allocator { public: LinkedListOf (const Allocator &a = Allocator()) : Allocator(a), fFirst(NULL) {} ~LinkedListOf(); LinkedListOf (const CS2_LL_DECL &); const Allocator& allocator() const { return *this;} Allocator& allocator() { return *this;} CS2_LL_DECL &operator= (const CS2_LL_DECL &); // Add an item to the list. By default, items are added at the beginning // of the list. Specify atEnd = true if the item is to be added at the end. // For adding items anywhere else in the list, use the cursor class. void Add (const ADataType &, bool atEnd = false); // Remove an item from the list. By default, items are removed from the beginning // of the list. Specify atEnd = true if the item is to be removed from the end. // For removing items anywhere else in the list, use the cursor class. void Remove (bool atEnd = false); // Convenience methods for Add and Remove with atEnd = false void Push (const ADataType &); void Pop (); // Return first item of the list, or NULL if empty. ADataType *Head (); // Append another list at the end of this list void Append (const CS2_LL_DECL &); // Check if the list is empty. bool IsEmpty() const; // Make the list empty. void MakeEmpty(); // Compute the number of elements (expensive) uint32_t NumberOfElements() const; // Return the number of bytes of memory used by the list unsigned long MemoryUsage() const; // Dump the linked list template <class str> friend str &operator<< (str &out, const CS2_LL_DECL &ll) { LinkedListItem *p = ll.fFirst; out << "( "; while (p) { out << p->Data() << " "; p = p->Next(); } out << ")"; return out; } private: #define CS2_LL_ITEM CS2_LL_DECL::LinkedListItem class LinkedListItem { public: void *operator new (size_t, void *ptr) { return ptr;} LinkedListItem(); // ~LinkedListItem(); LinkedListItem (const ADataType &, typename CS2_LL_ITEM *); ADataType &Data(); void SetData (const ADataType &); typename CS2_LL_ITEM *Next() const; void SetNext (typename CS2_LL_ITEM *); private: LinkedListItem (const LinkedListItem &); LinkedListItem &operator= (const LinkedListItem &); ADataType fData; typename CS2_LL_ITEM *fNext; }; friend class LinkedListItem; public: #define CS2_LLC_DECL CS2_LL_DECL::Cursor class Cursor { public: Cursor (CS2_LL_DECL &); // ~Cursor(); Cursor (const typename CS2_LLC_DECL &); // Set the cursor position - return flag indicating if position is valid bool SetToFirst(); bool SetToNext(); bool SetToLast(); typename CS2_LL_ITEM *Next() const; // Determine if the cursor points at a valid position bool Valid() const; // Check if a cursor points to the last position (must be valid) bool IsLast() const; // Get/set the data at the current position in the list. ADataType &Data() const; ADataType &operator*(); ADataType *operator->(); void SetData (const ADataType &); // Add an item to the list after the current position. void AddAfter (const ADataType &); // Delete the item on the list after the current position. void DeleteAfter(); // Check for equality int operator== (const typename CS2_LLC_DECL &) const; friend class CS2_LL_DECL; private: typename CS2_LLC_DECL &operator= (const typename CS2_LLC_DECL &); protected: CS2_LL_DECL& fList; typename CS2_LL_ITEM *fItem; }; friend class Cursor; private: LinkedListItem *fFirst; }; // LinkedListOf::MakeEmpty // // Make the list empty. CS2_LL_TEMP inline void CS2_LL_DECL::MakeEmpty() { typename CS2_LL_ITEM *p, *np; for (p = fFirst; p != NULL; p = np) { np = p->Next(); p->~LinkedListItem(); Allocator::deallocate(p, sizeof(LinkedListItem)); } fFirst = NULL; } CS2_LL_TEMP inline CS2_LL_DECL::~LinkedListOf() { MakeEmpty(); } // LinkedListOf::Add // // Add an item to the list. By default, items are added at the beginning // of the list. Specify atEnd = true if the item is to be added at the end. // For adding items anywhere else in the list, use the cursor class. CS2_LL_TEMP inline void CS2_LL_DECL::Add (const ADataType &data, bool atEnd) { typename CS2_LL_ITEM *newp; if (atEnd && fFirst) { typename CS2_LL_ITEM *p = fFirst; while (p->Next()) p = p->Next(); newp = (LinkedListItem *)Allocator::allocate(sizeof(LinkedListItem)); newp = new (newp) typename CS2_LL_ITEM (data, NULL); p->SetNext (newp); } else { newp = (LinkedListItem *) Allocator::allocate(sizeof(LinkedListItem)); newp = new (newp) typename CS2_LL_ITEM (data, fFirst); fFirst = newp; } } // LinkedListOf::Remove // // Remove an item from the list. By default, items are removed from the beginning // of the list. Specify atEnd = true if the item is to be removed from the end. // For removing items anywhere else in the list, use the cursor class. CS2_LL_TEMP inline void CS2_LL_DECL::Remove (bool atEnd) { typename CS2_LL_ITEM *p, *np; if (fFirst != NULL) { if (atEnd) { p = NULL; np = fFirst; while (np->Next()) {p = np; np = np->Next(); } // np is last, p is previous to last np->~LinkedListItem(); Allocator::deallocate(np, sizeof(LinkedListItem)); if (p) { p->SetNext(NULL); } else { fFirst = NULL; } } else { p = fFirst; np = p->Next(); p->~LinkedListItem(); Allocator::deallocate(p, sizeof(LinkedListItem)); fFirst = np; } } } // LinkedListOf::Push // // Convenience method pushing an item onto the list. Identical to Add(data) CS2_LL_TEMP inline void CS2_LL_DECL::Push (const ADataType &data) { Add(data); } // LinkedListOf::Pop // // Convenience method popping an item from the top of the list. Identical to Remove(data) CS2_LL_TEMP inline void CS2_LL_DECL::Pop () { Remove(); } // LinkedListOf::Head // // return the first item of the list, or NULL if empty. CS2_LL_TEMP inline ADataType *CS2_LL_DECL::Head () { if (fFirst == NULL) return NULL; return &(fFirst->Data()); } // LinkedListOf::IsEmpty // // Check if the list is empty. CS2_LL_TEMP inline bool CS2_LL_DECL::IsEmpty() const { return (fFirst == NULL); } // LinkedListOf::NumberOfElements // // Compute the number of elements (expensive) CS2_LL_TEMP inline uint32_t CS2_LL_DECL::NumberOfElements() const { uint32_t count = 0; typename CS2_LL_ITEM *p = fFirst; while (p) { count++; p = p->Next(); } return count; } CS2_LL_TEMP inline CS2_LL_ITEM::LinkedListItem() : fNext(NULL) { } CS2_LL_TEMP inline CS2_LL_ITEM::LinkedListItem (const ADataType &data, typename CS2_LL_ITEM *next) : fData(data) { fNext = (typename CS2_LL_ITEM *) next; } CS2_LL_TEMP inline ADataType &CS2_LL_ITEM::Data() { return fData; } CS2_LL_TEMP inline void CS2_LL_ITEM::SetData (const ADataType &data) { fData = data; } CS2_LL_TEMP inline typename CS2_LL_ITEM *CS2_LL_ITEM::Next() const { return fNext; } CS2_LL_TEMP inline void CS2_LL_ITEM::SetNext (typename CS2_LL_ITEM *next) { fNext = (typename CS2_LL_ITEM *) next; } CS2_LL_TEMP inline CS2_LLC_DECL::Cursor (CS2_LL_DECL &ll) : fList(ll), fItem(ll.fFirst) { } CS2_LL_TEMP inline CS2_LLC_DECL::Cursor (const typename CS2_LLC_DECL &c) : fList(c.fList), fItem(c.fItem) { } // LinkedListOf::Cursor::operator== // CS2_LL_TEMP inline int CS2_LLC_DECL::operator== (const typename CS2_LLC_DECL &c) const { return (&fList == &(c.fList)) && (fItem == c.fItem); } // LinkedListOf::Cursor::SetTo... // // Set the cursor position - return flag indicating if position is valid CS2_LL_TEMP inline bool CS2_LLC_DECL::SetToFirst() { fItem = fList.fFirst; return (fItem != NULL); } CS2_LL_TEMP inline bool CS2_LLC_DECL::SetToNext() { fItem = fItem->Next(); return (fItem != NULL); } CS2_LL_TEMP inline bool CS2_LLC_DECL::SetToLast() { fItem = fList.fFirst; if (fItem == NULL) return false; while (fItem->Next()) fItem = fItem->Next(); return true; } // LinkedListOf::Cursor::Valid // // Determine if the cursor points at a valid position CS2_LL_TEMP inline bool CS2_LLC_DECL::Valid() const { return (fItem != NULL); } // LinkedListOf::Cursor::IsLast // // Check if a cursor points to the last position (must be valid) CS2_LL_TEMP inline bool CS2_LLC_DECL::IsLast() const { CS2Assert (fItem != NULL, ("Expecting valid cursor")); return (fItem->Next() == NULL); } // LinkedListOf::Cursor::Data // // Get/set the data at the current position in the list. CS2_LL_TEMP inline ADataType &CS2_LLC_DECL::Data() const { return fItem->Data(); } CS2_LL_TEMP inline ADataType &CS2_LLC_DECL::operator*() { return fItem->Data(); } CS2_LL_TEMP inline ADataType *CS2_LLC_DECL::operator->() { return &(fItem->Data()); } CS2_LL_TEMP inline void CS2_LLC_DECL::SetData (const ADataType &data) { fItem->SetData (data); } // LinkedListOf::Cursor::AddAfter // // Add an item to the list after the current position. CS2_LL_TEMP inline void CS2_LLC_DECL::AddAfter (const ADataType &data) { typename CS2_LL_ITEM *newp; CS2Assert (fItem != NULL, ("Expecting valid cursor")); newp = (LinkedListItem *)fList.allocator().allocate(sizeof(LinkedListItem)); newp = new (newp) typename CS2_LL_ITEM (data, fItem->Next()); fItem->SetNext (newp); } // LinkedListOf::Cursor::DeleteAfter // // Delete the item on the list after the current position. CS2_LL_TEMP inline void CS2_LLC_DECL::DeleteAfter() { CS2Assert (fItem != NULL, ("Expecting valid cursor")); typename CS2_LL_ITEM *deletep = fItem->Next(); if (deletep) { fItem->SetNext(deletep->Next()); deletep->~LinkedListItem(); fList.allocator().deallocate(deletep, sizeof(LinkedListItem)); } } CS2_LL_TEMP inline typename CS2_LL_ITEM *CS2_LLC_DECL::Next () const { CS2Assert (fItem != NULL, ("Expecting valid cursor")); return fItem->Next(); } CS2_LL_TEMP inline CS2_LL_DECL::LinkedListOf (const CS2_LL_DECL &ll) : Allocator(ll.allocator()), fFirst(NULL) { *this = ll; } CS2_LL_TEMP inline CS2_LL_DECL &CS2_LL_DECL::operator= (const CS2_LL_DECL &ll) { MakeEmpty(); if (ll.fFirst) { typename CS2_LL_ITEM *p, *thisp, *nextp; thisp = (LinkedListItem *) Allocator::allocate(sizeof(LinkedListItem)); thisp = fFirst = new (thisp) typename CS2_LL_ITEM (ll.fFirst->Data(), NULL); p = ll.fFirst->Next(); while (p) { nextp = (LinkedListItem *)Allocator::allocate(sizeof(LinkedListItem)); nextp = new (nextp) typename CS2_LL_ITEM (p->Data(), NULL); thisp->SetNext (nextp); thisp = nextp; p = p->Next(); } } else { fFirst = NULL; } return *this; } // LinkedListOf::Append // // Append the given list at the end of this list CS2_LL_TEMP inline void CS2_LL_DECL::Append (const CS2_LL_DECL &inList) { if (inList.IsEmpty()) return; typename CS2_LLC_DECL thisc(*this), inc((CS2_LL_DECL &)inList); inc.SetToFirst(); if (IsEmpty()) { Add (*inc); inc.SetToNext(); } thisc.SetToLast(); while (inc.Valid()) { thisc.AddAfter (*inc); thisc.SetToNext(); inc.SetToNext(); } } // LinkedListOf::MemoryUsage // // Return the number of bytes of memory used by the list CS2_LL_TEMP inline unsigned long CS2_LL_DECL::MemoryUsage() const { typename CS2_LL_ITEM *p = fFirst; unsigned long mem = sizeof (CS2_LL_DECL); while (p) { mem += sizeof (typename CS2_LL_ITEM); p = p->Next(); } return mem; } template <class ADataType, class Allocator> class QueueOf : public LinkedListOf<ADataType, Allocator> { public: QueueOf (const Allocator &a = Allocator()) : LinkedListOf<ADataType, Allocator>(a) {} using LinkedListOf<ADataType, Allocator>::Add; using LinkedListOf<ADataType, Allocator>::Remove; using LinkedListOf<ADataType, Allocator>::Head; void Push(const ADataType &data) { Add(data, true); } ADataType Pop() { ADataType head = *(Head()); Remove(); return head; } }; template <class ADataType, class Allocator> class StackOf : public QueueOf<ADataType, Allocator> { public: StackOf (const Allocator &a = Allocator()) : QueueOf<ADataType, Allocator>(a) {} using LinkedListOf<ADataType, Allocator>::Add; void Push(const ADataType &data) { Add(data); } }; } #undef CS2_LLC_DECL #undef CS2_LL_TEMPARGS #undef CS2_LL_TEMP #undef CS2_LL_DECL #ifdef CS2_ALLOCINFO #undef allocate #undef deallocate #undef reallocate #endif #endif // CS2_LLISTOF_H