/* * Copyright (c) 2017-2019 Cisco and/or its affiliates. * 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. */ /** * \file array.h * \brief Generic array template */ #ifndef UTIL_ARRAY_H #define UTIL_ARRAY_H #include #include #include // log2 #include // memmove #define BUFSIZE 1024 typedef int(*cmp_t)(const void * x, const void * y); #define TYPEDEF_ARRAY_H(NAME, T) \ \ typedef struct { \ size_t size; \ size_t max_size_log; \ T * elements; \ } NAME ## _t; \ \ int NAME ## _initialize(NAME ## _t * array); \ \ int NAME ## _finalize(NAME ## _t * array); \ \ NAME ## _t * NAME ## _create(); \ \ void NAME ## _free(NAME ## _t * array); \ \ int NAME ## _add(NAME ## _t * array, T element); \ \ int NAME ## _remove_index(NAME ## _t * array, int index, T * element); \ \ int NAME ## _remove(NAME ## _t * array, const T search, T * element); \ \ int NAME ## _get(const NAME ## _t * array, const T search, T * element); \ \ int NAME ## _get_index(const NAME ## _t * array, int index, T * element); \ \ int NAME ## _get_elements(const NAME ## _t * array, T ** elements); \ \ size_t NAME ## _len(const NAME ## _t * array); #define ARRAY_MAX_SIZE_LOG_INIT 0 #define TYPEDEF_ARRAY(NAME, T, CMP, SNPRINTF) \ int \ NAME ## _initialize(NAME ## _t * array) \ { \ array->max_size_log = ARRAY_MAX_SIZE_LOG_INIT; \ array->size = 0; \ if (array->max_size_log == 0) { \ array->elements = NULL; \ return 0; \ } \ array->elements = malloc((1 << array->max_size_log) * sizeof(T)); \ if (!array->elements) \ return -1; \ return 0; \ } \ \ int \ NAME ## _finalize(NAME ## _t * array) \ { \ for (unsigned i = 0; i < array->size; i++) { \ NAME ## _remove_index(array, i, NULL); \ } \ return 0; \ } \ \ NAME ## _t * \ NAME ## _create() \ { \ NAME ## _t * array = malloc(sizeof(NAME ## _t)); \ if (!array) \ goto ERR_MALLOC; \ \ if (NAME ## _initialize(array) < 0) \ goto ERR_INITIALIZE; \ \ return array; \ \ ERR_INITIALIZE: \ free(array); \ ERR_MALLOC: \ return NULL; \ } \ \ void \ NAME ## _free(NAME ## _t * array) \ { \ NAME ## _finalize(array); \ free(array->elements); \ free(array); \ } \ \ int \ NAME ## _add(NAME ## _t * array, T element) \ { \ /* Ensure sufficient space for next addition */ \ size_t new_size_log = (array->size > 0) ? log2(array->size)+1 : 1; \ if (new_size_log > array->max_size_log) { \ array->max_size_log = new_size_log; \ array->elements = realloc(array->elements, \ (1 << new_size_log) * sizeof(T)); \ } \ \ if (!array->elements) \ goto ERR_REALLOC; \ \ array->elements[array->size++] = element; \ return 0; \ \ ERR_REALLOC: \ return -1; \ } \ \ int \ NAME ## _remove_index(NAME ## _t * array, int index, T * element) \ { \ if (index > NAME ## _len(array)) \ return -1; \ if (element) \ *element = array->elements[index]; \ if (index < array->size) \ memmove(array->elements + index, array->elements + index + 1, \ array->size - index); \ array->size--; \ return 0; \ } \ \ int \ NAME ## _remove(NAME ## _t * array, const T search, T * element) \ { \ for (unsigned i = 0; i < array->size; i++) { \ if (CMP(search, array->elements[i]) == 0) \ return facelet_array_remove_index(array, i, element); \ } \ /* Not found */ \ if (element) \ *element = NULL; \ return 0; \ } \ \ int \ NAME ## _get(const NAME ## _t * array, const T search, T * element) \ { \ assert(element); \ for (unsigned i = 0; i < array->size; i++) \ if (CMP(search, array->elements[i]) == 0) { \ *element = array->elements[i]; \ return 0; \ } \ /* Not found */ \ *element = NULL; \ return 0; \ } \ \ int \ NAME ## _get_index(const NAME ## _t * array, int index, T * element) \ { \ assert(element); \ *element = array->elements[index]; \ return 0; \ } \ \ int \ NAME ## _get_elements(const NAME ## _t * array, T ** elements) \ { \ *elements = array->elements; \ return 0; \ } \ \ size_t \ NAME ## _len(const NAME ## _t * array) \ { \ return array->size; \ } #endif /* UTIL_ARRAY_H */