// Copyright 2015-2021 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.


#ifndef HASH_H_
#define HASH_H_

struct __natsHashEntry;

typedef struct __natsHashEntry
{
    int64_t                 key;
    void                    *data;
    struct __natsHashEntry  *next;

} natsHashEntry;

typedef struct __natsHash
{
    natsHashEntry   **bkts;
    int             numBkts;
    int             mask;
    int             used;
    bool            canResize;

} natsHash;

typedef struct __natsHashIter
{
    natsHash        *hash;
    natsHashEntry   *current;
    natsHashEntry   *next;
    int             currBkt;
    bool            started;

} natsHashIter;

typedef struct __natsStrHashEntry
{
    uint32_t                    hk;
    char                        *key;
    bool                        freeKey;
    void                        *data;
    struct __natsStrHashEntry   *next;

} natsStrHashEntry;

typedef struct __natsStrHash
{
    natsStrHashEntry    **bkts;
    int                 numBkts;
    int                 mask;
    int                 used;
    bool                canResize;

} natsStrHash;

typedef struct __natsStrHashIter
{
    natsStrHash         *hash;
    natsStrHashEntry    *current;
    natsStrHashEntry    *next;
    int                 currBkt;
    bool                started;

} natsStrHashIter;

#define natsHash_Count(h)       ((h)->used)
#define natsStrHash_Count(h)    ((h)->used)

//
// Hash with in64_t as the key
//
natsStatus
natsHash_Create(natsHash **newHash, int initialSize);

natsStatus
natsHash_Set(natsHash *hash, int64_t key, void *data, void **oldData);

void*
natsHash_Get(natsHash *hash, int64_t key);

void*
natsHash_Remove(natsHash *hash, int64_t key);

natsStatus
natsHash_RemoveSingle(natsHash *hash, int64_t *key, void **data);

void
natsHash_Destroy(natsHash *hash);

//
// Iterator for Hash int64_t
//
void
natsHashIter_Init(natsHashIter *iter, natsHash *hash);

bool
natsHashIter_Next(natsHashIter *iter, int64_t *key, void **value);

natsStatus
natsHashIter_RemoveCurrent(natsHashIter *iter);

void
natsHashIter_Done(natsHashIter *iter);

//
// Hash with char* as the key
//
natsStatus
natsStrHash_Create(natsStrHash **newHash, int initialSize);

uint32_t
natsStrHash_Hash(const char *data, int dataLen);

#define natsStrHash_Set(h, k, c, d, o) natsStrHash_SetEx((h), (k), (c), ((c) ? true : false), (d), (o))

natsStatus
natsStrHash_SetEx(natsStrHash *hash, char *key, bool copyKey, bool freeKey,
                  void *data, void **oldData);

#define natsStrHash_Get(h, k) natsStrHash_GetEx((h), (k), (int) strlen(k))

void*
natsStrHash_GetEx(natsStrHash *hash, char *key, int keyLen);

void*
natsStrHash_Remove(natsStrHash *hash, char *key);

natsStatus
natsStrHash_RemoveSingle(natsStrHash *hash, char **key, void **data);

void
natsStrHash_Destroy(natsStrHash *hash);

//
// Iterator for Hash char*
//
void
natsStrHashIter_Init(natsStrHashIter *iter, natsStrHash *hash);

bool
natsStrHashIter_Next(natsStrHashIter *iter, char **key, void **value);

natsStatus
natsStrHashIter_RemoveCurrent(natsStrHashIter *iter);

void
natsStrHashIter_Done(natsStrHashIter *iter);


#endif /* HASH_H_ */
