#ifndef _QUEUE_HPP_
#define _QUEUE_HPP_
//                                        Ruler
//       1         2         3         4         5         6         7         8
//345678901234567890123456789012345678901234567890123456789012345678901234567890

    /********************************************************************/
    /*                                                                  */
    /*   The standard layout.                                           */
    /*                                                                  */
    /*   The standard layout for 'hpp' files for this code is as        */
    /*   follows:                                                       */
    /*                                                                  */
    /*      1. Include files.                                           */
    /*      2. Constants exported from the class.                       */
    /*      3. Data structures exported from the class.                 */
	/*      4. Forward references to other data structures.             */
	/*      5. Class specifications (including inline functions).       */
    /*      6. Additional large inline functions.                       */
    /*                                                                  */
    /*   Any portion that is not required is simply omitted.            */
    /*                                                                  */
    /********************************************************************/

#include "Global.hpp"

#include "Common.hpp"
#include "Lock.hpp"
#include "Vector.hpp"

    /********************************************************************/
    /*                                                                  */
    /*   Constants exported from the class.                             */
    /*                                                                  */
    /*   The queue constants specify the initial size of the queue.     */
    /*                                                                  */
    /********************************************************************/

CONST SBIT32 QueueSize				  = 1024;

    /********************************************************************/
    /*                                                                  */
    /*   Queues and queue management.                                   */
    /*                                                                  */
    /*   This class provides general purpose queues along with some     */
    /*   basic management.  The queues are optimized for very high      */
    /*   performance on SMP systems.  Whenever possible multiple        */
    /*   items should added and removed from a queue at the same time.  */
    /*                                                                  */
    /********************************************************************/

template <class TYPE,class LOCK=NO_LOCK> class QUEUE : public COMMON, public LOCK
    {
        //
        //   Private data.
        //
        SBIT32						  MaxSize;

		BOOLEAN						  Align;
        SBIT32						  Mask;

        SBIT32						  Back;
        SBIT32						  Front;

        VECTOR<TYPE>                  Queue;

    public:
        //
        //   Public functions.
        //
        QUEUE( SBIT32 NewMaxSize = QueueSize,BOOLEAN NewAlign = True );

        BOOLEAN MultiplePopBackOfQueue
            ( 
            SBIT32					  Requested, 
            TYPE					  Data[], 
            SBIT32					  *Size 
            );

        BOOLEAN MultiplePopFrontOfQueue
            ( 
            SBIT32					  Requested, 
            TYPE					  Data[], 
            SBIT32					  *Size 
            );

        VOID MultiplePushBackOfQueue
            ( 
            CONST TYPE				  Data[], 
            CONST SBIT32			  Size 
            );

        VOID MultiplePushFrontOfQueue
            ( 
            CONST TYPE				  Data[], 
            CONST SBIT32			  Size 
            );

        BOOLEAN PeekBackOfQueue( TYPE *Data );

        BOOLEAN PeekFrontOfQueue( TYPE *Data );

        BOOLEAN PopBackOfQueue( TYPE *Data );

        BOOLEAN PopFrontOfQueue( TYPE *Data );

        VOID PushBackOfQueue( CONST TYPE & Data );

        VOID PushFrontOfQueue( CONST TYPE & Data );

		SBIT32 SizeOfQueue( VOID );

        ~QUEUE( VOID );

		//
		//   Public inline functions.
		//
        INLINE BOOLEAN MultiplePopQueue
				( 
				SBIT32				  Requested, 
				TYPE				  Data[], 
				SBIT32				  *Size 
				)
			{ return MultiplePopFrontOfQueue( Requested,Data,Size ); }

        INLINE VOID MultiplePushQueue
				( 
				CONST TYPE			  Data[], 
				CONST SBIT32		  Size 
				)
			{ MultiplePushBackOfQueue( Data,Size ); }

        INLINE BOOLEAN PeekQueue( TYPE *Data )
			{ return PeekFrontOfQueue( Data ); }

        INLINE BOOLEAN PopQueue( TYPE *Data )
			{ return PopFrontOfQueue( Data ); }

        INLINE VOID PushQueue( CONST TYPE & Data )
			{ PushBackOfQueue( Data ); }

	private:
		//
		//   Private functions.
		//
		VOID ExpandQueue( VOID );

        //
        //   Disabled operations.
        //
        QUEUE( CONST QUEUE & Copy );

        VOID operator=( CONST QUEUE & Copy );
    };

    /********************************************************************/
    /*                                                                  */
    /*   Class constructor.                                             */
    /*                                                                  */
    /*   Create a new queue and prepare it for use.  This call is       */
    /*   not thread safe and should only be made in a single thread     */
    /*   environment.                                                   */
    /*                                                                  */
    /********************************************************************/

