## root/libutil/varray.c

/* [<][>][^][v][top][bottom][index][help] */

## DEFINITIONS

This source file includes following definitions.

1. varray_open
2. varray_assign
3. varray_append
4. varray_reset
5. varray_close

    /*
     * Copyright (c) 2004 Tama Communications Corporation
     *
     * This file is part of GNU GLOBAL.
     *
     * 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, either version 3 of the License, or
     * (at your option) any later version.
     *
     * 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, see <http://www.gnu.org/licenses/>.
     */

    #ifdef HAVE_CONFIG_H
    #include <config.h>
    #endif
    #ifdef STDC_HEADERS
    #include <stdlib.h>
    #endif
    #include <stdio.h>
    #include "checkalloc.h"
    #include "die.h"
    #include "varray.h"

    /*

    Virtual array: usage and memory status

    _: allocated but not assigned.
    @: assigned but the value is uncertainty.

    Function call                           Memory status
    ----------------------------------------------------------
                                            (not exist)
    vb = varray_open(sizeof(int), 5);       ||

    int *a = varray_assign(vb, 0, 0);       ||

            a == NULL

    int *a = varray_assign(vb, 0, 1);       |@|_|_|_|_|             // expand

    printf("%d allocated, %d assigned.\n", vb->alloced, vb->length);

            "5 allocated, 1 assigned."
                                            v
    *a = 3;                                 |3|_|_|_|_|

                                                  v
    int *a = varray_assign(vb, 3, 1);       |3|@|@|@|_|
                                                  v
    *a = 8;                                 |3|@|@|8|_|
                                                      v
    int *a = varray_assign(vb, 5, 1);       |3|@|@|8|@|@|_|_|_|_|   // expand
                                                      v
    *a = 5;                                 |3|@|@|8|@|5|_|_|_|_|

    printf("%d allocated, %d assigned.\n", vb->alloced, vb->length);

            "10 allocated, 6 assigned."

    // After construction, you can treat it as a C array.

    int i, *a = varray_assign(vb, 0, 0);

    for (i = 0; i < vb->length; i++)
            printf("%d: %d\n", i, a[i]); // a[1], a[2], a[4] is uncertainty.
    */

    #define DEFAULT_EXPAND  100
    static int debug = 0;
    /*
     * varray_open: open virtual array.
     *
     *      i)      size    size of entry
     *      i)      expand  expand array size
     *                      if 0 is specified then use DEFAULT_EXPAND.
     *      r)      vb      VARRAY structure
     */
    VARRAY *
    varray_open(int size, int expand)
    {
            VARRAY *vb = (VARRAY *)check_calloc(sizeof(VARRAY), 1);

            if (size < 1)
                    die("varray_open: size < 1.");
            if (expand < 0)
                    die("varray_open: expand < 0.");
            vb->size = size;
            vb->alloced = vb->length = 0;
            vb->expand = (expand == 0) ? DEFAULT_EXPAND : expand;
            vb->vbuf = NULL;
            return vb;
    }
    /*
     * varray_assign: assign varray entry.
     *
     *      i)      vb      VARRAY structure
     *      i)      index   index
     *      i)      force   if entry not found, create it.
     *      r)              pointer of the entry
     *
     * If specified entry is found then it is returned, else it is allocated
     * and returned.
     * This procedure doesn't operate the contents of the array.
     */
    void *
    varray_assign(VARRAY *vb, int index, int force)
    {
            if (index < 0)
                    die("varray_assign: illegal index value.");
            if (index >= vb->length) {
                    if (force)
                            vb->length = index + 1;
                    else if (index == 0 && vb->length == 0)
                            return NULL;
                    else
                            die("varray_assign: index(=%d) is out of range.", index);
            }
            /*
             * Expand the area.
             */
            if (index >= vb->alloced) {
                    int old_alloced = vb->alloced;

                    while (index >= vb->alloced)
                            vb->alloced += vb->expand;
                    /*
                     * Old implementations of realloc() may crash
                     * when a null pointer is passed.
                     * Therefore, we cannot use realloc(NULL, ...).
                     */
                    if (vb->vbuf == NULL)
                            vb->vbuf = (char *)check_malloc(vb->size * vb->alloced);
                    else
                            vb->vbuf = (char *)check_realloc(vb->vbuf, vb->size * vb->alloced);
                    if (debug)
                            fprintf(stderr, "Expanded: from %d to %d.\n", old_alloced, vb->alloced);
            }
            return (void *)(vb->vbuf + vb->size * index);
    }

    /*
     * varray_append: append varray entry.
     *
     *      i)      vb      VARRAY structure
     *      r)              pointer of the entry
     *
     * This procedure doesn't operate the contents of the array.
     */
    void *
    varray_append(VARRAY *vb)
    {
            return varray_assign(vb, vb->length, 1);
    }
    /*
     * varray_reset: reset varray array.
     *
     *      i)      vb      VARRAY structure
     */
    void
    varray_reset(VARRAY *vb)
    {
            vb->length = 0;
    }
    /*
     * varray_close: close varray array.
     *
     *      i)      vb      VARRAY structure
     */
    void
    varray_close(VARRAY *vb)
    {
            if (vb) {
                    if (vb->vbuf)
                            (void)free(vb->vbuf);
                    (void)free(vb);
            }
    }

/* [<][>][^][v][top][bottom][index][help] */