[core] more memory-efficient fn table for data_*

save 40 bytes (64-bit), or 16 bytes (32-bit) per data_* element
at the cost of going through indirect function pointer to execute
methods.  At runtime, the reset() method is most used among them.
This commit is contained in:
Glenn Strauss 2018-09-22 22:12:51 -04:00
parent 002a4c524d
commit 8c7f1dfb03
10 changed files with 90 additions and 69 deletions

View File

@ -34,7 +34,7 @@ array *array_init_array(array *src) {
a->data = malloc(sizeof(*src->data) * src->size);
force_assert(NULL != a->data);
for (i = 0; i < src->size; i++) {
if (src->data[i]) a->data[i] = src->data[i]->copy(src->data[i]);
if (src->data[i]) a->data[i] = src->data[i]->fn->copy(src->data[i]);
else a->data[i] = NULL;
}
@ -49,7 +49,7 @@ void array_free(array *a) {
if (!a) return;
for (i = 0; i < a->size; i++) {
if (a->data[i]) a->data[i]->free(a->data[i]);
if (a->data[i]) a->data[i]->fn->free(a->data[i]);
}
if (a->data) free(a->data);
@ -63,7 +63,7 @@ void array_reset(array *a) {
if (!a) return;
for (i = 0; i < a->used; i++) {
a->data[i]->reset(a->data[i]);
a->data[i]->fn->reset(a->data[i]);
}
a->used = 0;
@ -277,7 +277,7 @@ static data_unset **array_find_or_insert(array *a, data_unset *entry) {
ndx = a->used;
/* make sure there is nothing here */
if (a->data[ndx]) a->data[ndx]->free(a->data[ndx]);
if (a->data[ndx]) a->data[ndx]->fn->free(a->data[ndx]);
a->data[a->used++] = entry;
@ -299,7 +299,7 @@ void array_replace(array *a, data_unset *entry) {
force_assert(NULL != entry);
if (NULL != (old = array_find_or_insert(a, entry))) {
force_assert(*old != entry);
(*old)->free(*old);
(*old)->fn->free(*old);
*old = entry;
}
}
@ -310,7 +310,7 @@ void array_insert_unique(array *a, data_unset *entry) {
force_assert(NULL != entry);
if (NULL != (old = array_find_or_insert(a, entry))) {
force_assert((*old)->type == entry->type);
entry->insert_dup(*old, entry);
entry->fn->insert_dup(*old, entry);
}
}
@ -551,7 +551,7 @@ int array_print(array *a, int depth) {
if (i != 0) {
fprintf(stdout, ", ");
}
du->print(du, depth + 1);
du->fn->print(du, depth + 1);
}
fprintf(stdout, ")");
return 0;
@ -575,7 +575,7 @@ int array_print(array *a, int depth) {
}
fprintf(stdout, " => ");
}
du->print(du, depth + 1);
du->fn->print(du, depth + 1);
fprintf(stdout, ",\n");
}
if (!(i && (i - 1 % 5) == 0)) {

View File

@ -4,16 +4,22 @@
#include "buffer.h"
struct data_unset; /* declaration */
struct data_methods {
void (*reset)(struct data_unset *p); \
struct data_unset *(*copy)(const struct data_unset *src); \
void (*free)(struct data_unset *p); \
int (*insert_dup)(struct data_unset *dst, struct data_unset *src); \
void (*print)(const struct data_unset *p, int depth);
};
typedef enum { TYPE_UNSET, TYPE_STRING, TYPE_OTHER, TYPE_ARRAY, TYPE_INTEGER, TYPE_DONOTUSE, TYPE_CONFIG } data_type_t;
#define DATA_UNSET \
data_type_t type; \
buffer *key; \
data_type_t type; \
int is_index_key; /* 1 if key is a array index (autogenerated keys) */ \
struct data_unset *(*copy)(const struct data_unset *src); \
void (* free)(struct data_unset *p); \
void (* reset)(struct data_unset *p); \
int (*insert_dup)(struct data_unset *dst, struct data_unset *src); \
void (*print)(const struct data_unset *p, int depth)
const struct data_methods *fn /* function table */
typedef struct data_unset {
DATA_UNSET;

View File

@ -57,7 +57,7 @@ int config_insert_values_internal(server *srv, array *ca, const config_values_t
for (j = 0; j < da->value->used; j++) {
data_unset *ds = da->value->data[j];
if (ds->type == TYPE_STRING || ds->type == TYPE_INTEGER || ds->type == TYPE_ARRAY) {
array_insert_unique(cv[i].destination, ds->copy(ds));
array_insert_unique(cv[i].destination, ds->fn->copy(ds));
} else {
log_error_write(srv, __FILE__, __LINE__, "sssbsd",
"the value of an array can only be a string, variable:",

View File

@ -52,7 +52,7 @@ static data_unset *configparser_get_variable(config_t *ctx, const buffer *key) {
array_print(dc->value, 0);
#endif
if (NULL != (du = array_get_element_klen(dc->value, CONST_BUF_LEN(key)))) {
du = du->copy(du);
du = du->fn->copy(du);
buffer_reset(du->key);
return du;
}
@ -74,11 +74,11 @@ data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2) {
data_string *ds = data_string_init();
buffer_append_int(ds->value, ((data_integer*)op1)->value);
buffer_append_string_buffer(ds->value, ((data_string*)op2)->value);
op1->free(op1);
op1->fn->free(op1);
return (data_unset *)ds;
} else {
fprintf(stderr, "data type mismatch, cannot merge\n");
op1->free(op1);
op1->fn->free(op1);
return NULL;
}
}
@ -100,10 +100,10 @@ data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2) {
du = (data_unset *)src->data[i];
if (du) {
if (du->is_index_key || buffer_is_empty(du->key) || !array_get_element_klen(dst, CONST_BUF_LEN(du->key))) {
array_insert_unique(dst, du->copy(du));
array_insert_unique(dst, du->fn->copy(du));
} else {
fprintf(stderr, "Duplicate array-key '%s'\n", du->key->ptr);
op1->free(op1);
op1->fn->free(op1);
return NULL;
}
}
@ -174,9 +174,9 @@ metaline ::= EOL.
%type cond {config_cond_t }
%destructor value { if ($$) $$->free($$); }
%destructor expression { if ($$) $$->free($$); }
%destructor aelement { if ($$) $$->free($$); }
%destructor value { if ($$) $$->fn->free($$); }
%destructor expression { if ($$) $$->fn->free($$); }
%destructor aelement { if ($$) $$->fn->free($$); }
%destructor aelements { array_free($$); }
%destructor array { array_free($$); }
%destructor key { buffer_free($$); }
@ -205,7 +205,7 @@ varline ::= key(A) ASSIGN expression(B). {
}
buffer_free(A);
A = NULL;
if (B) B->free(B);
if (B) B->fn->free(B);
B = NULL;
}
@ -224,7 +224,7 @@ varline ::= key(A) FORCE_ASSIGN expression(B). {
}
buffer_free(A);
A = NULL;
if (B) B->free(B);
if (B) B->fn->free(B);
B = NULL;
}
@ -255,7 +255,7 @@ varline ::= key(A) APPEND expression(B). {
}
buffer_free(A);
A = NULL;
if (B) B->free(B);
if (B) B->fn->free(B);
B = NULL;
}
@ -280,9 +280,9 @@ expression(A) ::= expression(B) PLUS value(C). {
ctx->ok = 0;
}
}
if (B) B->free(B);
if (B) B->fn->free(B);
B = NULL;
if (C) C->free(C);
if (C) C->fn->free(C);
C = NULL;
}
@ -369,7 +369,7 @@ aelements(A) ::= aelements(C) COMMA aelement(B). {
}
array_free(C);
C = NULL;
if (B) B->free(B);
if (B) B->fn->free(B);
B = NULL;
}
@ -385,7 +385,7 @@ aelements(A) ::= aelement(B). {
array_insert_unique(A, B);
B = NULL;
}
if (B) B->free(B);
if (B) B->fn->free(B);
B = NULL;
}
@ -401,7 +401,7 @@ aelement(A) ::= stringop(B) ARRAY_ASSIGN expression(C). {
A = C;
C = NULL;
}
if (C) C->free(C);
if (C) C->fn->free(C);
C = NULL;
buffer_free(B);
B = NULL;
@ -493,7 +493,7 @@ condlines(A) ::= condlines(B) eols ELSE cond_else(C). {
} else {
fprintf(stderr, "unreachable else condition\n");
ctx->ok = 0;
C->free((data_unset *)C);
C->fn->free((data_unset *)C);
C = dc;
}
@ -715,7 +715,7 @@ context ::= DOLLAR SRVVARNAME(B) LBRACKET stringop(C) RBRACKET cond(E) expressio
if (ctx->ok) {
configparser_push(ctx, dc, 1);
} else {
dc->free((data_unset*) dc);
dc->fn->free((data_unset*) dc);
}
}
}
@ -726,7 +726,7 @@ context ::= DOLLAR SRVVARNAME(B) LBRACKET stringop(C) RBRACKET cond(E) expressio
B = NULL;
buffer_free(C);
C = NULL;
if (D) D->free(D);
if (D) D->fn->free(D);
D = NULL;
}
@ -768,7 +768,7 @@ stringop(A) ::= expression(B). {
ctx->ok = 0;
}
}
if (B) B->free(B);
if (B) B->fn->free(B);
B = NULL;
}