template <class TYPE,class LOCK> QUEUE<TYPE,LOCK>::QUEUE
		( 
		SBIT32						  NewMaxSize,
		BOOLEAN						  NewAlign 
		) : 
		//
		//   Call the constructors for the contained classes.
		//
		Queue( NewMaxSize,1,CacheLineSize )
    {
#ifdef DEBUGGING
    if ( NewMaxSize > 0 )
        {
#endif
		//
		//   Setup the control information.
		//
        MaxSize = NewMaxSize;

		Align = NewAlign;
        Mask = 0x7fffffff;

		//
		//   Setup the queue so it is empty.
		//
        Back = 0;
        Front = 0;

		//
		//   Compute the alignment mask.
		//
		if 
				(
				((sizeof(TYPE) > 0) && (sizeof(TYPE) <= CacheLineSize))
					&&
				(PowerOfTwo( sizeof(TYPE) ))
				)
			{ Mask = ((CacheLineSize / sizeof(TYPE))-1); }
#ifdef DEBUGGING
        }
    else
        { Failure( "Size in constructor for QUEUE" ); }
#endif
    }

    /********************************************************************/
    /*                                                                  */
    /*   Expand a queue.                                                */
    /*                                                                  */
    /*   When a queue becomes full we need to expand it and to copy     */
    /*   the tail end of the queue into the correct place.              */
    /*                                                                  */
    /********************************************************************/

template <class TYPE,class LOCK> VOID QUEUE<TYPE,LOCK>::ExpandQueue( VOID )
    {
    REGISTER SBIT32 Count;
    REGISTER SBIT32 NewSize = (MaxSize * ExpandStore);

	//
	//   Expand the queue (it will be at least doubled).
	//
    Queue.Resize( NewSize );

	//
	//   Copy the tail end of the queue to the correct
	//   place in the expanded queue.
	//
    for ( Count = 0;Count < Back;Count ++ )
        { Queue[ (MaxSize + Count) ] = Queue[ Count ]; }

	//
	//   Update the control information.
	//
    Back += MaxSize;
    MaxSize = NewSize;
    }

    /********************************************************************/
    /*                                                                  */
    /*   Pop multiple items from the back of the queue.                 */
    /*                                                                  */
    /*   We remove multiple items from a queue and check to make sure   */
    /*   that the queue has not wrapped.                                */
    /*                                                                  */
    /********************************************************************/

