diff --git a/src/driver/args.c b/src/driver/args.c index e5a5ba1..36146ba 100644 --- a/src/driver/args.c +++ b/src/driver/args.c @@ -15,7 +15,7 @@ */ static void yf_set_error(struct yf_args * args) { args->error = 1; - args->wanted_output = YF_ERROR; + args->wanted_output = YF_INFO_ERROR; } /** @@ -27,7 +27,7 @@ static void yf_set_error(struct yf_args * args) { * Check if the wanted action is not already set. */ static void yf_check_action(struct yf_args * args, enum yf_info_output out) { - if (args->wanted_output != YF_NONE) { + if (args->wanted_output != YF_INFO_NONE) { yf_set_error(args); } else { args->wanted_output = out; @@ -39,7 +39,7 @@ static void yf_check_action(struct yf_args * args, enum yf_info_output out) { */ static int yf_add_file(struct yf_args * args, char * file) { /* No actions allowed. e.g. : no "yfc --version foo.yf" */ - if (args->wanted_output != YF_NONE) { + if (args->wanted_output != YF_INFO_NONE) { yf_set_error(args); return 1; } @@ -48,7 +48,8 @@ static int yf_add_file(struct yf_args * args, char * file) { yf_set_error(args); return 1; } - yf_list_add(&args->files, file); + if (yf_list_add(&args->files, file) != YF_OK) + abort(); return 0; } @@ -63,9 +64,10 @@ void yf_parse_args(int argc, char ** argv, struct yf_args * args) { /* Zero the args structure. */ memset(args, 0, sizeof *args); - args->wanted_output = YF_NONE; + args->wanted_output = YF_INFO_NONE; args->run_c_comp = true; - yf_list_init(&args->files); + if (yf_list_init(&args->files) != YF_OK) + abort(); /* Start at 1 - avoid program name */ for (i = 1; i < argc; ++i) { @@ -110,12 +112,12 @@ void yf_parse_args(int argc, char ** argv, struct yf_args * args) { ++arg; if (!arg[1]) { if (arg[0] == 'h' || arg[0] == '?') { - yf_check_action(args, YF_HELP); + yf_check_action(args, YF_INFO_HELP); continue; } if (arg[0] == 'v') { - yf_check_action(args, YF_VERSION); + yf_check_action(args, YF_INFO_VERSION); continue; } } @@ -124,12 +126,12 @@ void yf_parse_args(int argc, char ** argv, struct yf_args * args) { ++arg; if (STREQ(arg, "help")) { - yf_check_action(args, YF_HELP); + yf_check_action(args, YF_INFO_HELP); continue; } if (STREQ(arg, "version")) { - yf_check_action(args, YF_VERSION); + yf_check_action(args, YF_INFO_VERSION); continue; } @@ -195,7 +197,7 @@ void yf_parse_args(int argc, char ** argv, struct yf_args * args) { } if (STREQ(arg, "benchmark")) { - if (args->profile || args->wanted_output != YF_NONE) { + if (args->profile || args->wanted_output != YF_INFO_NONE) { yf_set_error(args); return; } @@ -233,32 +235,32 @@ void yf_parse_args(int argc, char ** argv, struct yf_args * args) { } - if (args->wanted_output == YF_NONE && !args->project && yf_list_is_empty(&args->files)) { + if (args->wanted_output == YF_INFO_NONE && !args->project && yf_list_is_empty(&args->files)) { args->error = 1; - args->wanted_output = YF_ERROR_NO_ARGS; + args->wanted_output = YF_INFO_ERROR_NO_ARGS; } } bool yf_should_compile(struct yf_args * args) { - return args->wanted_output == YF_NONE; + return args->wanted_output == YF_INFO_NONE; } int yf_output_info(struct yf_args * args) { switch (args->wanted_output) { - case YF_NONE: + case YF_INFO_NONE: return 0; - case YF_VERSION: + case YF_INFO_VERSION: printf("%s", VERSION_MSG); return 0; - case YF_HELP: + case YF_INFO_HELP: printf("%s", USAGE_MSG); return 0; - case YF_ERROR: + case YF_INFO_ERROR: printf("%s", HELP_HINT_MSG); return 1; - case YF_ERROR_NO_ARGS: + case YF_INFO_ERROR_NO_ARGS: printf("%s", NO_ARGS_MSG); return 1; } diff --git a/src/driver/args.h b/src/driver/args.h index 5fd2b1b..3c565f4 100644 --- a/src/driver/args.h +++ b/src/driver/args.h @@ -13,11 +13,11 @@ * Any of the possible outputs wanted. */ enum yf_info_output { - YF_NONE, - YF_VERSION, - YF_HELP, - YF_ERROR, - YF_ERROR_NO_ARGS, /* SPECIFICALLY if no arguments are given. */ + YF_INFO_NONE, + YF_INFO_VERSION, + YF_INFO_HELP, + YF_INFO_ERROR, + YF_INFO_ERROR_NO_ARGS, /* SPECIFICALLY if no arguments are given. */ }; enum yf_compiler_class { diff --git a/src/driver/compile.c b/src/driver/compile.c index 9400869..fb4cccd 100644 --- a/src/driver/compile.c +++ b/src/driver/compile.c @@ -160,17 +160,19 @@ static int yf_create_compiler_jobs( yf_backend_find_compiler(args); struct yf_list link_objs; - yf_list_init(&link_objs); + if (yf_list_init(&link_objs) != YF_OK) + abort(); /* Fill project info */ compilation->project_name = data->project_name; - yf_list_init(&compilation->jobs); + if (yf_list_init(&compilation->jobs) != YF_OK) + abort(); yfh_init(&compilation->symtables); - yf_list_init(&compilation->garbage); + if (yf_list_init(&compilation->garbage) != YF_OK) + abort(); struct yfh_cursor cursor; - for (yfh_cursor_init(&cursor, &data->files); !yfh_cursor_next(&cursor); ) { - yfh_cursor_get(&cursor, NULL, (void **)&fdata); + for (yfh_cursor_init(&cursor, &data->files); yfh_cursor_next_get(&cursor, NULL, (void **)&fdata) == YF_OK; ) { ujob = malloc(sizeof(struct yf_compile_analyse_job)); memset(ujob, 0, sizeof(struct yf_compile_analyse_job)); @@ -186,22 +188,25 @@ static int yf_create_compiler_jobs( YF_COMPILE_FULL; yfh_cursor_set(&cursor, ujob); // Set the job for further stages - yf_list_add(&compilation->jobs, ujob); + if (yf_list_add(&compilation->jobs, ujob) != YF_OK) + abort(); } - for (yfh_cursor_init(&cursor, &data->files); !yfh_cursor_next(&cursor); ) { - yfh_cursor_get(&cursor, NULL, (void **)&ujob); + for (yfh_cursor_init(&cursor, &data->files); yfh_cursor_next_get(&cursor, NULL, (void **)&ujob) == YF_OK; ) { + if (ujob->stage < YF_COMPILE_ANALYSEONLY) continue; cjob = malloc(sizeof(struct yf_compile_compile_job)); cjob->job.type = YF_COMPILATION_COMPILE; cjob->unit = ujob; - yf_list_add(&compilation->jobs, cjob); + if (yf_list_add(&compilation->jobs, cjob) != YF_OK) + abort(); if (ujob->stage >= YF_COMPILE_CODEGENONLY) { char * object_file = yf_backend_add_compile_job(compilation, args, ujob->unit_info); - yf_list_add(&link_objs, object_file); + if (yf_list_add(&link_objs, object_file) != YF_OK) + abort(); has_compiled_files = true; } } @@ -210,7 +215,8 @@ static int yf_create_compiler_jobs( yf_backend_add_link_job(compilation, args, &link_objs); } - yf_list_merge(&compilation->garbage, &link_objs); + if (yf_list_merge(&compilation->garbage, &link_objs) != YF_OK) + abort(); yfh_destroy(&data->files, NULL); return 0; @@ -355,8 +361,7 @@ static int yf_compile_project(struct yf_args * args, struct yf_compilation_data if (args->dump_projfiles) { YF_PRINT_DEFAULT("Project files: (green = needs to be recompiled):"); struct yfh_cursor cursor; - for (yfh_cursor_init(&cursor, &data.files); !yfh_cursor_next(&cursor); ) { - yfh_cursor_get(&cursor, NULL, (void **)&fdata); + for (yfh_cursor_init(&cursor, &data.files); yfh_cursor_next_get(&cursor, NULL, (void **)&fdata) == YF_OK; ) { if (fdata->parse_anew) { YF_PRINT_WITH_COLOR( YF_CODE_YELLOW, @@ -396,7 +401,8 @@ static int yf_compile_files(struct yf_args * args, struct yf_compilation_data * fdata->file_name = yf_strdup(fname); fdata->parse_anew = 1; /* TODO - more data */ - yfh_set(&data.files, fdata->file_name, fdata); + if (yfh_set(&data.files, fdata->file_name, fdata) != YF_OK) + abort(); } return yf_create_compiler_jobs(compilation, &data, args); @@ -482,8 +488,10 @@ static int yfc_run_frontend_build_symtable( retval = yf_do_cst_dump(&data->parse_tree); } else { retval = yf_build_symtab(data); - if (!retval && data->unit_info->file_prefix) - yfh_set(&compilation->symtables, data->unit_info->file_prefix, &data->symtab); + if (!retval && data->unit_info->file_prefix) { + if (yfh_set(&compilation->symtables, data->unit_info->file_prefix, &data->symtab) != YF_OK) + abort(); + } } return retval; } diff --git a/src/driver/compiler-backend.c b/src/driver/compiler-backend.c index 0948e35..091fcb4 100644 --- a/src/driver/compiler-backend.c +++ b/src/driver/compiler-backend.c @@ -180,7 +180,8 @@ char * yf_backend_add_compile_job( cjob->command[5] = "-fdollars-in-identifiers"; cjob->command[6] = NULL; - yf_list_add(&compilation->jobs, cjob); + if (yf_list_add(&compilation->jobs, cjob) != YF_OK) + abort(); return object_file; @@ -214,8 +215,11 @@ int yf_backend_add_link_job( struct yf_list_cursor link_objs_cur; yf_list_reset_cursor(&link_objs_cur, link_objs); for (obj_it = 0; obj_it < num_objs; ++obj_it) { - yf_list_get(&link_objs_cur, (void **)it); - yf_list_next(&link_objs_cur); + if (yf_list_get(&link_objs_cur, (void **)it) != YF_OK || + yf_list_next(&link_objs_cur) != YF_OK) + + abort(); + ++it; } @@ -234,7 +238,8 @@ int yf_backend_add_link_job( ljob->job.type = YF_COMPILATION_EXEC; ljob->command = link_cmd; - yf_list_add(&compilation->jobs, ljob); + if (yf_list_add(&compilation->jobs, ljob) != YF_OK) + abort(); return 0; @@ -277,9 +282,7 @@ int yf_ensure_entry_point( void * dummy; struct yfh_cursor cursor; - for (yfh_cursor_init(&cursor, &pdata->symtables); !yfh_cursor_next(&cursor); ) { - - yfh_cursor_get(&cursor, NULL, (void **)&fsymtab); + for (yfh_cursor_init(&cursor, &pdata->symtables); yfh_cursor_next_get(&cursor, NULL, (void **)&fsymtab) == YF_OK; ) { /* If a lookup for "main" succeeds, that's another entry point. */ if (yfh_get(&fsymtab->table, "main", &dummy) == 0) { diff --git a/src/parser/func.c b/src/parser/func.c index 8d89a18..186d1fd 100644 --- a/src/parser/func.c +++ b/src/parser/func.c @@ -19,7 +19,8 @@ int yfp_funcdecl(struct yf_parse_node * node, struct yf_lexer * lexer) { node->funcdecl.extc = false; /* Start arg list for writing */ - yf_list_init(&node->funcdecl.params); + if (yf_list_init(&node->funcdecl.params) != YF_OK) + abort(); argct = 0; for (;;) { @@ -61,7 +62,8 @@ int yfp_funcdecl(struct yf_parse_node * node, struct yf_lexer * lexer) { ++argct; /* Add to arg list */ - yf_list_add(&node->funcdecl.params, argp); + if (yf_list_add(&node->funcdecl.params, argp) != YF_OK) + abort(); } diff --git a/src/parser/parser.c b/src/parser/parser.c index 213f83d..46a6c77 100644 --- a/src/parser/parser.c +++ b/src/parser/parser.c @@ -27,7 +27,8 @@ int yfp_program(struct yf_parse_node * node, struct yf_lexer * lexer) { node->loc.line = node->loc.column = -1; node->type = YFCS_PROGRAM; - yf_list_init(&node->program.decls); + if (yf_list_init(&node->program.decls) != YF_OK) + abort(); for (;;) { @@ -78,7 +79,8 @@ int yfp_program(struct yf_parse_node * node, struct yf_lexer * lexer) { } /* Now, we have a node - add it to the list. */ - yf_list_add(&node->program.decls, decl); + if (yf_list_add(&node->program.decls, decl) != YF_OK) + abort(); } @@ -258,7 +260,8 @@ int yfp_bstmt(struct yf_parse_node * node, struct yf_lexer * lexer) { P_GETCT(node, tok); node->type = YFCS_BSTMT; - yf_list_init(&node->bstmt.stmts); + if (yf_list_init(&node->bstmt.stmts) != YF_OK) + abort(); for (;;) { P_PEEK(lexer, &tok); @@ -272,7 +275,8 @@ int yfp_bstmt(struct yf_parse_node * node, struct yf_lexer * lexer) { free(stmt); return 1; } - yf_list_add(&node->bstmt.stmts, stmt); + if (yf_list_add(&node->bstmt.stmts, stmt) != YF_OK) + abort(); } } diff --git a/src/parser/stmt.c b/src/parser/stmt.c index 33af4bd..536f320 100644 --- a/src/parser/stmt.c +++ b/src/parser/stmt.c @@ -111,7 +111,8 @@ int yfp_funccall(struct yf_parse_node * node, struct yf_lexer * lexer) { */ /* Start arg list for writing */ - yf_list_init(&node->expr.call.args); + if (yf_list_init(&node->expr.call.args) != YF_OK) + abort(); argct = 0; for (;;) { @@ -143,7 +144,8 @@ int yfp_funccall(struct yf_parse_node * node, struct yf_lexer * lexer) { ++argct; /* Add to arg list */ - yf_list_add(&node->expr.call.args, argp); + if (yf_list_add(&node->expr.call.args, argp) != YF_OK) + abort(); } diff --git a/src/semantics/symtab.c b/src/semantics/symtab.c index 9571b2a..5d4cba6 100644 --- a/src/semantics/symtab.c +++ b/src/semantics/symtab.c @@ -62,7 +62,8 @@ static int yfs_add_var(struct yf_hashmap * symtab, struct yf_parse_node * n) { return 1; } - yfh_set(symtab, v->name.name, vsym); + if (yfh_set(symtab, v->name.name, vsym) != YF_OK) + abort(); return 0; @@ -86,7 +87,8 @@ static int yfs_add_fn(struct yf_hashmap * symtab, struct yf_parse_node * f) { fsym->fn.name = fn->name.name; - yf_list_init(&fsym->fn.params); + if (yf_list_init(&fsym->fn.params) != YF_OK) + abort(); /* Adding parameters to symbol */ YF_LIST_FOREACH(fn->params, narg) { @@ -98,11 +100,13 @@ static int yfs_add_fn(struct yf_hashmap * symtab, struct yf_parse_node * f) { param->name = arg->name.name; param->type = arg->type.databuf; - yf_list_add(&fsym->fn.params, param); + if (yf_list_add(&fsym->fn.params, param) != YF_OK) + abort(); } - yfh_set(symtab, fsym->fn.name, fsym); + if (yfh_set(symtab, fsym->fn.name, fsym) != YF_OK) + abort(); return 0; diff --git a/src/semantics/validate/validate-expr.c b/src/semantics/validate/validate-expr.c index d88d50f..15ee562 100644 --- a/src/semantics/validate/validate-expr.c +++ b/src/semantics/validate/validate-expr.c @@ -167,7 +167,7 @@ static int validate_funccall( struct yf_list_cursor param_cursor; struct yf_list_cursor arg_cursor; - int lgres; + yf_result pres, ares; /* Make sure the function exists. */ if (find_symbol( @@ -199,33 +199,35 @@ static int validate_funccall( * the types are compatible for each one and the number of arguments * matches. */ - yf_list_init(&a->args); + if (yf_list_init(&a->args) != YF_OK) + abort(); + yf_list_reset_cursor(¶m_cursor, &a->name->fn.params); yf_list_reset_cursor(&arg_cursor, &c->args); + pres = yf_list_get(¶m_cursor, (void **) ¶m); + ares = yf_list_get(&arg_cursor, (void **) &carg); for (;;) { - aarg = yf_malloc(sizeof (struct yf_ast_node)); - if (!aarg) - return 2; + if (pres == YF_ERROR || ares == YF_ERROR) + abort(); - if ( - yf_list_get(¶m_cursor, (void **) ¶m) != - (lgres = yf_list_get(&arg_cursor, (void **) &carg)) - ) { + if (pres != ares) { YF_PRINT_ERROR( "%s %d:%d: too %s arguments in function call", loc->file, loc->line, loc->column, - lgres ? "few" : "many" + (pres == YF_OK) ? "few" : "many" ); - yf_free(aarg); return 1; } - if (lgres == -1) { - yf_free(aarg); + + if (pres == YF_REACHED_END) break; - } + + aarg = yf_malloc(sizeof (struct yf_ast_node)); + if (!aarg) + return 2; if (validate_expr( validator, carg, aarg @@ -256,10 +258,19 @@ static int validate_funccall( return 1; } - yf_list_add(&a->args, aarg); - yf_list_next(&arg_cursor); - yf_list_next(¶m_cursor); + if (yf_list_add(&a->args, aarg) != YF_OK) + abort(); + ares = yf_list_next(&arg_cursor); + pres = yf_list_next(¶m_cursor); + + if (ares == YF_ERROR || pres == YF_ERROR) + abort(); + + if (ares == YF_OK && pres == YF_OK) { + pres = yf_list_get(¶m_cursor, (void **) ¶m); + ares = yf_list_get(&arg_cursor, (void **) &carg); + } } return 0; diff --git a/src/semantics/validate/validate-func.c b/src/semantics/validate/validate-func.c index 3266dd0..4cf979d 100644 --- a/src/semantics/validate/validate-func.c +++ b/src/semantics/validate/validate-func.c @@ -41,7 +41,8 @@ int validate_funcdecl( enter_scope(validator, &a->param_scope); /* Add the arguments to the scope. */ - yf_list_init(&a->params); + if (yf_list_init(&a->params) != YF_OK) + abort(); YF_LIST_FOREACH(c->params, cv) { av = yf_malloc(sizeof (struct yf_ast_node)); if (!av) @@ -51,7 +52,8 @@ int validate_funcdecl( validator->error = 1; return 1; } - yf_list_add(&a->params, av); + if (yf_list_add(&a->params, av) != YF_OK) + abort(); } /* Validate the return type. */ @@ -131,7 +133,8 @@ int validate_bstmt( enter_scope(validator, &a->symtab); /* Validate each statement */ - yf_list_init(&a->stmts); + if (yf_list_init(&a->stmts) != YF_OK) + abort(); *returns = 0; @@ -161,7 +164,8 @@ int validate_bstmt( } else { /* Move to abstract list */ - yf_list_add(&a->stmts, asub); + if (yf_list_add(&a->stmts, asub) != YF_OK) + abort(); /* Probably redundant */ if (asub->type == YFA_RETURN) { diff --git a/src/semantics/validate/validate-utils.c b/src/semantics/validate/validate-utils.c index 3a21ae5..ab4b0e0 100644 --- a/src/semantics/validate/validate-utils.c +++ b/src/semantics/validate/validate-utils.c @@ -120,6 +120,8 @@ struct yfs_type * yfv_get_type_s( * Get a value from the hashmap. */ struct yfs_type * result = NULL; - yfh_get(&udata->types.table, typestr, (void **)&result); + if (yfh_get(&udata->types.table, typestr, (void **)&result) != YF_OK) { + /* result is null */ + } return result; } diff --git a/src/semantics/validate/validate-var.c b/src/semantics/validate/validate-var.c index 5997055..c2b6fa0 100644 --- a/src/semantics/validate/validate-var.c +++ b/src/semantics/validate/validate-var.c @@ -62,7 +62,8 @@ int validate_vardecl( /* The global scope symtab is already set up. */ if (!global) { a->name->var.name = c->name.name; - yfh_set(&validator->current_scope->table, c->name.name, a->name); + if (yfh_set(&validator->current_scope->table, c->name.name, a->name) != YF_OK) + abort(); } else { /* Free the name, since it was only needed for type checking. */ free(a->name); diff --git a/src/semantics/validate/validate.c b/src/semantics/validate/validate.c index aa6168d..03e62df 100644 --- a/src/semantics/validate/validate.c +++ b/src/semantics/validate/validate.c @@ -110,8 +110,9 @@ int validate_program( aprog = &ain->program; ain->type = YFA_PROGRAM; - yf_list_init(&aprog->decls); - + if (yf_list_init(&aprog->decls) != YF_OK) + abort(); + /* Iterate through all decls, construct abstract instances of them, and move them into the abstract list. */ YF_LIST_FOREACH(cprog->decls, cnode) { @@ -130,8 +131,10 @@ int validate_program( } /* Move to abstract list */ - if (anode) - yf_list_add(&aprog->decls, anode); + if (anode) { + if (yf_list_add(&aprog->decls, anode) != YF_OK) + abort(); + } } return err; diff --git a/src/util/allocator.c b/src/util/allocator.c index f0360b1..d357bfc 100644 --- a/src/util/allocator.c +++ b/src/util/allocator.c @@ -10,6 +10,7 @@ void * yf_malloc(size_t size) { if (ret == NULL) { YF_PRINT_ERROR("Allocation of %zu bytes failed", size); + abort(); } /* Return anyway, the error will be printed out before. */ @@ -24,6 +25,7 @@ void * yf_calloc(size_t num_elems, size_t size) { if (ret == NULL) { YF_PRINT_ERROR("Allocation of %zu %zu-byte sized elements failed", num_elems, size); + abort(); } return ret; diff --git a/src/util/hashmap.c b/src/util/hashmap.c index 5c2b6a6..2ed7962 100644 --- a/src/util/hashmap.c +++ b/src/util/hashmap.c @@ -6,15 +6,6 @@ #define MAX_STEPS 10 -/** - * Hashmap cursor used internally by the hashmap functions. - */ -struct yfh_internal_cursor { - struct yf_hashmap * hashmap; - struct yfh_bucket ** bucket; - struct yfh_bucket ** position; -}; - static unsigned long hash(const char * key); /** @@ -23,13 +14,13 @@ static unsigned long hash(const char * key); * Returns true if the key has been found, false otherwise. * Note: this is a reverse of the conventions used by other functions of this kind. */ -static bool yfh_cursor_find_before(struct yfh_internal_cursor * cur, const char * key) { +static bool yfh_cursor_find_before(struct yfh_cursor * cur, const char * key) { unsigned long bucket = hash(key) % cur->hashmap->num_buckets; cur->bucket = cur->hashmap->buckets + bucket; - for (cur->position = cur->bucket; *cur->position; cur->position = &(*cur->position)->next) { - if (!strcmp(key, (*cur->position)->key)) + for (cur->current = cur->bucket; *cur->current; cur->current = &(*cur->current)->next) { + if (!strcmp(key, (*cur->current)->key)) return true; } @@ -58,139 +49,127 @@ void yfh_destroy(struct yf_hashmap * hm, void (*cleanup)(void *)) { } /** TODO: Not implemented yet */ -int yfh_rehash(struct yf_hashmap * hm, unsigned hint) { - return 1; +yf_result yfh_rehash(struct yf_hashmap * hm, unsigned hint) { + return YF_ERROR; } -int yfh_set(struct yf_hashmap * hm, const char * key, void * value) { +yf_result yfh_set(struct yf_hashmap * hm, const char * key, void * value) { - struct yfh_internal_cursor cursor; + struct yfh_cursor cursor; struct yfh_bucket * bucket; cursor.hashmap = hm; if (yfh_cursor_find_before(&cursor, key)) { - (*cursor.position)->value = value; - return 0; + (*cursor.current)->value = value; + return YF_OK; } bucket = yf_malloc(sizeof(struct yfh_bucket)); - *cursor.position = bucket; + *cursor.current = bucket; bucket->key = yf_strdup(key); bucket->value = value; bucket->next = NULL; - return 0; + return YF_OK; } -int yfh_remove(struct yf_hashmap * hm, const char * key, void (*cleanup)(void *)) { +yf_result yfh_remove(struct yf_hashmap * hm, const char * key, void (*cleanup)(void *)) { - struct yfh_internal_cursor cursor; + struct yfh_cursor cursor; struct yfh_bucket * bucket; cursor.hashmap = hm; if (!yfh_cursor_find_before(&cursor, key)) - return 1; + return YF_ERROR; - bucket = *cursor.position; + bucket = *cursor.current; if (cleanup) cleanup(bucket->value); - *cursor.position = bucket->next; + *cursor.current = bucket->next; free(bucket->key); free(bucket); - return 0; + return YF_OK; } -int yfh_remove_at(struct yfh_cursor * cur, void (*cleanup)(void *)) { +yf_result yfh_remove_at(struct yfh_cursor * cur, void (*cleanup)(void *)) { /* We have to backtrack a little because we need to update the previous pointer */ - struct yfh_bucket ** before_ptr; struct yfh_bucket * bucket; - if (cur->bucket == NULL || cur->current == NULL) - return 1; + if (cur->bucket == NULL || cur->current == NULL || *cur->current == NULL) + return YF_ERROR; - for (before_ptr = cur->bucket; *before_ptr; before_ptr = &(*before_ptr)->next) { - if (*before_ptr == cur->current) - break; - } - - bucket = *before_ptr; + bucket = *cur->current; if (cleanup) cleanup(bucket->value); - *before_ptr = bucket->next; - cur->current = *before_ptr; + *cur->current = bucket->next; free(bucket->key); free(bucket); - return 0; + return YF_OK; } -int yfh_get(struct yf_hashmap * hm, const char * key, void ** value) { +yf_result yfh_get(struct yf_hashmap * hm, const char * key, void ** value) { - struct yfh_internal_cursor cursor; + struct yfh_cursor cursor; cursor.hashmap = hm; if (!yfh_cursor_find_before(&cursor, key)) - return 1; + return YF_ERROR; - *value = (*cursor.position)->value; - return 0; + *value = (*cursor.current)->value; + return YF_OK; } -int yfh_cursor_next(struct yfh_cursor * cur) { +yf_result yfh_cursor_next(struct yfh_cursor * cur) { if (cur->hashmap == NULL) - return 2; + return YF_ERROR; /* When a cursor is initialised, bucket is null */ if (cur->bucket == NULL) { cur->bucket = cur->hashmap->buckets; - cur->current = *cur->bucket; - if (cur->current != NULL) - return 0; + cur->current = cur->bucket; + if (*cur->current != NULL) + return YF_OK; } /* If we're pointing at an entry, move to the next one */ - if (cur->current != NULL) { - cur->current = cur->current->next; + if (*cur->current != NULL) { + cur->current = &(**cur->current).next; } /* When a cursor points past a bucket list (or an empty bucket), advance to the next bucket */ - while (cur->current == NULL) { + while (*cur->current == NULL) { ++cur->bucket; /* Check if we reached an end */ if (cur->bucket - cur->hashmap->buckets >= cur->hashmap->num_buckets) { cur->bucket = NULL; - return 1; + return YF_REACHED_END; } - cur->current = *cur->bucket; + cur->current = cur->bucket; } - return 0; + return YF_OK; } -int yfh_cursor_find(struct yfh_cursor * cur, const char * key, void ** value) { - - /* We're gonna cheat a little bit */ - struct yfh_internal_cursor * internal_cur = (struct yfh_internal_cursor*)cur; +yf_result yfh_cursor_find(struct yfh_cursor * cur, const char * key, void ** value) { if (cur->hashmap == NULL) - return 1; + return YF_ERROR; - if (!yfh_cursor_find_before(internal_cur, key)) { + if (!yfh_cursor_find_before(cur, key)) { cur->current = NULL; - return 1; + return YF_ERROR; } - /* Fixup cursor pointer to point to the actual entry */ - cur->current = *internal_cur->position; if (value) - *value = cur->current->value; - return 0; + *value = (**cur->current).value; + return YF_ERROR; } @@ -206,10 +185,3 @@ static unsigned long hash(const char * key) { return hash; } - -/* External inline function definitions */ -extern inline void yfh_init(struct yf_hashmap * map); -extern inline void yfh_cursor_init(struct yfh_cursor * cur, struct yf_hashmap * hashmap); -extern inline int yfh_cursor_get(struct yfh_cursor * cur, const char ** key, void ** value); -extern inline int yfh_cursor_set(struct yfh_cursor * cur, void * value); -extern inline int yfh_cursor_recalibrate(struct yfh_cursor * cur); diff --git a/src/util/hashmap.h b/src/util/hashmap.h index a9ecb9d..cb50334 100644 --- a/src/util/hashmap.h +++ b/src/util/hashmap.h @@ -6,7 +6,9 @@ #ifndef UTIL_HASHMAP_H #define UTIL_HASHMAP_H -#include "util/allocator.h" +#include "allocator.h" +#include "result.h" +#include "platform.h" #include #define YFH_INIT_BUCKETS (0x1000 / sizeof(void*)) @@ -35,16 +37,22 @@ struct yfh_cursor { struct yf_hashmap * hashmap; struct yfh_bucket ** bucket; - struct yfh_bucket * current; + /** Points to the pointer pointing to the acutal bucket to allow for fast insertions/removals */ + struct yfh_bucket ** current; }; /* Initialize a new hashmap. */ -inline void yfh_init(struct yf_hashmap * map) { +yf_always_inline void yfh_init(struct yf_hashmap * map) { map->num_buckets = YFH_INIT_BUCKETS; map->buckets = yf_calloc(map->num_buckets, sizeof(struct yfh_bucket *)); } +yf_always_inline void yfh_init_size(struct yf_hashmap * map, unsigned long num_buckets) { + map->num_buckets = num_buckets; + map->buckets = yf_calloc(map->num_buckets, sizeof(struct yfh_bucket *)); +} + /** * Destroy a hashmap. * The cleanup hook is a function used to free the values stored in the hashmap, @@ -56,44 +64,40 @@ void yfh_destroy(struct yf_hashmap *, void (*cleanup)(void *)); /** * Tries to rehash the whole hashmap. * Not implemented yet! - * Returns 0 on success, 1 on failure. * Regardless of the result, ALL existing cursors to the map will be invalidated and must optionally be re-initialised. * @param hint the number of buckets to use; 0 means rehash will pick an optimal number of buckets itself. */ -int yfh_rehash(struct yf_hashmap *, unsigned hint); +yf_nodiscard yf_result yfh_rehash(struct yf_hashmap *, unsigned hint); /** - * Return 1 if adding a value failed. * Probably will need to rehash on demand as well. */ -int yfh_set(struct yf_hashmap *, const char * key, void * value); +yf_nodiscard yf_result yfh_set(struct yf_hashmap *, const char * key, void * value); /** - * Return 1 if removing a value failed. * @param cleanup same as in yfh_destroy */ -int yfh_remove(struct yf_hashmap *, const char * key, void (*cleanup)(void *)); +yf_nodiscard yf_result yfh_remove(struct yf_hashmap *, const char * key, void (*cleanup)(void *)); /** - * Return 1 if removing a value failed. * @param cur must be a valid cursor pointing to the element being removed. * After the operation, cursor points to the entry after the one removed or null if there's no one. * It should be recalibrated to retrieve the next element. * @param cleanup same as in yfh_destroy */ -int yfh_remove_at(struct yfh_cursor * cur, void (*cleanup)(void *)); +yf_result yfh_remove_at(struct yfh_cursor * cur, void (*cleanup)(void *)); /** * Returns 1 if key was not present (value is unmodified), otherwise returns 0 and value is stored in value. */ -int yfh_get(struct yf_hashmap *, const char * key, void ** value); +yf_nodiscard yf_result yfh_get(struct yf_hashmap *, const char * key, void ** value); /** * Init/reset cursor to the beginning. * If hashmap is NULL, uses the last used hashmap in cursor, it is undefined behaviour if the cursor hasn't been used before. * The cursor must be 'next'ed or recalibrated before it can be dereferenced first. */ -inline void yfh_cursor_init(struct yfh_cursor * cur, struct yf_hashmap * hashmap) { +yf_always_inline void yfh_cursor_init(struct yfh_cursor * cur, struct yf_hashmap * hashmap) { if (hashmap) { cur->hashmap = hashmap; } @@ -107,41 +111,57 @@ inline void yfh_cursor_init(struct yfh_cursor * cur, struct yf_hashmap * hashmap * @param key key of the entry * @param value value of the entry */ -inline int yfh_cursor_get(struct yfh_cursor * cur, const char ** key, void ** value) { - if (cur->current == NULL) - return 1; +yf_nodiscard yf_always_inline yf_result yfh_cursor_get(struct yfh_cursor * cur, const char ** key, void ** value) { + if (cur->current == NULL || *cur->current == NULL) + return YF_ERROR; if (key) - *key = cur->current->key; + *key = (**cur->current).key; if (value) - *value = cur->current->value; - return 0; + *value = (**cur->current).value; + return YF_OK; } /** * Set value at the entry pointed to by cur. * Returns 0 on success, 1 on failure. */ -inline int yfh_cursor_set(struct yfh_cursor * cur, void * value) { - if (cur->current == NULL) - return 1; +yf_always_inline yf_result yfh_cursor_set(struct yfh_cursor * cur, void * value) { + if (cur->current == NULL || *cur->current == NULL) + return YF_ERROR; - cur->current->value = value; - return 0; + (**cur->current).value = value; + return YF_OK; } /** - * Tries to find next element. Returns 1 if reached the end, 2 on other error 0 otherwise. + * Tries to find next element. Refer to values of @ref yf_result for info */ -int yfh_cursor_next(struct yfh_cursor * cur); +yf_nodiscard yf_result yfh_cursor_next(struct yfh_cursor * cur); + +/** + * Combines @ref yfh_cursor_next and @ref yfh_cursor_get + * @param key key of the next entry + * @param value value of the next entry + */ +yf_nodiscard yf_always_inline yf_result yfh_cursor_next_get(struct yfh_cursor * cur, const char ** key, void ** value) { + yf_result res = yfh_cursor_next(cur); + if (res == YF_OK) { + if (key) + *key = (**cur->current).key; + if (value) + *value = (**cur->current).value; + } + return res; +} /** * Used to repoint the cursor at next element after yfh_remove_at. * Return has the same meaning as yfh_cursor_next. */ -inline int yfh_cursor_recalibrate(struct yfh_cursor * cur) { - if (cur->current != NULL) - return 0; +yf_nodiscard yf_always_inline yf_result yfh_cursor_recalibrate(struct yfh_cursor * cur) { + if (cur->current != NULL && *cur->current == NULL) + return YF_OK; return yfh_cursor_next(cur); } @@ -150,6 +170,6 @@ inline int yfh_cursor_recalibrate(struct yfh_cursor * cur) { * If the key was found, the cursor points to its entry, and the value (if not null) is set to point to its value. * @param value place to hold the value, if found; can be null */ -int yfh_cursor_find(struct yfh_cursor * cur, const char * key, void ** value); +yf_nodiscard yf_result yfh_cursor_find(struct yfh_cursor * cur, const char * key, void ** value); #endif /* UTIL_HASHMAP_H */ diff --git a/src/util/list.c b/src/util/list.c index 83506c9..cb8181f 100644 --- a/src/util/list.c +++ b/src/util/list.c @@ -5,41 +5,43 @@ #include -int yf_list_init(struct yf_list * list) { +yf_result yf_list_init(struct yf_list * list) { list->first = yf_malloc(sizeof(struct yf_list_block)); list->first->numfull = 0; list->first->next = NULL; list->last = list->first; - return 0; + return YF_OK; } -int yf_list_next(struct yf_list_cursor * cur) { +yf_result yf_list_next(struct yf_list_cursor * cur) { ++cur->list_index; ++cur->block_index; if (cur->block_index >= cur->block->numfull) { if (cur->block->next == NULL) { - return -1; + return YF_REACHED_END; } else { cur->block = cur->block->next; cur->block_index = 0; } } else { if (cur->block_index > cur->block->numfull) { - return -1; + return YF_REACHED_END; } } - return 0; + return YF_OK; } -int yf_list_add(struct yf_list * list, void * element) { +yf_result yf_list_add(struct yf_list * list, void * element) { struct yf_list_block * block = list->last; + yf_result res; if (block == NULL) { - yf_list_init(list); + if ((res = yf_list_init(list)) != YF_OK) + return res; block = list->last; } @@ -60,23 +62,23 @@ int yf_list_add(struct yf_list * list, void * element) { block->data[block->numfull] = element; block->numfull++; - return 0; + return YF_OK; } -int yf_list_merge(struct yf_list * dst, struct yf_list * src) { +yf_result yf_list_merge(struct yf_list * dst, struct yf_list * src) { if (dst == src) - return -1; + return YF_ERROR; if (src->first == NULL) - return 0; + return YF_OK; struct yf_list_block ** pblock; for (pblock = &dst->first; *pblock; pblock = &(*pblock)->next) {} *pblock = src->first; dst->last = src->last; src->first = src->last = NULL; - return 0; + return YF_OK; } void yf_list_destroy(struct yf_list * list, int free_elements) { @@ -101,7 +103,5 @@ void yf_list_destroy(struct yf_list * list, int free_elements) { } /* External inline function definitions */ -extern inline int yf_list_get(struct yf_list_cursor * cur, void ** elem); -extern inline void yf_list_reset_cursor(struct yf_list_cursor * cur, struct yf_list * list); -extern inline bool yf_list_is_empty(struct yf_list *list); +extern inline yf_result yf_list_get(struct yf_list_cursor * cur, void ** elem); extern inline size_t yf_list_get_count(struct yf_list *list); diff --git a/src/util/list.h b/src/util/list.h index 21c0717..1b23de7 100644 --- a/src/util/list.h +++ b/src/util/list.h @@ -7,6 +7,8 @@ #include #include +#include "result.h" +#include "platform.h" /** * How it works - each linked list is theoretically a list of nodes with a @@ -46,35 +48,35 @@ struct yf_list_cursor { */ /** - * Initialize a new list. Return -1 if memory allocation has failed. + * Initialize a new list. */ -int yf_list_init(struct yf_list * list); +yf_nodiscard yf_result yf_list_init(struct yf_list * list); /** * Get the currently pointed-to element. Returns -1 if we've passed the end, or * 0 otherwise. */ -inline int yf_list_get(struct yf_list_cursor * cur, void ** elem) { +yf_nodiscard inline yf_result yf_list_get(struct yf_list_cursor * cur, void ** elem) { if (cur->block_index >= cur->block->numfull) { - return -1; + return YF_REACHED_END; } *elem = cur->block->data[cur->block_index]; - return 0; + return YF_OK; } /** * Move to the next element. Return -1 if we've passed the end, or 0. */ -int yf_list_next(struct yf_list_cursor * cur); +yf_nodiscard yf_result yf_list_next(struct yf_list_cursor * cur); /** * Reset to the beginning. * If list is NULL, uses the last used list in cursor, it is undefined behaviour if the cursor hasn't been used before. */ -inline void yf_list_reset_cursor(struct yf_list_cursor * cur, struct yf_list * list) { +yf_always_inline void yf_list_reset_cursor(struct yf_list_cursor * cur, struct yf_list * list) { if (list != NULL) { cur->list = list; @@ -87,15 +89,15 @@ inline void yf_list_reset_cursor(struct yf_list_cursor * cur, struct yf_list * l } /** - * Add an element. Returns -1 if we've run out of memory, or 0 otherwise. + * Add an element. */ -int yf_list_add(struct yf_list * list, void * element); +yf_nodiscard yf_result yf_list_add(struct yf_list * list, void * element); /** * Merges two lists together. - * src will be empty after the operation, if successful + * src will be empty after the operation, if successful. */ -int yf_list_merge(struct yf_list * dst, struct yf_list * src); +yf_nodiscard yf_result yf_list_merge(struct yf_list * dst, struct yf_list * src); /** * Destroy a list. @@ -105,7 +107,7 @@ void yf_list_destroy(struct yf_list * list, int free_elements); /** * Fast check if list is empty. */ -inline bool yf_list_is_empty(struct yf_list * list) { +yf_always_inline bool yf_list_is_empty(struct yf_list * list) { if (list->first == NULL) return true; @@ -142,6 +144,6 @@ inline size_t yf_list_get_count(struct yf_list * list) { * @param out an lvalue denoting the element */ #define YF_LIST_FOREACH_CUR(cur, list, out) \ - for (yf_list_reset_cursor(&(cur), &(list)); yf_list_get(&(cur), (void **)&(out)) == 0; yf_list_next(&(cur))) + for (yf_list_reset_cursor(&(cur), &(list)); yf_list_get(&(cur), (void **)&(out)) == YF_OK; (void)yf_list_next(&(cur))) #endif /* UTIL_LIST_H */ diff --git a/src/util/platform.h b/src/util/platform.h index fef8a75..2777d47 100644 --- a/src/util/platform.h +++ b/src/util/platform.h @@ -32,4 +32,22 @@ #define YF_SUBPLATFORM YF_PLATFORMID_UNKNOWN #endif +#if defined(__has_attribute) +#define __yf_has_attribute __has_attribute +#else +#define __yf_has_attribute(name) 0 +#endif + +#if __yf_has_attribute(warn_unused_result) +#define yf_nodiscard __attribute__((warn_unused_result)) +#else +#define yf_nodiscard +#endif + +#if __yf_has_attribute(always_inline) +#define yf_always_inline __attribute__((always_inline)) inline +#else +#define yf_always_inline static inline +#endif + #endif /* UTIL_SYSTEM_H */ diff --git a/src/util/result.h b/src/util/result.h new file mode 100644 index 0000000..3c3d6da --- /dev/null +++ b/src/util/result.h @@ -0,0 +1,15 @@ +#ifndef UTIL_RESULT_H +#define UTIL_RESULT_H + +#include "platform.h" + +typedef enum yf_result { + /** Success */ + YF_OK, + /** Generic error */ + YF_ERROR, + /** Reached end of collection */ + YF_REACHED_END, +} yf_result; + +#endif