Path: blob/master/samples/winrt/ImageManipulations/MediaExtensions/Common/LinkList.h
16345 views
//-----------------------------------------------------------------------------1// File: Linklist.h2// Desc: Linked list class.3//4// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF5// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO6// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A7// PARTICULAR PURPOSE.8//9// Copyright (C) Microsoft Corporation. All rights reserved.10//-----------------------------------------------------------------------------1112#pragma once1314// Notes:15//16// The List class template implements a simple double-linked list.17// It uses STL's copy semantics.1819// There are two versions of the Clear() method:20// Clear(void) clears the list w/out cleaning up the object.21// Clear(FN fn) takes a functor object that releases the objects, if they need cleanup.2223// The List class supports enumeration. Example of usage:24//25// List<T>::POSIITON pos = list.GetFrontPosition();26// while (pos != list.GetEndPosition())27// {28// T item;29// hr = list.GetItemPos(&item);30// pos = list.Next(pos);31// }3233// The ComPtrList class template derives from List<> and implements a list of COM pointers.3435template <class T>36struct NoOp37{38void operator()(T& t)39{40}41};4243template <class T>44class List45{46protected:4748// Nodes in the linked list49struct Node50{51Node *prev;52Node *next;53T item;5455Node() : prev(nullptr), next(nullptr)56{57}5859Node(T item) : prev(nullptr), next(nullptr)60{61this->item = item;62}6364T Item() const { return item; }65};6667public:6869// Object for enumerating the list.70class POSITION71{72friend class List<T>;7374public:75POSITION() : pNode(nullptr)76{77}7879bool operator==(const POSITION &p) const80{81return pNode == p.pNode;82}8384bool operator!=(const POSITION &p) const85{86return pNode != p.pNode;87}8889private:90const Node *pNode;9192POSITION(Node *p) : pNode(p)93{94}95};9697protected:98Node m_anchor; // Anchor node for the linked list.99DWORD m_count; // Number of items in the list.100101Node* Front() const102{103return m_anchor.next;104}105106Node* Back() const107{108return m_anchor.prev;109}110111virtual HRESULT InsertAfter(T item, Node *pBefore)112{113if (pBefore == nullptr)114{115return E_POINTER;116}117118Node *pNode = new Node(item);119if (pNode == nullptr)120{121return E_OUTOFMEMORY;122}123124Node *pAfter = pBefore->next;125126pBefore->next = pNode;127pAfter->prev = pNode;128129pNode->prev = pBefore;130pNode->next = pAfter;131132m_count++;133134return S_OK;135}136137virtual HRESULT GetItem(const Node *pNode, T* ppItem)138{139if (pNode == nullptr || ppItem == nullptr)140{141return E_POINTER;142}143144*ppItem = pNode->item;145return S_OK;146}147148// RemoveItem:149// Removes a node and optionally returns the item.150// ppItem can be nullptr.151virtual HRESULT RemoveItem(Node *pNode, T *ppItem)152{153if (pNode == nullptr)154{155return E_POINTER;156}157158assert(pNode != &m_anchor); // We should never try to remove the anchor node.159if (pNode == &m_anchor)160{161return E_INVALIDARG;162}163164165T item;166167// The next node's previous is this node's previous.168pNode->next->prev = pNode->prev;169170// The previous node's next is this node's next.171pNode->prev->next = pNode->next;172173item = pNode->item;174delete pNode;175176m_count--;177178if (ppItem)179{180*ppItem = item;181}182183return S_OK;184}185186public:187188List()189{190m_anchor.next = &m_anchor;191m_anchor.prev = &m_anchor;192193m_count = 0;194}195196virtual ~List()197{198Clear();199}200201// Insertion functions202HRESULT InsertBack(T item)203{204return InsertAfter(item, m_anchor.prev);205}206207208HRESULT InsertFront(T item)209{210return InsertAfter(item, &m_anchor);211}212213HRESULT InsertPos(POSITION pos, T item)214{215if (pos.pNode == nullptr)216{217return InsertBack(item);218}219220return InsertAfter(item, pos.pNode->prev);221}222223// RemoveBack: Removes the tail of the list and returns the value.224// ppItem can be nullptr if you don't want the item back. (But the method does not release the item.)225HRESULT RemoveBack(T *ppItem)226{227if (IsEmpty())228{229return E_FAIL;230}231else232{233return RemoveItem(Back(), ppItem);234}235}236237// RemoveFront: Removes the head of the list and returns the value.238// ppItem can be nullptr if you don't want the item back. (But the method does not release the item.)239HRESULT RemoveFront(T *ppItem)240{241if (IsEmpty())242{243return E_FAIL;244}245else246{247return RemoveItem(Front(), ppItem);248}249}250251// GetBack: Gets the tail item.252HRESULT GetBack(T *ppItem)253{254if (IsEmpty())255{256return E_FAIL;257}258else259{260return GetItem(Back(), ppItem);261}262}263264// GetFront: Gets the front item.265HRESULT GetFront(T *ppItem)266{267if (IsEmpty())268{269return E_FAIL;270}271else272{273return GetItem(Front(), ppItem);274}275}276277278// GetCount: Returns the number of items in the list.279DWORD GetCount() const { return m_count; }280281bool IsEmpty() const282{283return (GetCount() == 0);284}285286// Clear: Takes a functor object whose operator()287// frees the object on the list.288template <class FN>289void Clear(FN& clear_fn)290{291Node *n = m_anchor.next;292293// Delete the nodes294while (n != &m_anchor)295{296clear_fn(n->item);297298Node *tmp = n->next;299delete n;300n = tmp;301}302303// Reset the anchor to point at itself304m_anchor.next = &m_anchor;305m_anchor.prev = &m_anchor;306307m_count = 0;308}309310// Clear: Clears the list. (Does not delete or release the list items.)311virtual void Clear()312{313NoOp<T> clearOp;314Clear<>(clearOp);315}316317318// Enumerator functions319320POSITION FrontPosition()321{322if (IsEmpty())323{324return POSITION(nullptr);325}326else327{328return POSITION(Front());329}330}331332POSITION EndPosition() const333{334return POSITION();335}336337HRESULT GetItemPos(POSITION pos, T *ppItem)338{339if (pos.pNode)340{341return GetItem(pos.pNode, ppItem);342}343else344{345return E_FAIL;346}347}348349POSITION Next(const POSITION pos)350{351if (pos.pNode && (pos.pNode->next != &m_anchor))352{353return POSITION(pos.pNode->next);354}355else356{357return POSITION(nullptr);358}359}360361// Remove an item at a position.362// The item is returns in ppItem, unless ppItem is nullptr.363// NOTE: This method invalidates the POSITION object.364HRESULT Remove(POSITION& pos, T *ppItem)365{366if (pos.pNode)367{368// Remove const-ness temporarily...369Node *pNode = const_cast<Node*>(pos.pNode);370371pos = POSITION();372373return RemoveItem(pNode, ppItem);374}375else376{377return E_INVALIDARG;378}379}380381};382383384385// Typical functors for Clear method.386387// ComAutoRelease: Releases COM pointers.388// MemDelete: Deletes pointers to new'd memory.389390class ComAutoRelease391{392public:393void operator()(IUnknown *p)394{395if (p)396{397p->Release();398}399}400};401402class MemDelete403{404public:405void operator()(void *p)406{407if (p)408{409delete p;410}411}412};413414415// ComPtrList class416// Derived class that makes it safer to store COM pointers in the List<> class.417// It automatically AddRef's the pointers that are inserted onto the list418// (unless the insertion method fails).419//420// T must be a COM interface type.421// example: ComPtrList<IUnknown>422//423// NULLABLE: If true, client can insert nullptr pointers. This means GetItem can424// succeed but return a nullptr pointer. By default, the list does not allow nullptr425// pointers.426427template <class T, bool NULLABLE = FALSE>428class ComPtrList : public List<T*>429{430public:431432typedef T* Ptr;433434void Clear()435{436ComAutoRelease car;437List<Ptr>::Clear(car);438}439440~ComPtrList()441{442Clear();443}444445protected:446HRESULT InsertAfter(Ptr item, Node *pBefore)447{448// Do not allow nullptr item pointers unless NULLABLE is true.449if (item == nullptr && !NULLABLE)450{451return E_POINTER;452}453454if (item)455{456item->AddRef();457}458459HRESULT hr = List<Ptr>::InsertAfter(item, pBefore);460if (FAILED(hr) && item != nullptr)461{462item->Release();463}464return hr;465}466467HRESULT GetItem(const Node *pNode, Ptr* ppItem)468{469Ptr pItem = nullptr;470471// The base class gives us the pointer without AddRef'ing it.472// If we return the pointer to the caller, we must AddRef().473HRESULT hr = List<Ptr>::GetItem(pNode, &pItem);474if (SUCCEEDED(hr))475{476assert(pItem || NULLABLE);477if (pItem)478{479*ppItem = pItem;480(*ppItem)->AddRef();481}482}483return hr;484}485486HRESULT RemoveItem(Node *pNode, Ptr *ppItem)487{488// ppItem can be nullptr, but we need to get the489// item so that we can release it.490491// If ppItem is not nullptr, we will AddRef it on the way out.492493Ptr pItem = nullptr;494495HRESULT hr = List<Ptr>::RemoveItem(pNode, &pItem);496497if (SUCCEEDED(hr))498{499assert(pItem || NULLABLE);500if (ppItem && pItem)501{502*ppItem = pItem;503(*ppItem)->AddRef();504}505506if (pItem)507{508pItem->Release();509pItem = nullptr;510}511}512513return hr;514}515};516517518