template <class TYPE,class LOCK> BOOLEAN QUEUE<TYPE,LOCK>::MultiplePopBackOfQueue
        ( 
        SBIT32                        Requested, 
        TYPE                          Data[], 
        SBIT32                        *Size 
        )
    {
    REGISTER BOOLEAN Result;

	//
	//   Claim an exclusive lock (if enabled).
	//
    ClaimExclusiveLock();

    //
    //   When running on SMP hardware it is very important 
	//   to prevent multiple CPU fighting over the same memory.  
	//   Most systems prevent multiple CPUs accessing a cache  
	//   line at the same time.  Here we modify the request  
	//   to pop exactly the correct number of items to leave  
	//   us on a cache line boundary. 
    //
    if ( Align )
        {
        REGISTER SBIT32 Spare = (Back & Mask);

		if ( Requested > Spare )
			{
			Requested -= Spare;
			Requested &= ~Mask;
			Requested += Spare;
			}
        }

	//
	//   If there is enough elements in the current queue
	//   to extract without wrapping then just do a straight 
	//   copy.
	//
    if 
            ( 
            ((Front <= Back) && (Front <= (Back - Requested))) 
                || 
            ((Front > Back) && ((Back - Requested) >= 0)) 
            )
        {
        REGISTER SBIT32 Count;

        //
        //   We have verified that it is safe to remove all  
        //   the requested elements with a straight copy.
        //
        for ( Count = 0;Count < Requested;Count ++ )
            { Data[ Count ] = Queue[ -- Back ]; }

        (*Size) = Requested;

		Result = True;
		}
    else
        {
        REGISTER SBIT32 Count;

        //
        //   It is not safe to remove all the elements from 
        //   the array.  Hence, I must remove them one at a 
		//   time.  This is tedious but should only happen 
		//   occasionally.
        //
        for ( Count=0,(*Size)=0;Count < Requested;Count ++,(*Size) ++ )
            {
            if ( Front != Back )
                {
                //
                //   We have found an element so return it 
				//   to the caller.  However, lets we need  
				//   to be careful about wrapping.
                //
				 if ( Back <= 0 )
					{ Back = MaxSize; }

                Data[ Count ] = Queue[ -- Back ];
                }
            else
                {
                //
                //  We are out of queue elements so lets exit.  
				//  However, we only return 'False' if we didn't 
				//  find any elements at all.
                //
				Result = (Count != 0);

                break;
                }
            }
        }

	//
	//   Release any lock we claimed earlier.
	//
    ReleaseExclusiveLock();

    return Result;
    }

    /********************************************************************/
    /*                                                                  */
    /*   Pop multiple items from the front of the queue.                */
    /*                                                                  */
    /*   We remove multiple items from a queue and check to make sure   */
    /*   that the queue has not wrapped.                                */
    /*                                                                  */
    /********************************************************************/

template <class TYPE,class LOCK> BOOLEAN QUEUE<TYPE,LOCK>::MultiplePopFrontOfQueue
        ( 
        SBIT32                        Requested, 
        TYPE                          Data[], 
        SBIT32                        *Size 
        )
    {
    REGISTER BOOLEAN Result;

	//
	//   Claim an exclusive lock (if enabled).
	//
    ClaimExclusiveLock();

    //
    //   When running on SMP hardware it is very important 
	//   to prevent multiple CPU fighting over the same memory.  
	//   Most systems prevent multiple CPUs accessing cache  
	//   lines at the same time.  Here we modify the request  
	//   to access exactly the correct number of items to leave  
	//   us on a cache line boundary. 
    //
    if ( Align )
        {
        REGISTER SBIT32 Spare = ((Mask + 1) - (Front & Mask));

		if ( Requested > Spare )
			{
			Requested -= Spare;
			Requested &= ~Mask;
			Requested += Spare;
			}
        }

	//
	//   If there is enough elements in the current queue
	//   to extract without wrapping then just do a straight 
	//   copy.
	//
    if 
            ( 
            ((Front <= Back) && ((Front + Requested) <= Back)) 
                || 
            ((Front > Back) && ((Front + Requested) < MaxSize)) 
            )
        {
        REGISTER SBIT32 Count;

        //
        //   We have verified that it is safe to remove all  
        //   the requested elements with a straight copy.
        //
        for ( Count = 0;Count < Requested;Count ++ )
            { Data[ Count ] = Queue[ Front ++ ]; }

        (*Size) = Requested;

		Result = True;
		}
    else
        {
        REGISTER SBIT32 Count;
        //
        //   It is not safe to remove all the elements from 
        //   the array.  Hence, I must remove them one at a 
		//   time.  This is tedious but should only happen 
		//   occasionally.
        //
        for ( Count=0,(*Size)=0;Count < Requested;Count ++,(*Size) ++ )
            {
            if ( Front != Back )
                {
                //
                //   We have found an element so return it 
				//   to the caller.  However, lets we need  
				//   to be careful about wrapping.
                //
                Data[ Count ] = Queue[ Front ++ ];

                if ( Front >= MaxSize )
                    { Front = 0; }
                }
            else
                {
                //
                //  We are out of queue elements so lets exit.  
				//  However, we only return 'False' if we didn't 
				//  find any elements at all.
                //
				Result = (Count != 0);

                break;
                }
            }
        }

	//
	//   Release any lock we claimed earlier.
	//
    ReleaseExclusiveLock();

    return Result;
    }

    /********************************************************************/
    /*                                                                  */
    /*   Push multiple items onto the back of the queue.                */
    /*                                                                  */
    /*   We add multiple items to a queue and check to make sure that   */
    /*   the queue has not overflowed.  If the queue has overflowed     */
    /*   we double its size.                                            */
    /*                                                                  */
    /********************************************************************/

