diff --git a/elem.h b/elem.h index 06f2accc..5a91af36 100644 --- a/elem.h +++ b/elem.h @@ -23,6 +23,7 @@ #include "tommyhash.h" #include "tommyhashdyn.h" #include "tommyarray.h" +#include "tommyarrayof.h" /****************************************************************************/ /* snapraid */ diff --git a/state.c b/state.c index 34b1004c..620b6fab 100644 --- a/state.c +++ b/state.c @@ -54,7 +54,7 @@ void state_init(struct snapraid_state* state) tommy_list_init(&state->filterlist); tommy_list_init(&state->importlist); tommy_hashdyn_init(&state->importset); - tommy_array_init(&state->infoarr); + tommy_arrayof_init(&state->infoarr, sizeof(snapraid_info)); state->loaded_blockmax = 0; } @@ -66,7 +66,7 @@ void state_done(struct snapraid_state* state) tommy_list_foreach(&state->filterlist, (tommy_foreach_func*)filter_free); tommy_list_foreach(&state->importlist, (tommy_foreach_func*)import_file_free); tommy_hashdyn_done(&state->importset); - tommy_array_done(&state->infoarr); + tommy_arrayof_done(&state->infoarr); } /** @@ -1040,8 +1040,8 @@ void state_read(struct snapraid_state* state) info = info_make(t); /* insert the block in the block array */ - tommy_array_grow(&state->infoarr, v_pos + 1); - tommy_array_set(&state->infoarr, v_pos, (void*)info); + tommy_arrayof_grow(&state->infoarr, v_pos + 1); + memcpy(tommy_arrayof_ref(&state->infoarr, v_pos), &info, sizeof(snapraid_info)); } else if (strcmp(tag, "off") == 0) { /* "off" command */ block_off_t v_pos; @@ -1964,14 +1964,14 @@ void state_write(struct snapraid_state* state) /* tha could be smaller than of blocks we have in memory, in case of deleted blocks */ /* don't try to write more info than stored */ - if (infomax > tommy_array_size(&state->infoarr)) - infomax = tommy_array_size(&state->infoarr); + if (infomax > tommy_arrayof_size(&state->infoarr)) + infomax = tommy_arrayof_size(&state->infoarr); /* for each block */ for(b=0;binfoarr, b); + memcpy(&info, tommy_arrayof_ref(&state->infoarr, b), sizeof(snapraid_info)); /* save only stuff different than 0 */ if (info != 0) { diff --git a/state.h b/state.h index 2a9955ad..312bc27c 100644 --- a/state.h +++ b/state.h @@ -62,7 +62,7 @@ struct snapraid_state { tommy_list filterlist; /**< List of inclusion/exclusion. */ tommy_list importlist; /**< List of import file. */ tommy_hashdyn importset; /**< Hashtable by hash of all the import blocks. */ - tommy_array infoarr; /**< Block information array. */ + tommy_arrayof infoarr; /**< Block information array. */ block_off_t loaded_blockmax; /**< Previous size of the parity file, computed from the loaded state. */ time_t progress_start; /**< Start of processing for progress visualization. */ time_t progress_last; /**< Last update of progress visualization. */ diff --git a/tommy.c b/tommy.c index ec8a8a1f..00ded3e6 100644 --- a/tommy.c +++ b/tommy.c @@ -28,4 +28,5 @@ #include "tommyhash.c" #include "tommyhashdyn.c" #include "tommyarray.c" +#include "tommyarrayof.c" diff --git a/tommyarray.c b/tommyarray.c index e151b57e..3f39614f 100644 --- a/tommyarray.c +++ b/tommyarray.c @@ -73,6 +73,6 @@ void tommy_array_grow(tommy_array* array, unsigned size) tommy_size_t tommy_array_memory_usage(tommy_array* array) { - return array->bucket_max * (tommy_size_t)sizeof(array->bucket[0][0]); + return array->bucket_max * (tommy_size_t)sizeof(void*); } diff --git a/tommyarray.h b/tommyarray.h index 82b2e288..499547a5 100644 --- a/tommyarray.h +++ b/tommyarray.h @@ -114,9 +114,9 @@ tommy_inline void** tommy_array_ref(tommy_array* array, unsigned pos) * You must be sure that space for this position is already * allocated calling tommy_array_grow(). */ -tommy_inline void tommy_array_set(tommy_array* array, unsigned pos, void* node) +tommy_inline void tommy_array_set(tommy_array* array, unsigned pos, void* element) { - *tommy_array_ref(array, pos) = node; + *tommy_array_ref(array, pos) = element; } /** @@ -132,13 +132,13 @@ tommy_inline void* tommy_array_get(tommy_array* array, unsigned pos) /** * Grows and inserts a new element at the end of the array. */ -tommy_inline void tommy_array_insert(tommy_array* array, void* node) +tommy_inline void tommy_array_insert(tommy_array* array, void* element) { unsigned pos = array->size; tommy_array_grow(array, pos + 1); - tommy_array_set(array, pos, node); + tommy_array_set(array, pos, element); } /** diff --git a/tommyarrayof.c b/tommyarrayof.c new file mode 100644 index 00000000..7656309f --- /dev/null +++ b/tommyarrayof.c @@ -0,0 +1,79 @@ +/* + * Copyright 2011 Andrea Mazzoleni. All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY ANDREA MAZZOLENI 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 ANDREA MAZZOLENI 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. + */ + +#include "tommyarrayof.h" + +#include /* for memset */ + +/******************************************************************************/ +/* array */ + +void tommy_arrayof_init(tommy_arrayof* array, unsigned element_size) +{ + /* fixed initial size */ + array->element_size = element_size; + array->bucket_bit = TOMMY_ARRAYOF_BIT; + array->bucket_max = 1 << array->bucket_bit; + array->bucket[0] = tommy_malloc(array->bucket_max * array->element_size); + + /* initializes it with zeros */ + memset(array->bucket[0], 0, array->bucket_max * array->element_size); + + array->bucket_mac = 1; + array->size = 0; +} + +void tommy_arrayof_done(tommy_arrayof* array) +{ + unsigned i; + for(i=0;ibucket_mac;++i) + tommy_free(array->bucket[i]); +} + +void tommy_arrayof_grow(tommy_arrayof* array, unsigned size) +{ + while (size > array->bucket_max) { + /* allocate one more bucket */ + array->bucket[array->bucket_mac] = tommy_malloc(array->bucket_max * array->element_size); + + /* initializes it with zeros */ + memset(array->bucket[array->bucket_mac], 0, array->bucket_max * array->element_size); + + ++array->bucket_mac; + ++array->bucket_bit; + array->bucket_max = 1 << array->bucket_bit; + } + + if (array->size < size) + array->size = size; +} + +tommy_size_t tommy_arrayof_memory_usage(tommy_arrayof* array) +{ + return array->bucket_max * (tommy_size_t)array->element_size; +} + diff --git a/tommyarrayof.h b/tommyarrayof.h new file mode 100644 index 00000000..9586d6af --- /dev/null +++ b/tommyarrayof.h @@ -0,0 +1,132 @@ +/* + * Copyright 2013 Andrea Mazzoleni. All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY ANDREA MAZZOLENI 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 ANDREA MAZZOLENI 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. + */ + +/** \file + * Dynamic array. + * + * This array is able to grow dynamically upon request. + * + * This is very similar at ::tommy_array, but it allows to store elements of any + * size and not just pointers. + * + * The resize involve an allocation of a new array segment, without reallocating + * the already allocated memory, and then not increasing the heap fragmentation. + * + * This means that the address of the allocated segments never change. + */ + +#ifndef __TOMMYARRAYOF_H +#define __TOMMYARRAYOF_H + +#include "tommytypes.h" + +#include /* for assert */ + +/******************************************************************************/ +/* array */ + +/** + * Initial and minimal size of the array expressed as a power of 2. + * The initial size is 2^TOMMY_ARRAYOF_BIT. + */ +#define TOMMY_ARRAYOF_BIT 6 + +/** \internal + * Max number of elements as a power of 2. + */ +#define TOMMY_ARRAYOF_BIT_MAX 32 + +/** + * Array. + */ +typedef struct tommy_arrayof_struct { + void* bucket[TOMMY_ARRAYOF_BIT_MAX]; /**< Dynamic array of buckets. */ + unsigned element_size; /**< Size of the stored element in bytes. */ + unsigned bucket_bit; /**< Bits used in the bit mask. */ + unsigned bucket_max; /**< Number of buckets. */ + unsigned bucket_mac; /**< Number of vectors allocated. */ + unsigned size; /**< Currently allocated and initialized size. */ +} tommy_arrayof; + +/** + * Initializes the array. + */ +void tommy_arrayof_init(tommy_arrayof* array, unsigned element_size); + +/** + * Deinitializes the array. + */ +void tommy_arrayof_done(tommy_arrayof* array); + +/** + * Grow the size up to the specified value. + * All the new elements in the array are initialized with the 0 value. + */ +void tommy_arrayof_grow(tommy_arrayof* array, unsigned size); + +/** + * Gets a reference of the element at the specified position. + * You must be sure that space for this position is already + * allocated calling tommy_arrayof_grow(). + */ +tommy_inline void* tommy_arrayof_ref(tommy_arrayof* array, unsigned pos) +{ + unsigned char* base; + + assert(pos < array->size); + + /* special case for the first bucket */ + if (pos < (1 << TOMMY_ARRAYOF_BIT)) { + base = array->bucket[0]; + } else { + /* get the highest bit set */ + unsigned bsr = tommy_ilog2_u32(pos); + + /* clear the highest bit */ + pos -= 1 << bsr; + + base = array->bucket[bsr - TOMMY_ARRAYOF_BIT + 1]; + } + + return base + pos * array->element_size; +} + +/** + * Gets the initialized size of the array. + */ +tommy_inline unsigned tommy_arrayof_size(tommy_arrayof* array) +{ + return array->size; +} + +/** + * Gets the size of allocated memory. + */ +tommy_size_t tommy_arrayof_memory_usage(tommy_arrayof* array); + +#endif +