/*++

Microsoft Windows NT RPC Name Service
Copyright (c) 1995 Microsoft Corporation

Module Name:

    linklist.hxx

Abstract:

	This module contains definitions of class CLinkList, and templates derived
	from it for type safety and multi-threading safety.
	
Author:

    Satish Thatte (SatishT) 08/16/95  Created all the code below except where
									  otherwise indicated.

--*/



#ifndef __LINKLIST_HXX_
#define __LINKLIST_HXX_

#include <abstract.hxx>
#include <util.hxx>

/* the type of comparison function used in CLinkList::find below */

typedef int (*TcompFun)(IDataItem*,IDataItem*);

/*++

Class Definition:

    CLinkList

Abstract:

    This is the linked list class.  It has a private Link class.
	Note that the links are garbage collected through reference
	counting, in order to accommodate iterators that share access
	to links.

--*/

extern char * LLname;

extern char * Lname;

class CLinkList 
{

  friend class CLinkListIterator;

  protected:

	  // a Link object should never be directly deleted, only released

	struct Link : public CRefCounted 
	{
		int fDeleteData;	// this flag is used to signal that the data is
							// expendable.  Typically, we don't delete the
							// data during self-destruct since it may be shared
		Link* next;
		IDataItem* data;

		Link(IDataItem* a, Link* n);
		virtual ~Link();
	};

	Link * pLnkLast, * pLnkFirst;

	long ulCount;

	static void releaseAll(Link*);	// protected utility
	
  public:

	CLinkList() 
	{ 
		pLnkFirst = pLnkLast = NULL; 
		ulCount = 0;
	}


	~CLinkList() 
	{ 
		releaseAll(pLnkFirst); 
	}
		
	ULONG size() 
	{ 
		return ulCount; 
	}
		
	// insert at the end

	void enque(IDataItem* x);

	// insert at the beginning

	void push(IDataItem* x);

	// insert at the end

	void insert(IDataItem* x)   
		{ enque(x); }

	IDataItem* pop();	// remove first item and return it

	/* remove the specified item and return it -- use pointer equality 
	   -- the return flag signifies success (TRUE) or failure (FALSE) */
	
	int remove(IDataItem *);	

	/* Unlike remove, this method is designed to use a client-supplied
	   comparison function instead of pointer equality.  The comparison
	   function is expected to behave like strcmp (returning <0 if less,
	   0 if equal and >0 if greater).
	*/

	IDataItem* find(IDataItem*,TcompFun);

	IDataItem* nth(long lOrdinal);

	void rotate(long lDegree);

	void catenate(CLinkList& ll);

	//  mark all links and all data for deletion
						
	void wipeOut();		// use with great caution!
	
};


/*++

Class Definition:

    CLinkListIterator

Abstract:

    An iterator class for traversing a CLinkList. 

--*/


class CLinkListIterator {
	
	CLinkList::Link* ptr;			// the current link
	CLinkList::Link* first;			// the first link
	
  public:
	  
	CLinkListIterator(CLinkList& source);

	~CLinkListIterator()
	{
		CLinkList::releaseAll(ptr);
	}

	IDataItem* next();	// advance the iterator and return next IDataItem

	int finished()
	{ 
		return ptr == NULL; 
	}

};



/*++

Template Class Definition:

    TCSafeLinkList

Abstract:

  The template TCSafeLinkList make it easy to produce "type safe" incarnations of
  the CLinkList classe, avoiding the use of casts in client code.  

  Note that Data must be a subtype of IDataItem.
  
--*/

template <class Data>
class TCSafeLinkList : private CLinkList
{

	friend class TCSafeLinkListIterator<Data>;

  public:

	inline
	void enque(Data* x) {
		CLinkList::enque(x);
	}

	inline
	void push(Data* x) {
		CLinkList::push(x);
	}

	inline
	void insert(Data* x) {
		enque(x);
	}

	inline
	void wipeOut() {
		CLinkList::wipeOut();
	}

	inline
	void rotate(long lDegree) {
		CLinkList::rotate(lDegree);
	}

	inline
	void catenate(TCSafeLinkList& ll) {
		CLinkList::catenate(ll);
	}

	inline
	Data* pop() {
		return (Data*) CLinkList::pop();
	}

	inline
	int remove(Data* x) {
		return CLinkList::remove(x);
	}

	inline
	Data* find(Data* pD,int comp(Data*,Data*)) {
		return (Data*) CLinkList::find(pD, (TcompFun) comp);
	}

	inline
	Data* nth(long lOrdinal) {
		return (Data*) CLinkList::nth(lOrdinal);
	}

	inline
	ULONG size() { return CLinkList::size(); }

};



/*++

Template Class Definition:

    TCSafeLinkListIterator

Abstract:

  The iterator for TCSafeLinkLists.
  
  The inheritance from TIIterator<Data> has the potential for considerable code bloat
  for this template because it forces the separate incarnation of every (virtual)
  function for every instance of the template in the code.  If code size become a 
  serious concern, this is one easy place to start the shrinkage, at some cost
  in flexibility.

  In practice, however, due to the small size of method implementations, the bloat
  was found to be insignificant (~1K in retail builds of the locator).

--*/

template <class Data>
class TCSafeLinkListIterator : public TIIterator<Data> {

	CLinkListIterator rep; 

  public:
	
	inline
	TCSafeLinkListIterator(TCSafeLinkList<Data>& l) : rep(l)
	{}

	inline
	Data* next() 
	{
		return (Data*) rep.next();
	}

