#ifndef _CACHE_HPP_
#define _CACHE_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 "Bucket.hpp"
#include "Find.hpp"
#include "NewPage.hpp"
#include "ThreadSafe.hpp"

    /********************************************************************/
    /*                                                                  */
    /*   The allocation cache.                                          */
    /*                                                                  */
    /*   The memory allocation cache consists of two stacks.  The       */
    /*   first stack contains preallocated elements which are           */
    /*   available for use.  The second stack contains elements         */
    /*   which have been deallocated and are about to be recycled.      */
    /*                                                                  */
    /********************************************************************/

class CACHE : public BUCKET
    {
		//
		//   Private data.
		//
		//   A cache sits on top of a bucket and shields 
		//   it from being swamped by calls.  The 'Active'
		//   flag is set when the cache is active.  The
		//   'Stealing' flag indicates that deallocated
		//   memory can be stolen and reallocated.  The
		//   'ThreadSafe' flag indicates that locking is
		//   required.
		//
		BOOLEAN						  Active;
		BOOLEAN						  Stealing;
#ifdef ENABLE_HEAP_STATISTICS

		//
		//   When we are collecting statistics we enable 
		//   the following variables.  The 'CacheFills' 
		//   count keeps track of the number of times
		//   the cache was filled from the bucket.  The
		//   'CacheFlushes' count keeps track of the 
		//   number of times the cache flushed deleted
		//   elements to the bucket.  The 'HighTide' count  
		//   keeps track the the highest number of outstanding
		//   allocations since the last "DeleteAll()'.  The 
		//   'HighWater' count keeps track of the maximum 
		//   number of allocations at any point.  The
		//   'InUse' counts the the current number of outstanding 
		//   allocations.
		//
		SBIT32						  CacheFills;
		SBIT32						  CacheFlushes;
		SBIT32						  HighTide;
		SBIT32						  HighWater;
		SBIT32						  InUse;
#endif

		//
		//   A cache can be controlled by the user.  The
		//   'CacheSize' controls the number of allocations
		//   that can be preallocated or queued for 
		//   deletion.  The 'NumberOfChildren' is a count
		//   of the number of caches that allocate space
		//   from this cache.
		//
		SBIT16						  CacheSize;
		SBIT16						  FillSize;
		SBIT16						  NumberOfChildren;

		//
		//   The cache consists of two stacks.  The
		//   'DeleteStack' contains elements that are 
		//   waiting to be deleted.  The 'NewStack' 
		//   contains elements waiting to be allocated.
		//
		ADDRESS_AND_PAGE			  *DeleteStack;
		VOID						  **NewStack;
		THREAD_SAFE					  *ThreadSafe;

		//
		//   The top of the deleted stack is kept in
		//   'TopOfDeleteStack' and the top of the new
		//   stack is kept in 'TopOfNewStack'.
		//
		SBIT32						  TopOfDeleteStack;
		SBIT32						  TopOfNewStack;

		//
		//   The 'Spinlock' is a fast lock employed to
		//   make the cache multi-threaded if 'ThreadSafe'
		//   is true.
		//   
		SPINLOCK					  Spinlock;

   public:
		//
		//   Public functions.
		//
		//   The cacahe is a subset of the full haep interface
		//   a certain calls simply bypass it.  However, there
		//   are a few additional functions for cases where the
		//   cache needs to be notified of significant heap
		//   events.
		//
        CACHE
			( 
			SBIT32					  NewAllocationSize,
			SBIT32					  NewCacheSize,
			SBIT32					  NewChunkSize,
			SBIT32					  NewPageSize,
			BOOLEAN					  NewStealing,
			THREAD_SAFE				  *NewThreadSafe
			);

		VOID *CreateDataPage( VOID );

		BOOLEAN Delete( VOID *Address,PAGE *Page,SBIT32 Version );

		VOID DeleteAll( VOID );

		BOOLEAN DeleteDataPage( VOID *Address );

		PAGE *FindChildPage( VOID *Address,FIND *Find );

		PAGE *FindParentPage( VOID *Address,FIND *Find );

		BOOLEAN MultipleNew
			( 
			SBIT32					  *Actual,
			VOID					  *Array[],
			SBIT32					  Requested 
			);

		VOID *New( VOID );

		VOID *New( BOOLEAN SubDivided,SBIT32 NewSize = NoSize );

		VOID ReleaseSpace( SBIT32 MaxActivePages );

		BOOLEAN SearchCache( VOID *Address );

		BOOLEAN Truncate( VOID );

		VOID UpdateCache
			( 
			HEAP					  *NewHeap,
			NEW_PAGE				  *NewPages,
			CACHE					  *NewParentCache,
			FIND					  *NewPrivateFind,
			FIND					  *NewPublicFind
			);

        ~CACHE( VOID );

		//
		//   Public inline functions.
		//
		//   A cache just like its parent bucket is closely
		//   coupled to various other classes and provides
		//   then is vital information.
		//
		INLINE VOID ClaimCacheLock( VOID )
			{
			if ( ThreadSafe -> ClaimActiveLock() )
				{ Spinlock.ClaimLock(); } 
			}

		INLINE SBIT16 GetCacheSize( VOID )
			{ return CacheSize; }

		INLINE SBIT32 GetNumberOfChildren( VOID )
			{ return NumberOfChildren; }

		INLINE VOID ReleaseCacheLock( VOID )
			{
			if ( ThreadSafe -> ClaimActiveLock() )
				{ Spinlock.ReleaseLock(); } 
			}

		INLINE BOOLEAN Walk( SEARCH_PAGE *Details,FIND *Find )
			{ return NewPage -> Walk( Details,Find ); }
#ifdef ENABLE_HEAP_STATISTICS

		//
		//   Cache statistics.
		//
		//   A cache has a collection statistics which it
		//   uses to measure how it is doing.  It is possible
		//   to get access to this data for the purpose of
		//   outputing various reports.
		//
		INLINE SBIT32 GetCacheFills( VOID )
			{ return CacheFills; }

		INLINE SBIT32 GetCacheFlushes( VOID )
			{ return CacheFlushes; }

		INLINE SBIT32 GetHighTide( VOID )
			{ return HighTide; }

		INLINE SBIT32 GetHighWater( VOID )
			{ return HighWater; }

		INLINE SBIT32 GetInUse( VOID )
			{ return InUse; }
#endif

	private:
		//
		//   Private functions.
		//
		//   A cache is initially inactive.  If at least one
		//   allocation request is made it will spring into
		//   life, allocate any space needed and prepare itself
		//   for use.
		//
		VOID CreateCacheStacks( VOID );
#ifdef ENABLE_HEAP_STATISTICS

		VOID ComputeHighWater( SBIT32 Size );
#endif

        //
        //   Disabled operations.
 		//
		//   All copy constructors and class assignment 
		//   operations are disabled.
        //
        CACHE( CONST CACHE & Copy );

        VOID operator=( CONST CACHE & Copy );
    };
#endif