/* * Copyright 2014 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef SkTInternalSList_DEFINED #define SkTInternalSList_DEFINED #include "SkTInternalLList.h" // for SkPtrWrapper /** * This macro creates the methods required by the SkTInternalSList class. * It should be instantiated in the private block of the class you want to put * into an SkTInternalSList. * For most use cases you should use SK_DECLARE_INTERNAL_SLIST_INTERFACE and not * this macro. If you care about the field name, or want to re-use an existing * field, then you can use this macro to declare the methods pointing to a * specific field. * Unlike SK_DECLARE_INTERNAL_SLIST_INTERFACE this does not declare the field * itself. * It also makes SkTInternalSList a friend to give it access to the * methods. */ #define SK_DECLARE_INTERNAL_SLIST_ADAPTER(ClassName, field) \ ClassName* getSListNext() { \ return this->field; \ } \ void setSListNext(ClassName* next) { \ this->field = next; \ } \ friend class SkTInternalSList /** * This macro declares an fSListNext that auto initializes to NULL and then * uses SK_DECLARE_INTERNAL_SLIST_ADAPTER to add the methods needed by * SkTInternalSList. * It should be instantiated in the private block of the class you want to put * into an SkTInternalSList. */ #define SK_DECLARE_INTERNAL_SLIST_INTERFACE(ClassName) \ SK_DECLARE_INTERNAL_SLIST_ADAPTER(ClassName, fSListNext); \ SkPtrWrapper fSListNext /** * An implementation of an intrusive singly linked list. * The type T must have a methods getSListNext and setSListNext that are visible * to the list. The easiest way to do this is with * SK_DECLARE_INTERNAL_SLIST_INTERFACE. * The list does not maintain ownership of any of its elements, or ever delete * them. */ template class SkTInternalSList { public: SkTInternalSList() : fHead(NULL), fCount(0) {} /** * Push an item onto the head of the list. * This method is *not* thread safe. */ void push(T* entry) { SkASSERT(entry->getSListNext() == NULL); entry->setSListNext(fHead); fHead = entry; ++fCount; } /** * Takes all the items from another list and pushes them into this list. * No ordering guarantees are made, the other list will be emptied. * This method is *not* thread safe. */ void pushAll(SkTInternalSList* other) { if (this->isEmpty()) { this->swap(other); return; } while (!other->isEmpty()) { this->push(other->pop()); } } /** * Pop an item from the head of the list. * Returns NULL if the list is empty. * This method is *not* thread safe. */ T* pop() { if (NULL == fHead) { return NULL; } T* result = fHead; fHead = result->getSListNext(); result->setSListNext(NULL); --fCount; return result; } T* head() const { return fHead; } /** * Returns true if the list has no elements. */ bool isEmpty() const { return NULL == fHead; } /** * Swaps the contents of this list with another one. * This method is *not* thread safe. */ void swap(SkTInternalSList* other) { SkTSwap(fHead, other->fHead); SkTSwap(fCount, other->fCount); } /** * Returns the count of elements in the list. */ int getCount() const { return fCount; } private: T* fHead; int fCount; }; #endif