add file src/tests/test_sorted_array.c

pull/37/merge
YuQing 2021-09-13 16:54:09 +08:00
parent 2993b34e80
commit 55f1e139a9
7 changed files with 331 additions and 63 deletions

1
.gitignore vendored
View File

@ -58,6 +58,7 @@ src/tests/test_pthread_wait
src/tests/test_mutex_lock_perf
src/tests/test_queue_perf
src/tests/test_normalize_path
src/tests/test_sorted_array
# other
*.swp

View File

@ -71,6 +71,7 @@ extern "C" {
int array_compare_element_int32(const int32_t *n1, const int32_t *n2);
#define i64_array_allocator_init(ctx, min_bits, max_bits) \
array_allocator_init(ctx, "i64", sizeof(int64_t), min_bits, max_bits)
@ -84,6 +85,19 @@ extern "C" {
array_allocator_free(ctx, (VoidArray *)array)
#define i32_array_allocator_init(ctx, min_bits, max_bits) \
array_allocator_init(ctx, "i32", sizeof(int32_t), min_bits, max_bits)
#define i32_array_allocator_alloc(ctx, target_count) \
(I32Array *)array_allocator_alloc(ctx, target_count)
#define i32_array_allocator_realloc(ctx, old_array, target_count) \
(I32Array *)array_allocator_realloc(ctx, (VoidArray *)old_array, target_count)
#define i32_array_allocator_free(ctx, array) \
array_allocator_free(ctx, (VoidArray *)array)
#ifdef __cplusplus
}
#endif

View File

@ -148,14 +148,13 @@ static int region_init(struct fast_allocator_context *acontext,
int result;
int bytes;
int element_size;
int allocator_count;
struct fast_allocator_info *allocator;
char *name;
char name_buff[FAST_MBLOCK_NAME_SIZE];
region->pad_mask = region->step - 1;
allocator_count = (region->end - region->start) / region->step;
bytes = sizeof(struct fast_allocator_info) * allocator_count;
region->count = (region->end - region->start) / region->step;
bytes = sizeof(struct fast_allocator_info) * region->count;
region->allocators = (struct fast_allocator_info *)fc_malloc(bytes);
if (region->allocators == NULL)
{
@ -163,7 +162,7 @@ static int region_init(struct fast_allocator_context *acontext,
}
memset(region->allocators, 0, bytes);
if ((result=allocator_array_check_capacity(acontext, allocator_count)) != 0)
if ((result=allocator_array_check_capacity(acontext, region->count)) != 0)
{
return result;
}
@ -171,7 +170,8 @@ static int region_init(struct fast_allocator_context *acontext,
name = name_buff;
result = 0;
allocator = region->allocators;
for (element_size=region->start+region->step; element_size<=region->end;
for (element_size = region->start + region->step;
element_size <= region->end;
element_size += region->step, allocator++)
{
if (mblock_name_prefix != NULL)
@ -276,10 +276,21 @@ int fast_allocator_init_ex(struct fast_allocator_context *acontext,
result = EINVAL;
break;
}
if (pRegion->step <= 0 || !is_power2(pRegion->step))
if (pRegion->step <= 0)
{
logError("file: "__FILE__", line: %d, "
"invalid step: %d",
"invalid step: %d <= 0",
__LINE__, pRegion->step);
result = EINVAL;
break;
}
if ((pRegion->end - pRegion->start) / pRegion->step > 1)
{
if (!is_power2(pRegion->step))
{
logError("file: "__FILE__", line: %d, "
"invalid step: %d, expect power of 2",
__LINE__, pRegion->step);
result = EINVAL;
break;
@ -299,6 +310,7 @@ int fast_allocator_init_ex(struct fast_allocator_context *acontext,
__LINE__, pRegion->end, pRegion->step);
result = EINVAL;
break;
}
}
previous_end = pRegion->end;
@ -368,8 +380,8 @@ void fast_allocator_destroy(struct fast_allocator_context *acontext)
memset(acontext, 0, sizeof(*acontext));
}
static struct fast_allocator_info *get_allocator(struct fast_allocator_context *acontext,
int *alloc_bytes)
static struct fast_allocator_info *get_allocator(struct fast_allocator_context
*acontext, int *alloc_bytes)
{
struct fast_region_info *pRegion;
struct fast_region_info *region_end;
@ -379,11 +391,16 @@ static struct fast_allocator_info *get_allocator(struct fast_allocator_context *
{
if (*alloc_bytes <= pRegion->end)
{
if (pRegion->count == 1) {
*alloc_bytes = pRegion->allocators[0].mblock.info.element_size;
return pRegion->allocators + 0;
} else {
*alloc_bytes = BYTES_ALIGN(*alloc_bytes, pRegion->pad_mask);
return pRegion->allocators + ((*alloc_bytes -
pRegion->start) / pRegion->step) - 1;
}
}
}
return &malloc_allocator;
}
@ -513,7 +530,8 @@ void fast_allocator_free(struct fast_allocator_context *acontext, void *ptr)
return;
}
allocator_info = acontext->allocator_array.allocators[pWrapper->allocator_index];
allocator_info = acontext->allocator_array.
allocators[pWrapper->allocator_index];
if (pWrapper->magic_number != allocator_info->magic_number)
{
logError("file: "__FILE__", line: %d, "
@ -532,7 +550,8 @@ void fast_allocator_free(struct fast_allocator_context *acontext, void *ptr)
}
else
{
fast_allocator_malloc_trunk_notify_func(-1 * pWrapper->alloc_bytes, acontext);
fast_allocator_malloc_trunk_notify_func(-1 *
pWrapper->alloc_bytes, acontext);
free(obj);
}
}

View File

@ -40,6 +40,7 @@ struct fast_region_info
int step;
int alloc_elements_once;
int pad_mask; //for internal use
int count;
struct fast_allocator_info *allocators;
};

View File

@ -25,25 +25,28 @@ void sorted_array_init(SortedArrayContext *ctx,
ctx->compare_func = compare_func;
}
static void *sorted_array_bsearch(SortedArrayContext *ctx, void *base,
static char *sorted_array_bsearch(SortedArrayContext *ctx, char *base,
const int count, const void *element, int *insert_pos)
{
int low;
int high;
int mid;
int compr;
char *current;
*insert_pos = 0;
low = 0;
high = count - 1;
while (low <= high) {
mid = (low + high) / 2;
compr = ctx->compare_func(base + mid, element);
current = base + ctx->element_size * mid;
compr = ctx->compare_func(current, element);
if (compr < 0) {
low = mid + 1;
*insert_pos = low;
} else if (compr == 0) {
return base + mid;
*insert_pos = mid;
return current;
} else {
high = mid - 1;
*insert_pos = mid;
@ -58,8 +61,9 @@ int sorted_array_insert(SortedArrayContext *ctx,
{
int insert_pos;
int move_count;
void *found;
void *end;
char *current;
char *found;
char *end;
found = sorted_array_bsearch(ctx, base, *count, element, &insert_pos);
if (found != NULL) {
@ -67,20 +71,39 @@ int sorted_array_insert(SortedArrayContext *ctx,
return EEXIST;
}
found++;
end = base + *count;
found += ctx->element_size;
end = (char *)base + ctx->element_size * (*count);
while (found < end && ctx->compare_func(found, element) == 0) {
found++;
insert_pos++;
found += ctx->element_size;
}
insert_pos = found - base;
}
current = (char *)base + ctx->element_size * insert_pos;
move_count = *count - insert_pos;
if (move_count > 0) {
memmove(base + insert_pos + 1, base + insert_pos,
ctx->element_size * move_count);
memmove((char *)base + ctx->element_size * (insert_pos + 1),
current, ctx->element_size * move_count);
}
memcpy(base + insert_pos, element, ctx->element_size);
switch (ctx->element_size) {
case 1:
*current = *((char *)element);
break;
case 2:
*((short *)current) = *((short *)element);
break;
case 4:
*((int32_t *)current) = *((int32_t *)element);
break;
case 8:
*((int64_t *)current) = *((int64_t *)element);
break;
default:
memcpy(current, element, ctx->element_size);
break;
}
(*count)++;
return 0;
}
@ -90,11 +113,11 @@ int sorted_array_delete(SortedArrayContext *ctx,
{
int move_count;
struct {
void *current;
void *start;
void *end;
char *current;
char *start;
char *end;
} found;
void *array_end;
char *array_end;
if ((found.current=bsearch(element, base, *count, ctx->element_size,
ctx->compare_func)) == NULL)
@ -102,29 +125,29 @@ int sorted_array_delete(SortedArrayContext *ctx,
return ENOENT;
}
array_end = base + *count;
array_end = (char *)base + ctx->element_size * (*count);
if (ctx->allow_duplicate) {
found.start = found.current;
while (found.start > base && ctx->compare_func(
found.start - 1, element) == 0)
while (found.start > (char *)base && ctx->compare_func(
found.start - ctx->element_size, element) == 0)
{
found.start--;
found.start -= ctx->element_size;
}
found.end = ++found.current;
found.end = found.current + ctx->element_size;
while (found.end < array_end && ctx->compare_func(
found.end, element) == 0)
{
found.end++;
found.end += ctx->element_size;
}
*count -= found.end - found.start;
*count -= (found.end - found.start) / ctx->element_size;
} else {
found.start = found.current;
found.end = found.start + 1;
found.end = found.start + ctx->element_size;
(*count)--;
}
move_count = array_end - found.end;
move_count = (array_end - found.end) / ctx->element_size;
if (move_count > 0) {
memmove(found.start, found.end, ctx->
element_size * move_count);

View File

@ -10,7 +10,7 @@ ALL_PRGS = test_allocator test_skiplist test_multi_skiplist test_mblock test_blo
test_json_parser test_pthread_lock test_uniq_skiplist test_split_string \
test_server_id_func test_pipe test_atomic test_file_write_hole test_file_lock \
test_pthread_wait test_thread_pool test_data_visible test_mutex_lock_perf \
test_queue_perf test_normalize_path
test_queue_perf test_normalize_path test_sorted_array
all: $(ALL_PRGS)
.c:

View File

@ -0,0 +1,210 @@
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the Lesser GNU General Public License, version 3
* or later ("LGPL"), as published by the Free Software Foundation.
*
* 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.
*
* You should have received a copy of the Lesser GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <inttypes.h>
#include <sys/time.h>
#include <assert.h>
#include "fastcommon/logger.h"
#include "fastcommon/shared_func.h"
#include "fastcommon/array_allocator.h"
#include "fastcommon/sorted_array.h"
#define ELEMENT_COUNT 5 * 1000
static bool silence;
static int test_i64()
{
const int min_bits = 2;
const int max_bits = 16;
const bool allow_duplicate = false;
int result;
int i;
int index;
int last_index;
int64_t tmp;
int64_t start_time;
ArrayAllocatorContext allocator_ctx;
SortedArrayContext sarray_ctx;
I64Array *input;
I64Array *output;
start_time = get_current_time_us();
sorted_i64_array_init(&sarray_ctx, allow_duplicate);
if ((result=i64_array_allocator_init(&allocator_ctx,
min_bits, max_bits)) != 0)
{
return result;
}
if ((input=i64_array_allocator_alloc(&allocator_ctx,
ELEMENT_COUNT)) == NULL)
{
return ENOMEM;
}
if ((output=i64_array_allocator_alloc(&allocator_ctx,
ELEMENT_COUNT)) == NULL)
{
return ENOMEM;
}
input->count = ELEMENT_COUNT;
for (i=0; i<input->count; i++) {
input->elts[i] = i + 1;
}
last_index = ELEMENT_COUNT - 1;
for (i=0; i<input->count; i++) {
index = (int64_t)rand() * last_index / (int64_t)RAND_MAX;
tmp = input->elts[index];
input->elts[index] = input->elts[last_index - index];
input->elts[last_index - index] = tmp;
}
for (i=0; i<input->count; i++) {
sorted_array_insert(&sarray_ctx, output->elts,
&output->count, input->elts + i);
}
assert(output->count == ELEMENT_COUNT);
for (i=0; i<output->count; i++) {
assert(output->elts[i] == i + 1);
}
for (i=last_index; i>=0; i--) {
sorted_array_delete(&sarray_ctx, output->elts,
&output->count, input->elts + i);
}
assert(output->count == 0);
i64_array_allocator_free(&allocator_ctx, input);
i64_array_allocator_free(&allocator_ctx, output);
if (!silence) {
printf("test i64 time used: %"PRId64" us\n",
get_current_time_us() - start_time);
}
return 0;
}
static int test_i32()
{
const int min_bits = 2;
const int max_bits = 16;
const bool allow_duplicate = false;
int result;
int i;
int index;
int last_index;
int32_t tmp;
int64_t start_time;
ArrayAllocatorContext allocator_ctx;
SortedArrayContext sarray_ctx;
I32Array *input;
I32Array *output;
start_time = get_current_time_us();
sorted_i32_array_init(&sarray_ctx, allow_duplicate);
if ((result=i32_array_allocator_init(&allocator_ctx,
min_bits, max_bits)) != 0)
{
return result;
}
if ((input=i32_array_allocator_alloc(&allocator_ctx,
ELEMENT_COUNT)) == NULL)
{
return ENOMEM;
}
if ((output=i32_array_allocator_alloc(&allocator_ctx,
ELEMENT_COUNT)) == NULL)
{
return ENOMEM;
}
input->count = ELEMENT_COUNT;
for (i=0; i<input->count; i++) {
input->elts[i] = i + 1;
}
last_index = ELEMENT_COUNT - 1;
for (i=0; i<input->count; i++) {
index = (int64_t)rand() * last_index / (int64_t)RAND_MAX;
tmp = input->elts[index];
input->elts[index] = input->elts[last_index - index];
input->elts[last_index - index] = tmp;
}
for (i=0; i<input->count; i++) {
sorted_array_insert(&sarray_ctx, output->elts,
&output->count, input->elts + i);
}
assert(output->count == ELEMENT_COUNT);
for (i=0; i<output->count; i++) {
assert(output->elts[i] == i + 1);
}
for (i=last_index; i>=0; i--) {
sorted_array_delete(&sarray_ctx, output->elts,
&output->count, input->elts + i);
}
assert(output->count == 0);
i32_array_allocator_free(&allocator_ctx, input);
i32_array_allocator_free(&allocator_ctx, output);
if (!silence) {
printf("test i32 time used: %"PRId64" us\n",
get_current_time_us() - start_time);
}
return 0;
}
int main(int argc, char *argv[])
{
int result;
int ch;
srand(time(NULL));
log_init();
while ((ch=getopt(argc, argv, "s")) != -1) {
switch (ch) {
case 's':
silence = true;
break;
default:
break;
}
}
if ((result=test_i64()) != 0) {
return result;
}
if ((result=test_i32()) != 0) {
return result;
}
return 0;
}