/*!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        allocator.h
 * @ingroup     memory
 *
 */
#ifndef TB_MEMORY_ALLOCATOR_H
#define TB_MEMORY_ALLOCATOR_H

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

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

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

#define tb_allocator_malloc(allocator, size)                        tb_allocator_malloc_(allocator, size __tb_debug_vals__)
#define tb_allocator_malloc0(allocator, size)                       tb_allocator_malloc0_(allocator, size __tb_debug_vals__)

#define tb_allocator_nalloc(allocator, item, size)                  tb_allocator_nalloc_(allocator, item, size __tb_debug_vals__)
#define tb_allocator_nalloc0(allocator, item, size)                 tb_allocator_nalloc0_(allocator, item, size __tb_debug_vals__)

#define tb_allocator_ralloc(allocator, data, size)                  tb_allocator_ralloc_(allocator, (tb_pointer_t)(data), size __tb_debug_vals__)
#define tb_allocator_free(allocator, data)                          tb_allocator_free_(allocator, (tb_pointer_t)(data) __tb_debug_vals__)

#define tb_allocator_large_malloc(allocator, size, real)            tb_allocator_large_malloc_(allocator, size, real __tb_debug_vals__)
#define tb_allocator_large_malloc0(allocator, size, real)           tb_allocator_large_malloc0_(allocator, size, real __tb_debug_vals__)

#define tb_allocator_large_nalloc(allocator, item, size, real)      tb_allocator_large_nalloc_(allocator, item, size, real __tb_debug_vals__)
#define tb_allocator_large_nalloc0(allocator, item, size, real)     tb_allocator_large_nalloc0_(allocator, item, size, real __tb_debug_vals__)

#define tb_allocator_large_ralloc(allocator, data, size, real)      tb_allocator_large_ralloc_(allocator, (tb_pointer_t)(data), size, real __tb_debug_vals__)
#define tb_allocator_large_free(allocator, data)                    tb_allocator_large_free_(allocator, (tb_pointer_t)(data) __tb_debug_vals__)

#define tb_allocator_align_malloc(allocator, size, align)           tb_allocator_align_malloc_(allocator, size, align __tb_debug_vals__)
#define tb_allocator_align_malloc0(allocator, size, align)          tb_allocator_align_malloc0_(allocator, size, align __tb_debug_vals__)

#define tb_allocator_align_nalloc(allocator, item, size, align)     tb_allocator_align_nalloc_(allocator, item, size, align __tb_debug_vals__)
#define tb_allocator_align_nalloc0(allocator, item, size, align)    tb_allocator_align_nalloc0_(allocator, item, size, align __tb_debug_vals__)

#define tb_allocator_align_ralloc(allocator, data, size, align)     tb_allocator_align_ralloc_(allocator, (tb_pointer_t)(data), size, align __tb_debug_vals__)
#define tb_allocator_align_free(allocator, data)                    tb_allocator_align_free_(allocator, (tb_pointer_t)(data) __tb_debug_vals__)

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

/// the allocator type enum
typedef enum __tb_allocator_type_e
{
    TB_ALLOCATOR_TYPE_NONE       = 0
,   TB_ALLOCATOR_TYPE_DEFAULT    = 1
,   TB_ALLOCATOR_TYPE_NATIVE     = 2
,   TB_ALLOCATOR_TYPE_VIRTUAL    = 3
,   TB_ALLOCATOR_TYPE_STATIC     = 4
,   TB_ALLOCATOR_TYPE_LARGE      = 5
,   TB_ALLOCATOR_TYPE_SMALL      = 6

}tb_allocator_type_e;

/// the allocator flag enum
typedef enum __tb_allocator_flag_e
{
    TB_ALLOCATOR_FLAG_NONE      = 0
,   TB_ALLOCATOR_FLAG_NOLOCK    = 1

}tb_allocator_flag_e;

