/*!The Treasure Box Library
 *
 * 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.
 *
 * Copyright (C) 2009-present, TBOOX Open Source Group.
 *
 * @author      ruki
 * @file        hash_map.h
 * @ingroup     container
 *
 */
#ifndef TB_CONTAINER_HASH_MAP_H
#define TB_CONTAINER_HASH_MAP_H

/* //////////////////////////////////////////////////////////////////////////////////////
 * includes
 */
#include "prefix.h"
#include "element.h"
#include "iterator.h"

/* //////////////////////////////////////////////////////////////////////////////////////
 * extern
 */
__tb_extern_c_enter__

/* //////////////////////////////////////////////////////////////////////////////////////
 * macros
 */

/// the micro hash bucket size
#define TB_HASH_MAP_BUCKET_SIZE_MICRO                 (64)

/// the small hash bucket size
#define TB_HASH_MAP_BUCKET_SIZE_SMALL                 (256)

/// the large hash bucket size
#define TB_HASH_MAP_BUCKET_SIZE_LARGE                 (65536)

/* //////////////////////////////////////////////////////////////////////////////////////
 * types
 */

/// the hash map item type
typedef struct __tb_hash_map_item_t
{
    /// the item name
    tb_pointer_t        name;

    /// the item data
    tb_pointer_t        data;

}tb_hash_map_item_t, *tb_hash_map_item_ref_t;

/*! the hash map ref type
 *
 * <pre>
 *                 0        1        3       ...     ...                n       n + 1
 * hash_list: |--------|--------|--------|--------|--------|--------|--------|--------|
 *                         |
 *                       -----
 * item_list:           |     |       key:0
 *                       -----
 *                      |     |       key:1
 *                       -----               <= insert by binary search algorithm
 *                      |     |       key:2
 *                       -----
 *                      |     |       key:3
 *                       -----
 *                      |     |       key:4
 *                       -----
 *                      |     |
 *                       -----
 *                      |     |
 *                       -----
 *                      |     |
 *                       -----
 *
 * </pre>
 *
 * @note the itor of the same item is mutable
 */
typedef tb_iterator_ref_t tb_hash_map_ref_t;

/* //////////////////////////////////////////////////////////////////////////////////////
 * interfaces
 */

/*! init hash map
 *
 * @param bucket_size   the hash bucket size, using the default size if be zero
 * @param element_name  the item for name
 * @param element_data  the item for data
 *
 * @return              the hash map
 */
tb_hash_map_ref_t       tb_hash_map_init(tb_size_t bucket_size, tb_element_t element_name, tb_element_t element_data);

/*! exit hash map
 *
 * @param hash_map      the hash map
 */
tb_void_t               tb_hash_map_exit(tb_hash_map_ref_t hash_map);

/*! clear hash map
 *
 * @param hash_map      the hash map
 */
tb_void_t               tb_hash_map_clear(tb_hash_map_ref_t hash_map);

/*! get item data from name
 *
 * @note
 * the return value may be zero if the item type is integer
 * so we need call tb_hash_map_find for judging whether to get value successfully
 *
 * @code
 *
 * // find item and get item data
 * tb_xxxx_ref_t data = (tb_xxxx_ref_t)tb_hash_map_get(hash_map, name);
 * if (data)
 * {
 *      // ...
 * }
 * @endcode
 *
 * @param hash_map      the hash map
 * @param name          the item name
 *
 * @return              the item data
 */
tb_pointer_t            tb_hash_map_get(tb_hash_map_ref_t hash_map, tb_cpointer_t name);

/*! find item from name
 *
 * @code
 *
 * // find item
 * tb_size_t itor = tb_hash_map_find(hash_map, name);
 * if (itor != tb_iterator_tail(hash_map))
 * {
 *      // get data
 *      tb_xxxx_ref_t data = (tb_xxxx_ref_t)tb_iterator_item(hash_map, itor);
 *      tb_assert(data);
 *
 *      // remove it
 *      tb_iterator_remove(hash_map, itor);
 * }
 * @endcode
 *
 * @param hash_map      the hash map
 * @param name          the item name
 *
 * @return              the item itor, @note: the itor of the same item is mutable
 */
tb_size_t               tb_hash_map_find(tb_hash_map_ref_t hash_map, tb_cpointer_t name);

/*! insert item data from name
 *
 * @note the pair (name => data) is unique
 *
 * @param hash_map      the hash map
 * @param name          the item name
 * @param data          the item data
 *
 * @return              the item itor, @note: the itor of the same item is mutable
 */
tb_size_t               tb_hash_map_insert(tb_hash_map_ref_t hash_map, tb_cpointer_t name, tb_cpointer_t data);

/*! remove item from name
 *
 * @param hash_map      the hash map
 * @param name          the item name
 */
tb_void_t               tb_hash_map_remove(tb_hash_map_ref_t hash_map, tb_cpointer_t name);

/*! the hash map size
 *
 * @param hash_map      the hash map
 *
 * @return              the hash map size
 */
tb_size_t               tb_hash_map_size(tb_hash_map_ref_t hash_map);

/*! the hash map maxn
 *
 * @param hash_map      the hash map
 *
 * @return              the hash map maxn
 */
tb_size_t               tb_hash_map_maxn(tb_hash_map_ref_t hash_map);

#ifdef __tb_debug__
/*! dump hash
 *
 * @param hash_map      the hash map
 */
tb_void_t               tb_hash_map_dump(tb_hash_map_ref_t hash_map);
#endif

/* //////////////////////////////////////////////////////////////////////////////////////
 * extern
 */
__tb_extern_c_leave__

#endif