template <class TYPE,class LOCK> VOID QUEUE<TYPE,LOCK>::MultiplePushBackOfQueue
        ( 
        CONST TYPE					  Data[],
        CONST SBIT32				  Size 
        )
    {
	//
	//   Claim an exclusive lock (if enabled).
	//
    ClaimExclusiveLock();

	//
	//   If there is enough space in the current queue
	//   for the new elements without wrapping then
	//   just do a straight copy.
	//
    if 
            ( 
            ((Front <= Back) && ((Back + Size) < MaxSize)) 
                || 
            ((Front > Back) && (Front > (Back + Size))) 
            )
        {
        REGISTER SBIT32 Count;

        //
        //   We have verified that it is safe to copy 
        //   all the new elements on to the end of the 
		//   array.  So lets do it and then we can exit. 
        //
        for ( Count = 0;Count < Size;Count ++ )
            { Queue[ Back ++ ] = Data[ Count ]; }
        }
    else
        {
        REGISTER SBIT32 Count;

        //
        //   It is not safe to add the new elements to 
		//   the end of the array so add them one at a 
		//   time.  This is tedious but should only happen 
		//   occasionally.
        //
        for ( Count=0;Count < Size;Count ++ )
            {
            //
            //   Add element to the queue.  If necessary  
            //   wrap round to the front of the array.
            //
            Queue[ Back ++ ] = Data[ Count ];

             if ( Back >= MaxSize )
                { Back = 0; }

            //
            //   Verify that the queue is not full.  If 
			//   it is full then double its size and  
			//   copy wrapped data to the correct position 
			//   in the new array.
            //
            if ( Front == Back )
				{ ExpandQueue(); }
            }
        }

	//
	//   Release any lock we claimed earlier.
	//
    ReleaseExclusiveLock();
    }

    /********************************************************************/
    /*                                                                  */
    /*   Push multiple items onto the front of the queue.               */
    /*                                                                  */
    /*   We add multiple items to a queue and check to make sure that   */
    /*   the queue has not overflowed.  If the queue has overflowed     */
    /*   we double its size.                                            */
    /*                                                                  */
    /********************************************************************/

template <class TYPE,class LOCK> VOID QUEUE<TYPE,LOCK>::MultiplePushFrontOfQueue
        ( 
        CONST TYPE					  Data[],
        CONST SBIT32				  Size 
        )
    {
	//
	//   Claim an exclusive lock (if enabled).
	//
    ClaimExclusiveLock();

	//
	//   If there is enough space in the current queue
	//   for the new elements without wrapping then
	//   just do a straight copy.
	//
    if 
            ( 
            ((Front <= Back) && ((Front - Size) >= 0)) 
                || 
            ((Front > Back) && ((Front - Size) > Back)) 
            )
        {
        REGISTER SBIT32 Count;

        //
        //   We have verified that it is safe to copy 
        //   all the new elements on to the end of the 
		//   array.  So lets do it and then we can exit. 
        //
        for ( Count = 0;Count < Size;Count ++ )
            { Queue[ -- Front ] = Data[ Count ]; }
        }
    else
        {
        REGISTER SBIT32 Count;

        //
        //   It is not safe to add the new elements to 
		//   the end of the array so add them one at a 
		//   time.  This is tedious but should only happen 
		//   occasionally.
        //
        for ( Count = 0;Count < Size;Count ++ )
            {
            //
            //   Add element to the queue.  If necessary  
            //   wrap round to the back of the array.
            //
			 if ( Front <= 0 )
				{ Front = MaxSize; }

			Queue[ -- Front ] = Data[ Count ];

            //
            //   Verify that the queue is not full.  If 
			//   it is full then double its size and  
			//   copy wrapped data to the correct position 
			//   in the new array.
            //
            if ( Front == Back )
				{ ExpandQueue(); }
            }
        }

	//
	//   Release any lock we claimed earlier.
	//
    ReleaseExclusiveLock();
    }

    /********************************************************************/
    /*                                                                  */
    /*   Peek the back of the queue.                                    */
    /*                                                                  */
    /*   We return the end of the queue but check to make sure          */
    /*   that the queue is not empty.                                   */
    /*                                                                  */
    /********************************************************************/