/// the allocator type
typedef struct __tb_allocator_t
{
    /// the type
    tb_uint32_t             type : 16;

    /// the flag
    tb_uint32_t             flag : 16;

    /// the lock
    tb_spinlock_t           lock;

    /*! malloc data
     *
     * @param allocator     the allocator
     * @param size          the size
     *
     * @return              the data address
     */
    tb_pointer_t            (*malloc)(struct __tb_allocator_t* allocator, tb_size_t size __tb_debug_decl__);

    /*! realloc data
     *
     * @param allocator     the allocator
     * @param data          the data address
     * @param size          the data size
     *
     * @return              the new data address
     */
    tb_pointer_t            (*ralloc)(struct __tb_allocator_t* allocator, tb_pointer_t data, tb_size_t size __tb_debug_decl__);

    /*! free data
     *
     * @param allocator     the allocator
     * @param data          the data address
     *
     * @return              tb_true or tb_false
     */
    tb_bool_t               (*free)(struct __tb_allocator_t* allocator, tb_pointer_t data __tb_debug_decl__);

    /*! malloc large data
     *
     * @param allocator     the allocator
     * @param size          the size
     * @param real          the real allocated size >= size, optional
     *
     * @return              the data address
     */
    tb_pointer_t            (*large_malloc)(struct __tb_allocator_t* allocator, tb_size_t size, tb_size_t* real __tb_debug_decl__);

    /*! realloc large data
     *
     * @param allocator     the allocator
     * @param data          the data address
     * @param size          the data size
     * @param real          the real allocated size >= size, optional
     *
     * @return              the new data address
     */
    tb_pointer_t            (*large_ralloc)(struct __tb_allocator_t* allocator, tb_pointer_t data, tb_size_t size, tb_size_t* real __tb_debug_decl__);

    /*! free large data
     *
     * @param allocator     the allocator
     * @param data          the data address
     *
     * @return              tb_true or tb_false
     */
    tb_bool_t               (*large_free)(struct __tb_allocator_t* allocator, tb_pointer_t data __tb_debug_decl__);

    /*! clear allocator
     *
     * @param allocator     the allocator
     */
    tb_void_t               (*clear)(struct __tb_allocator_t* allocator);

    /*! exit allocator
     *
     * @param allocator     the allocator
     */
    tb_void_t               (*exit)(struct __tb_allocator_t* allocator);

#ifdef __tb_debug__
    /*! dump allocator
     *
     * @param allocator     the allocator
     */
    tb_void_t               (*dump)(struct __tb_allocator_t* allocator);

    /*! have this given data addess?
     *
     * @param allocator     the allocator
     * @param data          the data address
     *
     * @return              tb_true or tb_false
     */
    tb_bool_t               (*have)(struct __tb_allocator_t* allocator, tb_cpointer_t data);
#endif

}tb_allocator_t, *tb_allocator_ref_t;

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

/*! the allocator
 *
 * @return              the allocator
 */
tb_allocator_ref_t      tb_allocator(tb_noarg_t);

/*! the native allocator
 *
 * uses system memory directly
 *
 * @return              the allocator
 */
tb_allocator_ref_t      tb_allocator_native(tb_noarg_t);

/*! the allocator type
 *
 * @param allocator     the allocator
 *
 * @return              the allocator type
 */
tb_size_t               tb_allocator_type(tb_allocator_ref_t allocator);

/*! malloc data
 *
 * @param allocator     the allocator
 * @param size          the size
 *
 * @return              the data address
 */
tb_pointer_t            tb_allocator_malloc_(tb_allocator_ref_t allocator, tb_size_t size __tb_debug_decl__);

/*! malloc data and fill zero
 *
 * @param allocator     the allocator
 * @param size          the size
 *
 * @return              the data address
 */
tb_pointer_t            tb_allocator_malloc0_(tb_allocator_ref_t allocator, tb_size_t size __tb_debug_decl__);

/*! malloc data with the item count
 *
 * @param allocator     the allocator
 * @param item          the item count
 * @param size          the item size
 *
 * @return              the data address
 */
tb_pointer_t            tb_allocator_nalloc_(tb_allocator_ref_t allocator, tb_size_t item, tb_size_t size __tb_debug_decl__);

/*! malloc data with the item count and fill zero
 *
 * @param allocator     the allocator
 * @param item          the item count
 * @param size          the item size
 *
 * @return              the data address
 */
tb_pointer_t            tb_allocator_nalloc0_(tb_allocator_ref_t allocator, tb_size_t item, tb_size_t size __tb_debug_decl__);

/*! realloc data
 *
 * @param allocator     the allocator
 * @param data          the data address
 * @param size          the data size
 *
 * @return              the new data address
 */
tb_pointer_t            tb_allocator_ralloc_(tb_allocator_ref_t allocator, tb_pointer_t data, tb_size_t size __tb_debug_decl__);

/*! free data
 *
 * @param allocator     the allocator
 * @param data          the data address
 *
 * @return              tb_true or tb_false
 */
tb_bool_t               tb_allocator_free_(tb_allocator_ref_t allocator, tb_pointer_t data __tb_debug_decl__);

/*! malloc large data
 *
 * @param allocator     the allocator
 * @param size          the size
 * @param real          the real allocated size >= size, optional
 *
 * @return              the data address
 */
tb_pointer_t            tb_allocator_large_malloc_(tb_allocator_ref_t allocator, tb_size_t size, tb_size_t* real __tb_debug_decl__);

