/*****************************************************************************
 * file    lib/management/array.c  
 * author  YuLiang
 * version 1.0.0
 * date    22-Sep-2021
 * brief   This file provides all the array related operation functions.
 ******************************************************************************
 * Attention
 *
 * <h2><center>&copy; COPYRIGHT(c) 2021 LandPower</center></h2>
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *   1. Redistributions of source code must retain the above copyright notice,
 *      this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright notice,
 *      this list of conditions and the following disclaimer in the documentation
 *      and/or other materials provided with the distribution.
 *   3. Neither the name of LandPower nor the names of its contributors may be used to 
 *      endorse or promote products derived from this software without specific
 *      prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ******************************************************************************/

/* Includes ------------------------------------------------------------------*/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

/* 标准C库头文件. */

/* 用户代码头文件. */
#include "array.h"
/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/

/* Private macro -------------------------------------------------------------*/

/* Private variables ---------------------------------------------------------*/

/* Private function prototypes -----------------------------------------------*/

/* Internal functions --------------------------------------------------------*/
/* 确保设置的数组成员没有内存越界，如果超出数组长度，则重新realloc: 
   a        --  数组结构
   len      --  需要申请的长度
   mem_type --  使用的内存模块
   
   return: void */
static void _array_len_ensure(array_t *a, uint32_t len, int32_t mem_type)
{
    if (a->alloced > len)
    {
        return;
    }

    a->index = XREALLOC(mem_type, a->index, sizeof(void *) * (a->alloced * 2));
    memset(&a->index[a->alloced], 0, sizeof(void *) * a->alloced);
    a->alloced *= 2;
  
    if (a->alloced <= len)
    {
        _array_len_ensure(a, len, mem_type);
    }
}

/* 查找数组a的第一个空位置.
   a    -- 数组结构
   
   return: 第一个空位置索引 */
uint32_t _array_empty_slot(array_t *a)
{
    uint32_t i = 0;

    for(i = 0; i < a->active; i++)
    {
        if (NULL == a->index[i])
        {
            return i;
        }
    }

    return i;
}

/* Interface functions -------------------------------------------------------*/
/* 初始化数组:
   size     --  数组初始大小
   mem_type --  使用的内存模块

   return: 数组指针 */
array_t *array_init(uint32_t size, int32_t mem_type)
{
    array_t *a = XMALLOC(mem_type, sizeof(array_t));

    /* 如果大小为0,设置默认大小. */
    if (0 == size)
    {
        size = ARRAY_MIN_SIZE;
    }

    a->alloced = size;
    a->active = 0;
    a->index = XMALLOC(mem_type, sizeof(void *) * size);
  
    return a;
}

/* 设置数组相应索引位置的值:
   a        --  数组
   i        --  索引
   val      --  值
   mem_type --  使用的内存模块

   return: void */
void array_set(array_t *a, uint32_t i, void *val, int32_t mem_type)
{
    _array_len_ensure(a, i, mem_type);

    a->index[i] = val;

    if (a->active <= i)
    {
        a->active = i + 1;
    }
}

/* 删除数组相应索引位置的值:
   a    -- 数组
   i    -- 索引 

   return: void */
void array_unset(array_t *a, uint32_t i)
{
    if (i >= a->alloced)
    {
        return;
    }

    a->index[i] = NULL;

    /* 不是最后一个元素直接返回. */
    if (i + 1 != a->active)
    {
        return;
    }

    /* 如果是最后一个元素,则将当前可使用指针前移. */
    while(--a->active)
    {
        if (a->index[a->active - 1] != NULL)
        {
            break;
        }
    }
}

/* 将数据放入数组的第一个空位置:
   a        --  数组
   val      --  值
   mem_type --  使用的内存模块

   return: 数据放入位置的索引值 */
uint32_t array_append(array_t *a, void *val, int32_t mem_type)
{
    uint32_t i = 0;

    i = _array_empty_slot(a);
    _array_len_ensure(a, i, mem_type);

    a->index[i] = val;

    if (a->active <= i)
    {
        a->active = i + 1;
    }

    return i;
}

/* 复制数组a:
   a        --  数组
   mem_type --  使用的内存模块
   
   return: 新数组指针 */
array_t *array_copy(array_t *a, int32_t mem_type)
{
    unsigned int size = 0;
    array_t *array = XMALLOC(mem_type, sizeof(array_t));

    array->active = a->active;
    array->alloced = a->alloced;

    size = sizeof(void *) * (a->alloced);
    array->index = XMALLOC(mem_type, size);
    memcpy(array->index, a->index, size);

    return array;
}

/* 将数组a和数组b合并成数组a:
   a        --  数组1
   b        --  数组2
   mem_type --  使用的内存模块

   return: void */
void array_merge(array_t *a, array_t *b, int32_t mem_type)
{
    uint32_t size = 0;

    if (0 == b->alloced)
    {
        return;
    }

    size = sizeof(void *) * (a->alloced + b->alloced);
    a->index = XREALLOC(mem_type, a->index, size);
    memcpy(&a->index[a->active], b->index, sizeof(void *) * b->active);

    a->active = a->active + b->active;
    a->alloced = a->alloced + b->alloced;
}

/* 释放array_t:
   a        --  数组
   mem_type --  使用的内存模块
   
   return: void */
void array_free_wrapper(array_t *a, int32_t mem_type)
{
    XFREE(mem_type, a);
}

/* 释放array_t->index:
   a        --  数组
   mem_type --  使用的内存模块

   return: void */
void array_free_index(array_t *a, int32_t mem_type)
{
    XFREE(mem_type, a->index);
}

/* 释放array_t和array_t->index:
   a        --  数组
   mem_type --  使用的内存模块

   return: void */
void array_free(array_t *a, int32_t mem_type)
{
    XFREE(mem_type, a->index);
    XFREE(mem_type, a);
}

/* 查询数组a的数据i:
   a    -- 数组
   i    -- 元素索引

   return: 元素指针 */
void *array_lookup(array_t *a, uint32_t i)
{
    return (i >= a->active) ? NULL : a->index[i];
}

/* 获取数组a中有效数据的个数:
   a    -- 数组

   return: void */
uint32_t array_count(array_t *a)
{
    uint32_t i = 0;
    uint32_t count = 0;

    for (i = 0; i < a->active; i++)
    {
        if (a->index[i] != NULL)
        {
            count++;
        }
    }

    return count;
}
/************************ (C) COPYRIGHT LandPower ***** END OF FILE ****/