template <class TYPE,class LOCK> BOOLEAN QUEUE<TYPE,LOCK>::PeekBackOfQueue
		( 
		TYPE						  *Data 
		)
    {
    REGISTER BOOLEAN Result;

	//
	//   Claim an exclusive lock (if enabled).
	//
    ClaimExclusiveLock();

	//
	//   If the queue contains at least one element then
	//   return a copy of the last element.
	//
    if ( Front != Back )
		{
		//
		//   The 'Back' index points at the next free cell.
		//   So the last element is 'Back - 1'.  However,
		//   when 'Back' is zero we need to wrap.
		//
		if ( Back > 0 )
			{ (*Data) = Queue[ (Back - 1) ]; }
		else
			{ (*Data) = Queue[ (MaxSize - 1) ]; }
	
		Result = True;
		}
    else
        { Result = False; }

	//
	//   Release any lock we claimed earlier.
	//
    ReleaseExclusiveLock();

    return Result;
    }

    /********************************************************************/
    /*                                                                  */
    /*   Peek the front of the queue.                                   */
    /*                                                                  */
    /*   We return the front of the queue but check to make sure        */
    /*   that the queue is not empty.                                   */
    /*                                                                  */
    /********************************************************************/

template <class TYPE,class LOCK> BOOLEAN QUEUE<TYPE,LOCK>::PeekFrontOfQueue
		( 
		TYPE						  *Data 
		)
    {
    REGISTER BOOLEAN Result;

	//
	//   Claim an exclusive lock (if enabled).
	//
    ClaimExclusiveLock();

	//
	//   If the queue contains at least one element then
	//   return a copy of the first element.
	//
    if ( Front != Back )
		{ 
		(*Data) = Queue[ Front ];
		
		Result = True;
		}
    else
        { Result = False; }

	//
	//   Release any lock we claimed earlier.
	//
    ReleaseExclusiveLock();

    return Result;
    }

    /********************************************************************/
    /*                                                                  */
    /*   Pop an item from the back of the queue.                        */
    /*                                                                  */
    /*   We remove a single item from a queue and check to make sure    */
    /*   that the queue has not wrapped.                                */
    /*                                                                  */
    /********************************************************************/

template <class TYPE,class LOCK> BOOLEAN QUEUE<TYPE,LOCK>::PopBackOfQueue
		( 
		TYPE						  *Data 
		)
    {
    REGISTER BOOLEAN Result;

	//
	//   Claim an exclusive lock (if enabled).
	//
    ClaimExclusiveLock();

	//
	//   We make sure the queue is not empty.
	//
    if ( Front != Back )
        {
        //
        //   We have found an element so return it to 
		//   the caller.  If we walk off the end of the 
		//   queue then wrap to the other end.
        //
         if ( Back <= 0 )
            { Back = MaxSize; }

       (*Data) = Queue[ -- Back ];

		Result = True;
        }
    else
        { Result = False; }

	//
	//   Release any lock we claimed earlier.
	//
    ReleaseExclusiveLock();

    return Result;
    }

    /********************************************************************/
    /*                                                                  */
    /*   Pop an item from the front of the queue.                       */
    /*                                                                  */
    /*   We remove a single item from a queue and check to make sure    */
    /*   that the queue has not wrapped.                                */
    /*                                                                  */
    /********************************************************************/