/*! malloc large data and fill zero
 *
 * @param allocator     the allocator
 * @param size          the size
 * @param real          the real allocated size >= size, optional
 *
 * @return              the data address
 */
tb_pointer_t            tb_allocator_large_malloc0_(tb_allocator_ref_t allocator, tb_size_t size, tb_size_t* real __tb_debug_decl__);

/*! malloc large data with the item count
 *
 * @param allocator     the allocator
 * @param item          the item count
 * @param size          the item size
 * @param real          the real allocated size >= item * size, optional
 *
 * @return              the data address
 */
tb_pointer_t            tb_allocator_large_nalloc_(tb_allocator_ref_t allocator, tb_size_t item, tb_size_t size, tb_size_t* real __tb_debug_decl__);

/*! malloc large data with the item count and fill zero
 *
 * @param allocator     the allocator
 * @param item          the item count
 * @param size          the item size
 * @param real          the real allocated size >= item * size, optional
 *
 * @return              the data address
 */
tb_pointer_t            tb_allocator_large_nalloc0_(tb_allocator_ref_t allocator, tb_size_t item, tb_size_t size, tb_size_t* real __tb_debug_decl__);

/*! realloc large data
 *
 * @param allocator     the allocator
 * @param data          the data address
 * @param size          the data size
 * @param real          the real allocated size >= size, optional
 *
 * @return              the new data address
 */
tb_pointer_t            tb_allocator_large_ralloc_(tb_allocator_ref_t allocator, tb_pointer_t data, tb_size_t size, tb_size_t* real __tb_debug_decl__);

/*! free large data
 *
 * @param allocator     the allocator
 * @param data          the data address
 *
 * @return              tb_true or tb_false
 */
tb_bool_t               tb_allocator_large_free_(tb_allocator_ref_t allocator, tb_pointer_t data __tb_debug_decl__);

/*! align malloc data
 *
 * @param allocator     the allocator
 * @param size          the size
 * @param align         the alignment bytes
 *
 * @return              the data address
 */
tb_pointer_t            tb_allocator_align_malloc_(tb_allocator_ref_t allocator, tb_size_t size, tb_size_t align __tb_debug_decl__);

/*! align malloc data and fill zero
 *
 * @param allocator     the allocator
 * @param size          the size
 * @param align         the alignment bytes
 *
 * @return              the data address
 */
tb_pointer_t            tb_allocator_align_malloc0_(tb_allocator_ref_t allocator, tb_size_t size, tb_size_t align __tb_debug_decl__);

/*! align malloc data with the item count
 *
 * @param allocator     the allocator
 * @param item          the item count
 * @param size          the item size
 * @param align         the alignment bytes
 *
 * @return              the data address
 */
tb_pointer_t            tb_allocator_align_nalloc_(tb_allocator_ref_t allocator, tb_size_t item, tb_size_t size, tb_size_t align __tb_debug_decl__);

/*! align malloc data with the item count and fill zero
 *
 * @param allocator     the allocator
 * @param item          the item count
 * @param size          the item size
 * @param align         the alignment bytes
 *
 * @return              the data address
 */
tb_pointer_t            tb_allocator_align_nalloc0_(tb_allocator_ref_t allocator, tb_size_t item, tb_size_t size, tb_size_t align __tb_debug_decl__);

/*! align realloc data
 *
 * @param allocator     the allocator
 * @param data          the data address
 * @param size          the data size
 *
 * @return              the new data address
 */
tb_pointer_t            tb_allocator_align_ralloc_(tb_allocator_ref_t allocator, tb_pointer_t data, tb_size_t size, tb_size_t align __tb_debug_decl__);

/*! align free data
 *
 * @param allocator     the allocator
 * @param data          the data address
 *
 * @return              tb_true or tb_false
 */
tb_bool_t               tb_allocator_align_free_(tb_allocator_ref_t allocator, tb_pointer_t data __tb_debug_decl__);

/*! clear it
 *
 * @param allocator     the allocator
 */
tb_void_t               tb_allocator_clear(tb_allocator_ref_t allocator);

/*! exit it
 *
 * @param allocator     the allocator
 */
tb_void_t               tb_allocator_exit(tb_allocator_ref_t allocator);

#ifdef __tb_debug__
/*! dump it
 *
 * @param allocator     the allocator
 */
tb_void_t               tb_allocator_dump(tb_allocator_ref_t allocator);

/*! have this given data addess?
 *
 * @param allocator     the allocator
 * @param data          the data address
 *
 * @return              tb_true or tb_false
 */
tb_bool_t               tb_allocator_have(tb_allocator_ref_t allocator, tb_cpointer_t data);
#endif

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

#endif