View File

@ -36,7 +36,7 @@ static void data_array_reset(data_unset *d) {
static int data_array_insert_dup(data_unset *dst, data_unset *src) {
UNUSED(dst);
src->free(src);
src->fn->free(src);
return 0;
}
@ -48,6 +48,13 @@ static void data_array_print(const data_unset *d, int depth) {
}
data_array *data_array_init(void) {
static const struct data_methods fn = {
data_array_reset,
data_array_copy,
data_array_free,
data_array_insert_dup,
data_array_print,
};
data_array *ds;
ds = calloc(1, sizeof(*ds));
@ -56,12 +63,8 @@ data_array *data_array_init(void) {
ds->key = buffer_init();
ds->value = array_init();
ds->copy = data_array_copy;
ds->free = data_array_free;
ds->reset = data_array_reset;
ds->insert_dup = data_array_insert_dup;
ds->print = data_array_print;
ds->type = TYPE_ARRAY;
ds->fn = &fn;
return ds;
}

View File

@ -58,7 +58,7 @@ static void data_config_reset(data_unset *d) {
static int data_config_insert_dup(data_unset *dst, data_unset *src) {
UNUSED(dst);
src->free(src);
src->fn->free(src);
return 0;
}
@ -96,7 +96,7 @@ static void data_config_print(const data_unset *d, int depth) {
fprintf(stdout, " ");
}
fprintf(stdout, " = ");
du->print(du, depth);
du->fn->print(du, depth);
fprintf(stdout, "\n");
}
@ -108,7 +108,7 @@ static void data_config_print(const data_unset *d, int depth) {
if (NULL == dc->prev) {
fprintf(stdout, "\n");
array_print_indent(depth);
dc->print((data_unset *) dc, depth);
dc->fn->print((data_unset *) dc, depth);
fprintf(stdout, "\n");
}
}
@ -129,11 +129,18 @@ static void data_config_print(const data_unset *d, int depth) {
fprintf(stdout, "\n");
array_print_indent(depth);
fprintf(stdout, "else ");
ds->next->print((data_unset *)ds->next, depth);
ds->next->fn->print((data_unset *)ds->next, depth);
}
}
data_config *data_config_init(void) {
static const struct data_methods fn = {
data_config_reset,
data_config_copy,
data_config_free,
data_config_insert_dup,
data_config_print,
};
data_config *ds;
ds = calloc(1, sizeof(*ds));
@ -145,12 +152,8 @@ data_config *data_config_init(void) {
ds->value = array_init();
vector_config_weak_init(&ds->children);
ds->copy = data_config_copy;
ds->free = data_config_free;
ds->reset = data_config_reset;
ds->insert_dup = data_config_insert_dup;
ds->print = data_config_print;
ds->type = TYPE_CONFIG;
ds->fn = &fn;
return ds;
}

View File

@ -35,7 +35,7 @@ static void data_integer_reset(data_unset *d) {
static int data_integer_insert_dup(data_unset *dst, data_unset *src) {
UNUSED(dst);
src->free(src);
src->fn->free(src);
return 0;
}
@ -49,6 +49,13 @@ static void data_integer_print(const data_unset *d, int depth) {
data_integer *data_integer_init(void) {
static const struct data_methods fn = {
data_integer_reset,
data_integer_copy,
data_integer_free,
data_integer_insert_dup,
data_integer_print,
};
data_integer *ds;
ds = calloc(1, sizeof(*ds));
@ -57,12 +64,8 @@ data_integer *data_integer_init(void) {
ds->key = buffer_init();
ds->value = 0;
ds->copy = data_integer_copy;
ds->free = data_integer_free;
ds->reset = data_integer_reset;
ds->insert_dup = data_integer_insert_dup;
ds->print = data_integer_print;
ds->type = TYPE_INTEGER;
ds->fn = &fn;
return ds;
}

View File

@ -44,7 +44,7 @@ static int data_string_insert_dup(data_unset *dst, data_unset *src) {
buffer_copy_buffer(ds_dst->value, ds_src->value);
}
src->free(src);
src->fn->free(src);
return 0;
}
@ -76,6 +76,13 @@ static void data_string_print(const data_unset *d, int depth) {
data_string *data_string_init(void) {
static const struct data_methods fn = {
data_string_reset,
data_string_copy,
data_string_free,
data_string_insert_dup,
data_string_print,
};
data_string *ds;
ds = calloc(1, sizeof(*ds));
@ -84,12 +91,8 @@ data_string *data_string_init(void) {
ds->key = buffer_init();
ds->value = buffer_init();
ds->copy = data_string_copy;
ds->free = data_string_free;
ds->reset = data_string_reset;
ds->insert_dup = data_string_insert_dup;
ds->print = data_string_print;
ds->type = TYPE_STRING;
ds->fn = &fn;
return ds;
}

View File

@ -95,14 +95,17 @@ static void data_auth_free(data_unset *d)
static data_auth *data_auth_init(void)
{
static const struct data_methods fn = {
NULL, /* reset must not be called on this data */
NULL, /* copy must not be called on this data */
data_auth_free,
NULL, /* insert_dup must not be called on this data */
NULL /* print must not be called on this data */
};
data_auth * const dauth = calloc(1, sizeof(*dauth));
force_assert(NULL != dauth);
dauth->copy = NULL; /* must not be called on this data */
dauth->free = data_auth_free;
dauth->reset = NULL; /* must not be called on this data */
dauth->insert_dup = NULL; /* must not be called on this data */
dauth->print = NULL; /* must not be called on this data */
dauth->type = TYPE_OTHER;
dauth->fn = &fn;
dauth->key = buffer_init();
dauth->require = http_auth_require_init();
@ -327,7 +330,7 @@ SETDEFAULTS_FUNC(mod_auth_set_defaults) {
dauth->require->scheme = auth_scheme;
buffer_copy_buffer(dauth->require->realm, realm);
if (!mod_auth_require_parse(srv, dauth->require, require)) {
dauth->free((data_unset *)dauth);
dauth->fn->free((data_unset *)dauth);
return HANDLER_ERROR;
}
array_insert_unique(s->auth_require, (data_unset *)dauth);

View File

@ -1055,7 +1055,7 @@ static int server_main (server * const srv, int argc, char **argv) {
if (print_config) {
data_unset *dc = srv->config_context->data[0];
if (dc) {
dc->print(dc, 0);
dc->fn->print(dc, 0);
fprintf(stdout, "\n");
} else {
/* shouldn't happend */