template <class TYPE,class LOCK> BOOLEAN QUEUE<TYPE,LOCK>::PopFrontOfQueue
		( 
		TYPE						  *Data 
		)
    {
    REGISTER BOOLEAN Result;

	//
	//   Claim an exclusive lock (if enabled).
	//
    ClaimExclusiveLock();

	//
	//   We make sure the queue is not empty.
	//
    if ( Front != Back )
        {
        //
        //   We have found an element so return it to 
		//   the caller.  If we walk off the end of the 
		//   queue then wrap to the other end.
        //
        (*Data) = Queue[ Front ++ ];

        if ( Front >= MaxSize )
            { Front = 0; }

		Result = True;
        }
    else
        { Result = False; }

	//
	//   Release any lock we claimed earlier.
	//
    ReleaseExclusiveLock();

    return Result;
    }

    /********************************************************************/
    /*                                                                  */
    /*   Push an item onto the back of the queue.                       */
    /*                                                                  */
    /*   We add a single item to a queue and check to make sure that    */
    /*   the queue has not overflowed.  If the queue has overflowed     */
    /*   we double its size.                                            */
    /*                                                                  */
    /********************************************************************/

template <class TYPE,class LOCK> VOID QUEUE<TYPE,LOCK>::PushBackOfQueue
		( 
		CONST TYPE					  & Data 
		)
    {
	//
	//   Claim an exclisive lock (if enabled).
	//
    ClaimExclusiveLock();

    //
    //   Add element to the queue.  If necessary wrap round 
    //   to the front of the array.
    //
    Queue[ Back ++ ] = Data;

     if ( Back >= MaxSize )
        { Back = 0; }

    //
    //   Verify that the queue is not full.  If it is full then 
    //   double its size and copy wrapped data to the correct
    //   position in the new array.
    //
    if ( Front == Back )
		{ ExpandQueue(); }

	//
	//   Release any lock we claimed earlier.
	//
    ReleaseExclusiveLock();
    }

    /********************************************************************/
    /*                                                                  */
    /*   Push an item onto the front of the queue.                      */
    /*                                                                  */
    /*   We add a single item to a queue and check to make sure that    */
    /*   the queue has not overflowed.  If the queue has overflowed     */
    /*   we double its size.                                            */
    /*                                                                  */
    /********************************************************************/

template <class TYPE,class LOCK> VOID QUEUE<TYPE,LOCK>::PushFrontOfQueue
		( 
		CONST TYPE					  & Data 
		)
    {
	//
	//   Claim an exclisive lock (if enabled).
	//
    ClaimExclusiveLock();

    //
    //   Add element to the queue.  If necessary wrap round 
    //   to the back of the array.
    //
     if ( Front <= 0 )
        { Front = MaxSize; }

    Queue[ -- Front ] = Data;

    //
    //   Verify that the queue is not full.  If it is full then 
    //   double its size and copy wrapped data to the correct
    //   position in the new array.
    //
    if ( Front == Back )
		{ ExpandQueue(); }

	//
	//   Release any lock we claimed earlier.
	//
    ReleaseExclusiveLock();
    }

    /********************************************************************/
    /*                                                                  */
    /*   Calculate the size of the queue.                               */
    /*                                                                  */
    /*   Calculate the size of the queue and return it to the caller.   */
    /*   This is only used when the size is needed in all other cases   */
    /*   we just try to remove the elements in the queue.               */
    /*                                                                  */
    /********************************************************************/

template <class TYPE,class LOCK> SBIT32 QUEUE<TYPE,LOCK>::SizeOfQueue( VOID )
    {
    REGISTER SBIT32 Size;

	//
	//   Claim a shared lock (if enabled).
	//
    ClaimSharedLock();

	//
	//   Compute the size of the queue.
	//
	Size = (Back - Front);

	if ( Size < 0 )
		{ Size += MaxSize; }

	//
	//   Release any lock we claimed earlier.
	//
    ReleaseSharedLock();

    return Size;
    }

    /********************************************************************/
    /*                                                                  */
    /*   Class destructor.                                              */
    /*                                                                  */
    /*   Destory a queue.  This call is not thread safe and should      */
    /*   only be made in a single thread environment.                   */
    /*                                                                  */
    /********************************************************************/

template <class TYPE,class LOCK> QUEUE<TYPE,LOCK>::~QUEUE( VOID )
    { /* void */ }
#endif