//+-------------------------------------------------------------------------
//
//  Microsoft Windows
//
//  Copyright (C) Microsoft Corporation, 1994 - 1999
//
//  File:       hashtabl.hxx
//
//--------------------------------------------------------------------------

/*++

Module Name:

    hashtabl.hxx

Abstract:

    interface for a hash table indexed by UUID

Author:

    Jeff Roberts (jroberts)  9-Nov-1994

Revision History:

     9-Nov-1994     jroberts

        Created this module.

--*/

#ifndef  _HASHTABL_HXX_
#define  _HASHTABL_HXX_

#define NO_HASH ((unsigned)(-1))
#define INVALID_NODE ((UUID_HASH_TABLE_NODE *) (-1))


class UUID_HASH_TABLE_NODE
{
public:

    UUID_HASH_TABLE_NODE * pNext;
    UUID_HASH_TABLE_NODE * pPrev;

    RPC_UUID Uuid;

    UUID_HASH_TABLE_NODE(
        )
    {
#ifdef DEBUGRPC

        pNext = INVALID_NODE;
        pPrev = INVALID_NODE;

#endif
    }

    UUID_HASH_TABLE_NODE(
        RPC_UUID * pNewUuid
        )
    {
        Initialize(pNewUuid);
#ifdef DEBUGRPC

        pNext = INVALID_NODE;
        pPrev = INVALID_NODE;

#endif
    }

    inline void
    Initialize(
        RPC_UUID * pNewUuid
        )
    {
        Uuid = *pNewUuid;
    }

    int
    CompareUuid(
        void * Buffer
        )
    {
        RPC_UUID * UuidBuffer = (RPC_UUID *) Buffer;
        return Uuid.MatchUuid(UuidBuffer);
    }

    inline void
    VerifyFree(
        )
    {
        ASSERT(pNext == INVALID_NODE);
        ASSERT(pPrev == INVALID_NODE);
    }

    void
    QueryUuid(
        void * Buffer
        )
    {
        RPC_UUID * UuidBuffer = (RPC_UUID *) Buffer;
        *UuidBuffer = Uuid;
    }

};


class UUID_HASH_TABLE
{
public:

    UUID_HASH_TABLE(
        RPC_STATUS * pStatus,
        unsigned long SpinCount = 0
        );

    ~UUID_HASH_TABLE();

    unsigned
    Add(
        UUID_HASH_TABLE_NODE * pNode,
        unsigned Hash = NO_HASH
        );

    void
    Remove(
        UUID_HASH_TABLE_NODE * pNode,
        unsigned Hash = NO_HASH
        );

    inline UUID_HASH_TABLE_NODE *
    Lookup(
        RPC_UUID * Uuid,
        unsigned Hash = NO_HASH
        );

    inline unsigned
    MakeHash(
        RPC_UUID * Uuid
        )
    {
        return (Uuid->HashUuid() & BUCKET_COUNT_MASK);
    }

protected:

    inline void
    RequestHashMutex(
        unsigned Hash
        )
    {
        BucketMutexes[Hash % MUTEX_COUNT]->Request();
    }

    inline void
    ReleaseHashMutex(
        unsigned Hash
        )
    {
        BucketMutexes[Hash % MUTEX_COUNT]->Clear();
    }

    enum
    {
        // number of hash buckets
        //
        BUCKET_COUNT      = 128,

        // XOR this with any number to get a hash bucket index
        //
        BUCKET_COUNT_MASK = 0x007f,

        MUTEX_COUNT       = 4

    };

#ifdef DEBUGRPC
    unsigned Counts[BUCKET_COUNT];
#endif

    // hash buckets - each bucket has a linked list of nodes
    // in no particular order
    //
    UUID_HASH_TABLE_NODE * Buckets[BUCKET_COUNT];

    // a mutex protexts each bucket
    //
    MUTEX * BucketMutexes[MUTEX_COUNT];
};


UUID_HASH_TABLE_NODE *
UUID_HASH_TABLE::Lookup(
    RPC_UUID * Uuid,
    unsigned Hash
    )
{
    if (Hash == NO_HASH)
        {
        Hash = MakeHash(Uuid);
        }

    ASSERT( Hash < BUCKET_COUNT );

    UUID_HASH_TABLE_NODE * pScan = Buckets[Hash];
    while (pScan)
        {
        if (0 == Uuid->MatchUuid(&pScan->Uuid))
            {
            return pScan;
            }

        if (pScan->pNext && pScan->pNext->pPrev != pScan)
            {
#ifdef NTENV
            DbgBreakPoint();
#else
            RpcpBreakPoint();
#endif
            }

        pScan = pScan->pNext;
        }

    return 0;
}

#endif //  _HASHTABL_HXX_