/* * Copyright (C) 2010 Red Hat, Inc. * * Author: Angus Salkeld * * This file is part of libqb. * * libqb is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 2.1 of the License, or * (at your option) any later version. * * libqb 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with libqb. If not, see . */ #include "os_base.h" #include #define MAX_BIN_ELEMENTS 256 #define MAX_BINS 256 #define BIN_NUM_GET(_idx_) (_idx_ >> 8) #define ELEM_NUM_GET(_idx_) (_idx_ & 0xff) struct qb_array { void *bin[MAX_BINS]; size_t max_elements; size_t element_size; size_t num_bins; size_t autogrow_elements; }; qb_array_t * qb_array_create(size_t max_elements, size_t element_size) { return qb_array_create_2(max_elements, element_size, 0); } qb_array_t * qb_array_create_2(size_t max_elements, size_t element_size, size_t autogrow_elements) { int32_t i; struct qb_array *a = NULL; if (max_elements > (MAX_BIN_ELEMENTS * MAX_BINS)) { errno = -EINVAL; return NULL; } if (element_size < 1) { errno = -EINVAL; return NULL; } if (autogrow_elements > MAX_BIN_ELEMENTS) { errno = -EINVAL; return NULL; } a = calloc(1, sizeof(struct qb_array)); if (a == NULL) { return NULL; } a->element_size = element_size; a->max_elements = max_elements; a->num_bins = QB_MIN((max_elements / MAX_BIN_ELEMENTS) + 1, MAX_BINS); a->autogrow_elements = autogrow_elements; for (i = 0; i < MAX_BINS; i++) { if (i < a->num_bins) { a->bin[i] = calloc(MAX_BIN_ELEMENTS, element_size); } else { a->bin[i] = NULL; } } return a; } int32_t qb_array_index(struct qb_array * a, int32_t idx, void **element_out) { int32_t b; int32_t elem; char *bin; if (a == NULL || element_out == NULL) { return -EINVAL; } if (idx < 0) { return -ERANGE; } if (idx >= a->max_elements) { elem = idx + a->autogrow_elements; if (a->autogrow_elements == 0) { return -ERANGE; } else { int32_t rc = qb_array_grow(a, elem); if (rc != 0) { return rc; } } } b = BIN_NUM_GET(idx); assert(b < a->num_bins); elem = ELEM_NUM_GET(idx); assert(elem < MAX_BIN_ELEMENTS); bin = a->bin[b]; *element_out = (bin + (a->element_size * elem)); return 0; } size_t qb_array_num_bins_get(struct qb_array * a) { if (a == NULL) { return -EINVAL; } return a->num_bins; } size_t qb_array_elems_per_bin_get(struct qb_array * a) { if (a == NULL) { return -EINVAL; } return MAX_BIN_ELEMENTS; } int32_t qb_array_grow(struct qb_array * a, size_t max_elements) { int32_t i; int32_t old_bins; if (a == NULL || max_elements > (MAX_BIN_ELEMENTS * MAX_BINS)) { return -EINVAL; } if (max_elements <= a->max_elements) { return 0; } a->max_elements = max_elements; if (a->num_bins >= ((max_elements / MAX_BIN_ELEMENTS) + 1)) { return 0; } old_bins = a->num_bins; a->num_bins = QB_MIN((max_elements / MAX_BIN_ELEMENTS) + 1, MAX_BINS); for (i = old_bins; i < a->num_bins; i++) { if (a->bin[i] == NULL) { a->bin[i] = calloc(MAX_BIN_ELEMENTS, a->element_size); } } return 0; } void qb_array_free(struct qb_array *a) { int32_t i; for (i = 0; i < a->num_bins; i++) { free(a->bin[i]); } free(a); }