	inline
	int finished() 
	{ 
		return rep.finished(); 
	}

};



/*++

Template Class Definition:

    TCGuardedLinkList

Abstract:

  The template TCGuardedLinkList makes it easy to produce thread safe incarnations of
  the CLinkList class.

  The guarded linked list below uses a simple CSharedCriticalSection. A more complex
  version using a CReadWriteSection is also possible -- see the guarded skip
  list template as an example.

  Even though the template uses CSharedCriticalSection, "sem.hxx" is not included
  here -- it must be included before the template can be instantiated.

  The reason why the TCSafeLinkList<Data> object representation used underneath
  is a member rather than a private base is that the constructor and destructor
  calls on the representation must themselves be guarded ..  Especially the 
  latter because it does iterative release of links underneath, whereas those
  links may be shared by several iterators still outstanding.  We guard the
  constructor basically "on principle", so any future changes to the representation
  will be transparent wrt thread safety.
  
--*/

template <class Data>
class TCGuardedLinkList {

	friend class TCGuardedLinkListIterator<Data>;

	/* A Linked List is not a search oriented structure.  It is therefore
	   hard to justify a CReadWriteSection to guard it */

	CSharedCriticalSection *csLock;	// shared with iterators

	TCSafeLinkList<Data> *psllRep;	// links shared with iterators

  public:

	/* For those operations which are subject to any kind of exceptions, 
	   we must use SEH to avoid deadlock */

	TCGuardedLinkList() {

		csLock = new CSharedCriticalSection;	// has ref count of 1 already

		csLock->Enter();

		__try {
			psllRep = new TCSafeLinkList<Data>();
		}

		__finally {
			csLock->Leave();
		}
	}


	~TCGuardedLinkList() {
		csLock->Enter();

		__try {
			delete psllRep;
		}

		__finally {
			csLock->Leave();
		}

		csLock->release();
	}
	
	// since the following does not chase pointers and just reads a mem location
	// and especially since it is inline, I don't see a reason to guard it

	ULONG size() { 
		return psllRep->size(); 
	}

	void enque(Data* x) {  
		csLock->Enter();

		__try {
			psllRep->enque(x);
		}

		__finally {
			csLock->Leave();
		}
	}

	void push(Data* x) {
		csLock->Enter();

		__try {
			psllRep->push(x);
		}

		__finally {
			csLock->Leave();
		}
	}

	void catenate(TCGuardedLinkList& ll) {
		csLock->Enter();

		__try {
			psllRep->catenate(*ll.psllRep);
		}

		__finally {
			csLock->Leave();
		}
	}

	void rotate(long lDegree) {
		csLock->Enter();

		__try {
			psllRep->rotate(lDegree);
		}

		__finally {
			csLock->Leave();
		}
	}

	void insert(Data* x) {
		enque(x);
	}

	/* wipeOut may cause faults due to delete calls on stored items */
	
	void wipeOut() {
		csLock->Enter();

		__try {
			psllRep->wipeOut();
		}

		__finally {
			csLock->Leave();
		}
	}

	Data* pop() {
		csLock->Enter();
		Data* result = psllRep->pop();
		csLock->Leave();
		return result;
	}

	int remove(Data* x) {
		csLock->Enter();
		int result = psllRep->remove(x);
		csLock->Leave();
		return result;
	}

	Data* find(Data* x,int comp(Data*,Data*)) {
		csLock->Enter();
		Data* result = (Data*) psllRep->find(x,comp);
		csLock->Leave();
		return result;
	}

	Data* nth(long lOrdinal) {
		csLock->Enter();
		Data* result = psllRep->nth(lOrdinal);
		csLock->Leave();
		return result;
	}
};


/*++

Template Class Definition:

    TCGuardedLinkListIterator

Abstract:

  The iterator for TCGuardedLinkLists.  It shares the CSharedCriticalSection
  object used to guard the list being iterated over.
  
--*/

template <class Data>
class TCGuardedLinkListIterator : public TIIterator<Data> {

	CSharedCriticalSection* csLock;					// shared
	TCSafeLinkListIterator<Data> *pSLLIiter;	// not shared

  public:
	
	TCGuardedLinkListIterator(TCGuardedLinkList<Data>& l) 
		: csLock(l.csLock)
	{

	/* Question: what if this csLock is released and self-destructs before
	   this constructor can hold it?

	   Answer: the guarded list must exist for it to be used as a parameter here,
	   and the list has a reference to the csLock so it cannot self-destruct.

	   However, a wipeOut call on the list concurrently with its use as a
	   parameter to this constructor is a possibility, hence the construction
	   process must be guarded.
	*/
	   
		csLock->hold();
		csLock->Enter();
		pSLLIiter = new TCSafeLinkListIterator<Data>(*(l.psllRep));
		csLock->Leave();
	}

	/* the destructor does not use the guard because if the iterator
	   is being destroyed even though it is shared, we are in big
	   trouble anyway -- it then ought to be reference counted!
	*/

	TCGuardedLinkListIterator::~TCGuardedLinkListIterator() {
		
		csLock->Enter();
		delete pSLLIiter;
		csLock->Leave();
		csLock->release();
	}


	Data* next() {
		Data* result;
		csLock->Enter();
		result = pSLLIiter->next();
		csLock->Leave();
		return result;
	}

	int finished() { 
		int result;
		csLock->Enter();
		result = pSLLIiter->finished();
		csLock->Leave();
		return result;
	}
};


#endif // __LINKLIST_HXX_