/***********************************************************************

Copyright (c) 2012, Oracle and/or its affiliates. All Rights Reserved.

This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; version 2 of the License.

This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
Public License for more details.

You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA

***********************************************************************/
/**************************************************//**
@file innodb_list.h

Created 03/15/2011      Jimmy Yang (most macros and defines are adopted
			from utility files in the InnoDB. Namely
			ut/ut0lst.h, ut0rnd.h and hash0hash.h etc.)
*******************************************************/

#ifndef INNODB_UTILITY_H
#define INNODB_UTILITY_H

#include "config.h"
#include "api0api.h"


#define UT_LIST_NODE_T(TYPE)						\
struct {								\
	TYPE*	prev;	/*!< pointer to the previous node,		\
			NULL if start of list */			\
	TYPE*	next;	/*!< pointer to next node, NULL if end of list */\
}									\

#define UT_LIST_BASE_NODE_T(TYPE)					\
struct {								\
	int   count;  /*!< count of nodes in list */			\
	TYPE *  start;  /*!< pointer to list start, NULL if empty */	\
	TYPE *  end;    /*!< pointer to list end, NULL if empty */	\
}

/** Some Macros to manipulate the list, extracted from "ut0lst.h" */
#define UT_LIST_INIT(BASE)						\
{									\
	(BASE).count = 0;						\
	(BASE).start = NULL;						\
	(BASE).end   = NULL;						\
}									\

#define UT_LIST_ADD_LAST(NAME, BASE, N)					\
{									\
        ((BASE).count)++;						\
        ((N)->NAME).prev = (BASE).end;					\
        ((N)->NAME).next = NULL;					\
        if ((BASE).end != NULL) {					\
                (((BASE).end)->NAME).next = (N);			\
        }								\
        (BASE).end = (N);						\
        if ((BASE).start == NULL) {					\
                (BASE).start = (N);					\
        }								\
}									\

#define UT_LIST_ADD_FIRST(NAME, BASE, N)				\
{									\
	((BASE).count)++;						\
	((N)->NAME).next = (BASE).start;				\
	((N)->NAME).prev = NULL;					\
	if (UNIV_LIKELY((BASE).start != NULL)) {			\
		(((BASE).start)->NAME).prev = (N);			\
	}								\
	(BASE).start = (N);						\
	if (UNIV_UNLIKELY((BASE).end == NULL)) {			\
		(BASE).end = (N);					\
	}								\
}									\

# define UT_LIST_REMOVE_CLEAR(NAME, N)					\
	((N)->NAME.prev = (N)->NAME.next = (void*) -1)

/** Removes a node from a linked list. */
#define UT_LIST_REMOVE(NAME, BASE, N)                                   \
do {                                                                    \
	((BASE).count)--;                                               \
	if (((N)->NAME).next != NULL) {                                 \
		((((N)->NAME).next)->NAME).prev = ((N)->NAME).prev;     \
	} else {                                                        \
		(BASE).end = ((N)->NAME).prev;                          \
	}                                                               \
	if (((N)->NAME).prev != NULL) {                                 \
		((((N)->NAME).prev)->NAME).next = ((N)->NAME).next;     \
	} else {                                                        \
		(BASE).start = ((N)->NAME).next;                        \
	}                                                               \
	UT_LIST_REMOVE_CLEAR(NAME, N);                                  \
} while (0)

#define UT_LIST_GET_NEXT(NAME, N)	(((N)->NAME).next)

#define UT_LIST_GET_LEN(BASE)	(BASE).count

#define UT_LIST_GET_FIRST(BASE)	(BASE).start

/*************************************************************//**
Folds a character string ending in the null character.
Extracted from ut0rnd.h and ut0rnd.ic.
@return folded value */

ib_ulint_t
ut_fold_string(
/*===========*/
	const char*	str);	/*!< in: null-terminated string */

typedef struct hash_cell_struct{
	void*		node;	/*!< hash chain node, NULL if none */
} hash_cell_t;

typedef struct hash_table_struct {
	ib_ulint_t	n_cells;/* number of cells in the hash table */
	hash_cell_t*	array;	/*!< pointer to cell array */
} hash_table_t;

#define HASH_INSERT(TYPE, NAME, TABLE, FOLD, DATA)	\
do {							\
	hash_cell_t*	cell3333;			\
	TYPE*		struct3333;			\
							\
							\
	(DATA)->NAME = NULL;				\
							\
	cell3333 = hash_get_nth_cell(TABLE, hash_calc_hash(FOLD, TABLE));\
							\
	if (cell3333->node == NULL) {			\
		cell3333->node = DATA;			\
	} else {					\
		struct3333 = (TYPE*) cell3333->node;	\
							\
		while (struct3333->NAME != NULL) {	\
							\
			struct3333 = (TYPE*) struct3333->NAME;\
		}					\
							\
		struct3333->NAME = DATA;		\
	}						\
} while (0)

/*******************************************************************//**
Gets the first struct in a hash chain, NULL if none. */

#define HASH_GET_FIRST(TABLE, HASH_VAL)			\
	(hash_get_nth_cell(TABLE, HASH_VAL)->node)

/*******************************************************************//**
Gets the next struct in a hash chain, NULL if none. */

#define HASH_GET_NEXT(NAME, DATA)       ((DATA)->NAME)

/********************************************************************//**
Looks for a struct in a hash table. */
#define HASH_SEARCH(NAME, TABLE, FOLD, TYPE, DATA, TEST)		\
{									\
	(DATA) = (TYPE) HASH_GET_FIRST(TABLE, hash_calc_hash(FOLD, TABLE));\
									\
	while ((DATA) != NULL) {					\
		if (TEST) {						\
			break;						\
		} else {						\
			(DATA) = (TYPE) HASH_GET_NEXT(NAME, DATA);	\
		}							\
	}								\
}


/********************************************************************//**
Cleanup items in a hash table */
#define HASH_CLEANUP(TABLE, TYPE)					\
do {									\
	ib_ulint_t      i;						\
	TYPE		data;						\
									\
	for (i = 0; i < TABLE->n_cells; i++) {				\
		data = (TYPE) HASH_GET_FIRST(TABLE, i);			\
									\
		while (data) {						\
			TYPE	next_data;				\
			next_data = HASH_GET_NEXT(name_hash, data);	\
			innodb_config_free(data);			\
			free(data);					\
			data = next_data;				\
		}							\
	}								\
									\
	free(TABLE->array);						\
	free(TABLE);							\
} while(0)

/************************************************************//**
Gets the nth cell in a hash table.
@return pointer to cell */
hash_cell_t*
hash_get_nth_cell(
/*==============*/
	hash_table_t*	table,  /*!< in: hash table */
	ib_ulint_t	n);     /*!< in: cell index */

/*************************************************************//**
Creates a hash table with >= n array cells. The actual number
of cells is chosen to be a prime number slightly bigger than n.
@return own: created table */
hash_table_t*
hash_create(
/*========*/
	ib_ulint_t	n);     /*!< in: number of array cells */

/**************************************************************//**
Calculates the hash value from a folded value.
@return hashed value */
ib_ulint_t
hash_calc_hash(
/*===========*/
	ib_ulint_t	fold,	/*!< in: folded value */
	hash_table_t*	table);	/*!< in: hash table */

#endif /* INNODB_UTILITY_H */
