From 2e2115ce3c135133d4db81ca45d78cf96286d023 Mon Sep 17 00:00:00 2001 From: i-evi Date: Thu, 6 Aug 2020 15:19:17 +0800 Subject: [PATCH] update --- demo/lenet.c | 54 +++++- demo/lenet_pack.c | 49 ++++- demo/lenet_unpack.c | 53 +++++- makefile | 60 ++++--- src/3rd_party/parg/COPYING | 113 ++++++++++++ src/3rd_party/parg/parg.c | 354 +++++++++++++++++++++++++++++++++++++ src/3rd_party/parg/parg.h | 192 ++++++++++++++++++++ src/cc_tsrmgr.c | 10 +- src/util_list.c | 305 +++++++++++++++++++++----------- src/util_list.h | 147 +++++++++------ 10 files changed, 1135 insertions(+), 202 deletions(-) create mode 100644 src/3rd_party/parg/COPYING create mode 100644 src/3rd_party/parg/parg.c create mode 100644 src/3rd_party/parg/parg.h diff --git a/demo/lenet.c b/demo/lenet.c index cd86bc3..01d64b9 100644 --- a/demo/lenet.c +++ b/demo/lenet.c @@ -1,6 +1,8 @@ #include #include +#include +#include "parg.h" #include "catcoon.h" #define INPUT_W 28 @@ -16,7 +18,48 @@ const char *parameters_files[]={ "fc2_w.bin", "fc2_b.bin", }; -const char *parameters_path = "/home/evi/catcoon-pytorch-model/lenet/dump"; + +char image_path[128]; +char parameters_path[128]; + +void arg_parser(int argc, char* const argv[]) +{ + struct parg_state ps; + int c; + parg_init(&ps); + while ((c = parg_getopt(&ps, argc, argv, "hp:v")) != -1) { + switch (c) { + case 1: + strcpy(image_path, ps.optarg); + break; + case 'h': + printf("Usage: [-h] -p parameters-path image-file\n"); + printf("-h: Displays this message\n"); + printf("-p: Choose parameters file path\n"); + exit(EXIT_SUCCESS); + break; + case 'p': + strcpy(parameters_path, ps.optarg); + break; + case '?': + if (ps.optopt == 'p') { + printf("option -p requires an argument\n"); + } else { + printf("unknown option -%c\n", ps.optopt); + } + exit(EXIT_FAILURE); + break; + default: + printf("error: unhandled option -%c\n", c); + exit(EXIT_FAILURE); + break; + } + } + if (!strlen(image_path) || !strlen(parameters_path)) { + printf("error: incomplete argument\n"); + exit(EXIT_FAILURE); + } +} int main(int argc, const char *argv[]) { @@ -40,12 +83,9 @@ int main(int argc, const char *argv[]) cc_int32 shape_fc2_w[] = {1, 1, 128, 10, 0}; cc_int32 shape_fc2_b[] = {10, 0}; - if (argc < 2) { - fprintf(stderr, "usage: lenet [filename]\n"); - exit(255); - } + arg_parser(argc, (char**)argv); - img_read = utim_read(argv[1]); + img_read = utim_read(image_path); utim_img2gray(img_read); img = utim_resize(img_read, INPUT_H, INPUT_W, 0); input = cc_image2tensor(img, "input"); @@ -129,7 +169,7 @@ int main(int argc, const char *argv[]) } printf("[%d]: %f\n", i, *((cc_float32*)l4->data + i)); } - printf("Result of \"%s\": [%d]\n", argv[1], j); + printf("Result of \"%s\": [%d]\n", image_path, j); cc_tsrmgr_list(); cc_clear(); return 0; diff --git a/demo/lenet_pack.c b/demo/lenet_pack.c index 6e888c9..310f2bf 100644 --- a/demo/lenet_pack.c +++ b/demo/lenet_pack.c @@ -1,6 +1,8 @@ #include #include +#include +#include "parg.h" #include "catcoon.h" #define INPUT_W 28 @@ -16,8 +18,49 @@ const char *parameters_files[]={ "fc2_w.bin", "fc2_b.bin", }; -const char *parameters_path = "/home/evi/catcoon-pytorch-model/lenet/dump"; -const char *parameters_pack = "lenet_parameters.bin"; + +char parameters_path[128]; +char parameters_pack[128]; + +void arg_parser(int argc, char* const argv[]) +{ + struct parg_state ps; + int c; + parg_init(&ps); + while ((c = parg_getopt(&ps, argc, argv, "hp:o:v")) != -1) { + switch (c) { + case 'h': + printf("Usage: [-h] -p parameters-path -o pack-name\n"); + printf("-h: Displays this message\n"); + printf("-p: Choose parameters file path\n"); + printf("-o: Output file name\n"); + exit(EXIT_SUCCESS); + break; + case 'p': + strcpy(parameters_path, ps.optarg); + break; + case 'o': + strcpy(parameters_pack, ps.optarg); + break; + case '?': + if (ps.optopt == 'p') { + printf("option -p requires an argument\n"); + } else { + printf("unknown option -%c\n", ps.optopt); + } + exit(EXIT_FAILURE); + break; + default: + printf("error: unhandled option -%c\n", c); + exit(EXIT_FAILURE); + break; + } + } + if (!strlen(parameters_path) || !strlen(parameters_pack)) { + printf("error: incomplete argument\n"); + exit(EXIT_FAILURE); + } +} int main(int argc, const char *argv[]) { @@ -32,6 +75,8 @@ int main(int argc, const char *argv[]) cc_int32 shape_fc2_w[] = {1, 1, 128, 10, 0}; cc_int32 shape_fc2_b[] = {10, 0}; + arg_parser(argc, (char**)argv); + sprintf(filepath, "%s/%s", parameters_path, parameters_files[i++]); cc_load_bin(filepath, diff --git a/demo/lenet_unpack.c b/demo/lenet_unpack.c index 6e78dcf..458475f 100644 --- a/demo/lenet_unpack.c +++ b/demo/lenet_unpack.c @@ -1,12 +1,54 @@ #include #include +#include +#include "parg.h" #include "catcoon.h" #define INPUT_W 28 #define INPUT_H 28 -const char *parameters_path = "./lenet_parameters.bin"; +char image_path[128]; +char parameters_path[128]; + +void arg_parser(int argc, char* const argv[]) +{ + struct parg_state ps; + int c; + parg_init(&ps); + while ((c = parg_getopt(&ps, argc, argv, "hp:v")) != -1) { + switch (c) { + case 1: + strcpy(image_path, ps.optarg); + break; + case 'h': + printf("Usage: [-h] -p parameters-pack image-file\n"); + printf("-h: Displays this message\n"); + printf("-p: Choose parameters file path\n"); + exit(EXIT_SUCCESS); + break; + case 'p': + strcpy(parameters_path, ps.optarg); + break; + case '?': + if (ps.optopt == 'p') { + printf("option -p requires an argument\n"); + } else { + printf("unknown option -%c\n", ps.optopt); + } + exit(EXIT_FAILURE); + break; + default: + printf("error: unhandled option -%c\n", c); + exit(EXIT_FAILURE); + break; + } + } + if (!strlen(image_path) || !strlen(parameters_path)) { + printf("error: incomplete argument\n"); + exit(EXIT_FAILURE); + } +} int main(int argc, const char *argv[]) { @@ -21,10 +63,7 @@ int main(int argc, const char *argv[]) *conv2_w, *conv2_b, *fc1_w, *fc1_b, *fc2_w, *fc2_b; cc_int32 shape_flat[] = {-1, 1, 1, 0}; - if (argc < 2) { - fprintf(stderr, "usage: lenet [filename]\n"); - exit(255); - } + arg_parser(argc, (char**)argv); /* load parameters */ cc_tsrmgr_import(parameters_path); @@ -37,7 +76,7 @@ int main(int argc, const char *argv[]) fc2_w = cc_tsrmgr_get("fc2_w"); fc2_b = cc_tsrmgr_get("fc2_b"); - img_read = utim_read(argv[1]); + img_read = utim_read(image_path); utim_img2gray(img_read); img = utim_resize(img_read, INPUT_H, INPUT_W, 0); input = cc_image2tensor(img, "input"); @@ -78,7 +117,7 @@ int main(int argc, const char *argv[]) } printf("[%d]: %f\n", i, *((cc_float32*)l4->data + i)); } - printf("Result of \"%s\": [%d]\n", argv[1], j); + printf("Result of \"%s\": [%d]\n", image_path, j); cc_tsrmgr_list(); cc_clear(); return 0; diff --git a/makefile b/makefile index 183acf7..bf57ffd 100644 --- a/makefile +++ b/makefile @@ -1,8 +1,11 @@ -CC = gcc +cc = gcc # Build Ctrl Flag BCTRL = +INC += -I ./src/ +LINK += -lm + # Debug flag, cc_assert DFLAG += -DENABLE_CC_ASSERT # AddressSanitizer for gcc/clang @@ -22,15 +25,19 @@ CFLAG += $(DFLAG) $(WFLAG) $(OFLAG) CFLAG += -DAUTO_TSRMGR # 3rd party source/library configurations -# stb for jpg, png, tga format images, -# will only support bmp image if disabled +# stb: read/write jpg, png, tga format images. +# Will only support bmp image if disabled 3RDSRC_CF += stb +# parg: argv parser written in ANSI C +# Argv parser for demo apps +3RDSRC_CF += parg + ifneq ($(findstring MINI, $(BCTRL)),) CC = tcc CFLAG = -std=c89 CFLAG += -DAUTO_TSRMGR - 3RDSRC_CF = + 3RDSRC_CF = parg endif ifneq ($(findstring -std=c89, $(CFLAG)),) @@ -40,16 +47,26 @@ ifneq ($(findstring -std=c89, $(CFLAG)),) endif endif -LINK += -lm -INC += -I ./src/ -ALL_O = catcoon.o cc_tensor.o cc_dtype.o cc_tsrmgr.o cc_fmap2d.o cc_pool2d.o \ - cc_array.o cc_basic.o cc_actfn.o cc_fullycon.o cc_pad2d.o cc_cpufn.o \ - cc_conv2d.o cc_normfn.o cc_image.o util_rbt.o util_list.o util_log.o \ - util_image.o global_fn_cfg.o +ifneq ($(findstring stb, $(3RDSRC_CF)),) + UTIM_COND += -DUSE3RD_STB_IMAGE -I ./src/3rd_party/stb/ +endif + +ifneq ($(findstring parg, $(3RDSRC_CF)),) + ALL_O += parg.o + APP_INC += -I ./src/3rd_party/parg/ +endif + +ALL_O += \ +catcoon.o cc_tensor.o cc_dtype.o cc_tsrmgr.o cc_fmap2d.o cc_pool2d.o \ +cc_array.o cc_basic.o cc_actfn.o cc_fullycon.o cc_pad2d.o cc_cpufn.o \ +cc_conv2d.o cc_normfn.o cc_image.o util_rbt.o util_list.o util_log.o \ +util_image.o global_fn_cfg.o CATCOON_A = libcatcoon.a -APP_NAMES = simple lenet lenet_pack lenet_unpack +APP_NAMES = simple lenet lenet_pack lenet_unpack +APP_INC += $(INC) +APP_LINK += $(LINK) ifeq ($(OS),Windows_NT) RM = del @@ -63,12 +80,13 @@ all: $(APPS) # $(CATCOON_A) %.o: ./src/%.c $(CC) -c -o $@ $< $(CFLAG) $(INC) -# Targets For Linux + +# Apps For Linux %: ./demo/%.c $(ALL_O) - $(CC) -o $@ $< $(ALL_O) $(CFLAG) $(INC) $(LINK) -# Targets For Windows + $(CC) -o $@ $< $(ALL_O) $(CFLAG) $(APP_INC) $(APP_LINK) +# Apps For Windows %.exe: ./demo/%.c $(ALL_O) - $(CC) -o $@ $< $(ALL_O) $(CFLAG) $(INC) $(LINK) + $(CC) -o $@ $< $(ALL_O) $(CFLAG) $(APP_INC) $(APP_LINK) global_fn_cfg.o : $(patsubst %, ./src/%, global_fn_cfg.h global_fn_cfg.c) @@ -90,15 +108,15 @@ cc_tensor.o : $(patsubst %, ./src/%, cc_tensor.h cc_tensor.c) util_log.o : $(patsubst %, ./src/%, util_log.h util_log.c) util_rbt.o : $(patsubst %, ./src/%, util_rbt.h util_rbt.c) -util_list.o : ./src/util_list.h ./src/util_list.c +util_list.o : $(patsubst %, ./src/%, util_list.h util_list.c) $(CC) -c -o $@ ./src/util_list.c $(CFLAG) -DENABLE_FOPS -UTIM_COND = -ifneq ($(findstring stb, $(3RDSRC_CF)),) - UTIM_COND += -DUSE3RD_STB_IMAGE -I ./src/3rd_party/stb/ -endif -util_image.o : ./src/util_image.h ./src/util_image.c +util_image.o : $(patsubst %, ./src/%, util_image.h util_image.c) $(CC) -c -o $@ ./src/util_image.c $(CFLAG) $(UTIM_COND) +# 3rd party objs +parg.o: ./src/3rd_party/parg/parg* + $(CC) -c -o $@ ./src/3rd_party/parg/parg.c $(CFLAG) + minimal: $(MAKE) "BCTRL = MINI" diff --git a/src/3rd_party/parg/COPYING b/src/3rd_party/parg/COPYING new file mode 100644 index 0000000..e367586 --- /dev/null +++ b/src/3rd_party/parg/COPYING @@ -0,0 +1,113 @@ +CC0 1.0 Universal + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. + +For more information, please see + diff --git a/src/3rd_party/parg/parg.c b/src/3rd_party/parg/parg.c new file mode 100644 index 0000000..a582205 --- /dev/null +++ b/src/3rd_party/parg/parg.c @@ -0,0 +1,354 @@ +/* + * parg - parse argv + * + * Written in 2015-2016 by Joergen Ibsen + * + * To the extent possible under law, the author(s) have dedicated all + * copyright and related and neighboring rights to this software to the + * public domain worldwide. This software is distributed without any + * warranty. + */ + +#include "parg.h" + +#include +#include +#include + +/* + * Check if state is at end of argv. + */ +static int +is_argv_end(const struct parg_state *ps, int argc, char *const argv[]) +{ + return ps->optind >= argc || argv[ps->optind] == NULL; +} + +/* + * Match nextchar against optstring. + */ +static int +match_short(struct parg_state *ps, int argc, char *const argv[], + const char *optstring) +{ + const char *p = strchr(optstring, *ps->nextchar); + + if (p == NULL) { + ps->optopt = *ps->nextchar++; + return '?'; + } + + /* If no option argument, return option */ + if (p[1] != ':') { + return *ps->nextchar++; + } + + /* If more characters, return as option argument */ + if (ps->nextchar[1] != '\0') { + ps->optarg = &ps->nextchar[1]; + ps->nextchar = NULL; + return *p; + } + + /* If option argument is optional, return option */ + if (p[2] == ':') { + return *ps->nextchar++; + } + + /* Option argument required, so return next argv element */ + if (is_argv_end(ps, argc, argv)) { + ps->optopt = *ps->nextchar++; + return optstring[0] == ':' ? ':' : '?'; + } + + ps->optarg = argv[ps->optind++]; + ps->nextchar = NULL; + return *p; +} + +/* + * Match string at nextchar against longopts. + */ +static int +match_long(struct parg_state *ps, int argc, char *const argv[], + const char *optstring, + const struct parg_option *longopts, int *longindex) +{ + size_t len; + int num_match = 0; + int match = -1; + int i; + + len = strcspn(ps->nextchar, "="); + + for (i = 0; longopts[i].name; ++i) { + if (strncmp(ps->nextchar, longopts[i].name, len) == 0) { + match = i; + num_match++; + /* Take if exact match */ + if (longopts[i].name[len] == '\0') { + num_match = 1; + break; + } + } + } + + /* Return '?' on no or ambiguous match */ + if (num_match != 1) { + ps->optopt = 0; + ps->nextchar = NULL; + return '?'; + } + + assert(match != -1); + + if (longindex) { + *longindex = match; + } + + if (ps->nextchar[len] == '=') { + /* Option argument present, check if extraneous */ + if (longopts[match].has_arg == PARG_NOARG) { + ps->optopt = longopts[match].flag ? 0 : longopts[match].val; + ps->nextchar = NULL; + return optstring[0] == ':' ? ':' : '?'; + } + else { + ps->optarg = &ps->nextchar[len + 1]; + } + } + else if (longopts[match].has_arg == PARG_REQARG) { + /* Option argument required, so return next argv element */ + if (is_argv_end(ps, argc, argv)) { + ps->optopt = longopts[match].flag ? 0 : longopts[match].val; + ps->nextchar = NULL; + return optstring[0] == ':' ? ':' : '?'; + } + + ps->optarg = argv[ps->optind++]; + } + + ps->nextchar = NULL; + + if (longopts[match].flag != NULL) { + *longopts[match].flag = longopts[match].val; + return 0; + } + + return longopts[match].val; +} + +void +parg_init(struct parg_state *ps) +{ + ps->optarg = NULL; + ps->optind = 1; + ps->optopt = '?'; + ps->nextchar = NULL; +} + +int +parg_getopt(struct parg_state *ps, int argc, char *const argv[], + const char *optstring) +{ + return parg_getopt_long(ps, argc, argv, optstring, NULL, NULL); +} + +int +parg_getopt_long(struct parg_state *ps, int argc, char *const argv[], + const char *optstring, + const struct parg_option *longopts, int *longindex) +{ + assert(ps != NULL); + assert(argv != NULL); + assert(optstring != NULL); + + ps->optarg = NULL; + + if (argc < 2) { + return -1; + } + + /* Advance to next element if needed */ + if (ps->nextchar == NULL || *ps->nextchar == '\0') { + if (is_argv_end(ps, argc, argv)) { + return -1; + } + + ps->nextchar = argv[ps->optind++]; + + /* Check for nonoption element (including '-') */ + if (ps->nextchar[0] != '-' || ps->nextchar[1] == '\0') { + ps->optarg = ps->nextchar; + ps->nextchar = NULL; + return 1; + } + + /* Check for '--' */ + if (ps->nextchar[1] == '-') { + if (ps->nextchar[2] == '\0') { + ps->nextchar = NULL; + return -1; + } + + if (longopts != NULL) { + ps->nextchar += 2; + + return match_long(ps, argc, argv, optstring, + longopts, longindex); + } + } + + ps->nextchar++; + } + + /* Match nextchar */ + return match_short(ps, argc, argv, optstring); +} + +/* + * Reverse elements of `v` from `i` to `j`. + */ +static void +reverse(char *v[], int i, int j) +{ + while (j - i > 1) { + char *tmp = v[i]; + v[i] = v[j - 1]; + v[j - 1] = tmp; + ++i; + --j; + } +} + +/* + * Reorder elements of `argv` with no special cases. + * + * This function assumes there is no `--` element, and the last element + * is not an option missing a required argument. + * + * The algorithm is described here: + * http://hardtoc.com/2016/11/07/reordering-arguments.html + */ +static int +parg_reorder_simple(int argc, char *argv[], + const char *optstring, + const struct parg_option *longopts) +{ + struct parg_state ps; + int change; + int l = 0; + int m = 0; + int r = 0; + + if (argc < 2) { + return argc; + } + + do { + int nextind; + int c; + + parg_init(&ps); + + nextind = ps.optind; + + /* Parse until end of argument */ + do { + c = parg_getopt_long(&ps, argc, argv, optstring, longopts, NULL); + } while (ps.nextchar != NULL && *ps.nextchar != '\0'); + + change = 0; + + do { + /* Find next non-option */ + for (l = nextind; c != 1 && c != -1;) { + l = ps.optind; + + do { + c = parg_getopt_long(&ps, argc, argv, optstring, longopts, NULL); + } while (ps.nextchar != NULL && *ps.nextchar != '\0'); + } + + /* Find next option */ + for (m = l; c == 1;) { + m = ps.optind; + + do { + c = parg_getopt_long(&ps, argc, argv, optstring, longopts, NULL); + } while (ps.nextchar != NULL && *ps.nextchar != '\0'); + } + + /* Find next non-option */ + for (r = m; c != 1 && c != -1;) { + r = ps.optind; + + do { + c = parg_getopt_long(&ps, argc, argv, optstring, longopts, NULL); + } while (ps.nextchar != NULL && *ps.nextchar != '\0'); + } + + /* Find next option */ + for (nextind = r; c == 1;) { + nextind = ps.optind; + + do { + c = parg_getopt_long(&ps, argc, argv, optstring, longopts, NULL); + } while (ps.nextchar != NULL && *ps.nextchar != '\0'); + } + + if (m < r) { + change = 1; + reverse(argv, l, m); + reverse(argv, m, r); + reverse(argv, l, r); + } + } while (c != -1); + } while (change != 0); + + return l + (r - m); +} + +int +parg_reorder(int argc, char *argv[], + const char *optstring, + const struct parg_option *longopts) +{ + struct parg_state ps; + int lastind; + int optend; + int c; + + assert(argv != NULL); + assert(optstring != NULL); + + if (argc < 2) { + return argc; + } + + parg_init(&ps); + + /* Find end of normal arguments */ + do { + lastind = ps.optind; + + c = parg_getopt_long(&ps, argc, argv, optstring, longopts, NULL); + + /* Check for trailing option with error */ + if ((c == '?' || c == ':') && is_argv_end(&ps, argc, argv)) { + lastind = ps.optind - 1; + break; + } + } while (c != -1); + + optend = parg_reorder_simple(lastind, argv, optstring, longopts); + + /* Rotate `--` or trailing option with error into position */ + if (lastind < argc) { + reverse(argv, optend, lastind); + reverse(argv, optend, lastind + 1); + ++optend; + } + + return optend; +} diff --git a/src/3rd_party/parg/parg.h b/src/3rd_party/parg/parg.h new file mode 100644 index 0000000..2d620f3 --- /dev/null +++ b/src/3rd_party/parg/parg.h @@ -0,0 +1,192 @@ +/* + * parg - parse argv + * + * Written in 2015-2016 by Joergen Ibsen + * + * To the extent possible under law, the author(s) have dedicated all + * copyright and related and neighboring rights to this software to the + * public domain worldwide. This software is distributed without any + * warranty. + */ + +#ifndef PARG_H_INCLUDED +#define PARG_H_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +#define PARG_VER_MAJOR 1 /**< Major version number */ +#define PARG_VER_MINOR 0 /**< Minor version number */ +#define PARG_VER_PATCH 2 /**< Patch version number */ +#define PARG_VER_STRING "1.0.2" /**< Version number as a string */ + +/** + * Structure containing state between calls to parser. + * + * @see parg_init + */ +struct parg_state { + const char *optarg; /**< Pointer to option argument, if any */ + int optind; /**< Next index in argv to process */ + int optopt; /**< Option value resulting in error, if any */ + const char *nextchar; /**< Next character to process */ +}; + +/** + * Structure for supplying long options to `parg_getopt_long()`. + * + * @see parg_getopt_long + */ +struct parg_option { + const char *name; /**< Name of option */ + int has_arg; /**< Option argument status */ + int *flag; /**< Pointer to flag variable */ + int val; /**< Value of option */ +}; + +/** + * Values for `has_arg` flag in `parg_option`. + * + * @see parg_option + */ +typedef enum { + PARG_NOARG, /**< No argument */ + PARG_REQARG, /**< Required argument */ + PARG_OPTARG /**< Optional argument */ +} parg_arg_num; + +/** + * Initialize `ps`. + * + * Must be called before using state with a parser. + * + * @see parg_state + * + * @param ps pointer to state + */ +void +parg_init(struct parg_state *ps); + +/** + * Parse next short option in `argv`. + * + * Elements in `argv` that contain short options start with a single dash + * followed by one or more option characters, and optionally an option + * argument for the last option character. Examples are '`-d`', '`-ofile`', + * and '`-dofile`'. + * + * Consecutive calls to this function match the command-line arguments in + * `argv` against the short option characters in `optstring`. + * + * If an option character in `optstring` is followed by a colon, '`:`', the + * option requires an argument. If it is followed by two colons, the option + * may take an optional argument. + * + * If a match is found, `optarg` points to the option argument, if any, and + * the value of the option character is returned. + * + * If a match is found, but is missing a required option argument, `optopt` + * is set to the option character. If the first character in `optstring` is + * '`:`', then '`:`' is returned, otherwise '`?`' is returned. + * + * If no option character in `optstring` matches a short option, `optopt` + * is set to the option character, and '`?`' is returned. + * + * If an element of argv does not contain options (a nonoption element), + * `optarg` points to the element, and `1` is returned. + * + * An element consisting of a single dash, '`-`', is returned as a nonoption. + * + * Parsing stops and `-1` is returned, when the end of `argv` is reached, or + * if an element contains '`--`'. + * + * Works similarly to `getopt`, if `optstring` were prefixed by '`-`'. + * + * @param ps pointer to state + * @param argc number of elements in `argv` + * @param argv array of pointers to command-line arguments + * @param optstring string containing option characters + * @return option value on match, `1` on nonoption element, `-1` on end of + * arguments, '`?`' on unmatched option, '`?`' or '`:`' on option argument + * error + */ +int +parg_getopt(struct parg_state *ps, int argc, char *const argv[], + const char *optstring); + +/** + * Parse next long or short option in `argv`. + * + * Elements in `argv` that contain a long option start with two dashes + * followed by a string, and optionally an equal sign and an option argument. + * Examples are '`--help`' and '`--size=5`'. + * + * If no exact match is found, an unambiguous prefix of a long option will + * match. For example, if '`foo`' and '`foobar`' are valid long options, then + * '`--fo`' is ambiguous and will not match, '`--foo`' matches exactly, and + * '`--foob`' is an unambiguous prefix and will match. + * + * If a long option match is found, and `flag` is `NULL`, `val` is returned. + * + * If a long option match is found, and `flag` is not `NULL`, `val` is stored + * in the variable `flag` points to, and `0` is returned. + * + * If a long option match is found, but is missing a required option argument, + * or has an option argument even though it takes none, `optopt` is set to + * `val` if `flag` is `NULL`, and `0` otherwise. If the first character in + * `optstring` is '`:`', then '`:`' is returned, otherwise '`?`' is returned. + * + * If `longindex` is not `NULL`, the index of the entry in `longopts` that + * matched is stored there. + * + * If no long option in `longopts` matches a long option, '`?`' is returned. + * + * Handling of nonoptions and short options is like `parg_getopt()`. + * + * If no short options are required, an empty string, `""`, should be passed + * as `optstring`. + * + * Works similarly to `getopt_long`, if `optstring` were prefixed by '`-`'. + * + * @see parg_getopt + * + * @param ps pointer to state + * @param argc number of elements in `argv` + * @param argv array of pointers to command-line arguments + * @param optstring string containing option characters + * @param longopts array of `parg_option` structures + * @param longindex pointer to variable to store index of matching option in + * @return option value on match, `0` for flag option, `1` on nonoption + * element, `-1` on end of arguments, '`?`' on unmatched or ambiguous option, + * '`?`' or '`:`' on option argument error + */ +int +parg_getopt_long(struct parg_state *ps, int argc, char *const argv[], + const char *optstring, + const struct parg_option *longopts, int *longindex); + +/** + * Reorder elements of `argv` so options appear first. + * + * If there are no long options, `longopts` may be `NULL`. + * + * The return value can be used as `argc` parameter for `parg_getopt()` and + * `parg_getopt_long()`. + * + * @param argc number of elements in `argv` + * @param argv array of pointers to command-line arguments + * @param optstring string containing option characters + * @param longopts array of `parg_option` structures + * @return index of first nonoption in `argv` on success, `-1` on error + */ +int +parg_reorder(int argc, char *argv[], + const char *optstring, + const struct parg_option *longopts); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* PARG_H_INCLUDED */ diff --git a/src/cc_tsrmgr.c b/src/cc_tsrmgr.c index d7c7199..4e11768 100644 --- a/src/cc_tsrmgr.c +++ b/src/cc_tsrmgr.c @@ -241,8 +241,8 @@ list_t *cc_tsrmgr_pack() off = strlen(csr->name) + 1; for (i = 0; i < csr->container->counter; ++i) { /* Ref: util_list.h */ - len = *(DynLenFlag*) - csr->container->index[i] + sizeof(DynLenFlag); + len = *(rlen_t*) + csr->container->index[i] + sizeof(rlen_t); memcpy(dptr + off, csr->container->index[i], len); off += len; } @@ -271,11 +271,11 @@ void cc_tsrmgr_unpack(list_t *tls) off = strlen(name) + 1; for (j = 0; j < CC_TENSOR_ITEMS; ++j) { /* Ref: util_list.h */ - len = *(DynLenFlag*)(rptr + off); - dptr = rptr + off + sizeof(DynLenFlag); + len = *(rlen_t*)(rptr + off); + dptr = rptr + off + sizeof(rlen_t); cc_assert_zero( list_set_record(container, j, dptr, len)); - off += (len + sizeof(DynLenFlag)); + off += (len + sizeof(rlen_t)); } cc_tsrmgr_del(name); cc_assert_alloc( diff --git a/src/util_list.c b/src/util_list.c index 4727c86..42d268c 100644 --- a/src/util_list.c +++ b/src/util_list.c @@ -30,7 +30,7 @@ void __________compile_time_test___________() } #endif -static uint _djb_hash(void *s, uint len, uint seed) +static uint _djb_hash(const void *s, uint len, uint seed) { uint hash = seed; uint i; @@ -40,7 +40,21 @@ static uint _djb_hash(void *s, uint len, uint seed) return hash; } -static int _is_little_endian() +static int _strcmp(const void *a, const void *b) +{ + return strcmp((const char*)a, (const char*)b); +} + +static uint _string_hash(const void *s, uint seed) +{ + return _djb_hash(s, strlen((const char*)s), seed); +} + +static uint _seed; +static __hashFx _hfx = _string_hash; +static __compFx _cmp = _strcmp; + +static int _is_little_endian(void) { uint i = 1; unsigned char *c = (unsigned char*)&i; @@ -94,6 +108,13 @@ static void _switch_byte_order(list_t *list) { _memrev(&list->scale , sizeof(uint)); } +list_t *list_new(uint scale, uint blen) +{ + if (!blen) + return list_new_dynamic(scale); + return list_new_static(scale, blen); +} + list_t *list_new_static(uint scale, uint blen) { list_t *list = (list_t*)malloc(sizeof(list_t)); @@ -173,8 +194,8 @@ list_t *list_clone_static(list_t *list) #define PROCESS_CLONE_DYN_INDEX(i) \ if (list->index[i]) { \ s = list_set_record(clone, i, \ - list->index[i] + sizeof(DynLenFlag), \ - *(DynLenFlag*)list->index[i]); \ + list->index[i] + sizeof(rlen_t), \ + *(rlen_t*)list->index[i]); \ if (s) { \ clone->status |= s; \ return clone; \ @@ -185,7 +206,7 @@ list_t *list_clone_dynamic(list_t *list) { uint i; list_t *clone; - ls_status_t s; + lsw_t s; if (!list) return NULL; clone = (list_t*)malloc(sizeof(list_t)); @@ -218,7 +239,7 @@ list_t *list_clone_dynamic(list_t *list) return clone; } -ls_status_t list_del(list_t *list) +lsw_t list_del(list_t *list) { if (TEST_FLAG(list->flag, LIST_DYNAMIC_MODE)) return list_del_dynamic(list); @@ -226,7 +247,7 @@ ls_status_t list_del(list_t *list) return list_del_static(list); } -ls_status_t list_del_static(list_t *list) +lsw_t list_del_static(list_t *list) { if (!list) return LSS_SUCCESS; @@ -238,7 +259,7 @@ ls_status_t list_del_static(list_t *list) return LSS_SUCCESS; } -ls_status_t list_del_dynamic(list_t *list) +lsw_t list_del_dynamic(list_t *list) { if (!list) return LSS_SUCCESS; @@ -254,7 +275,7 @@ ls_status_t list_del_dynamic(list_t *list) return LSS_SUCCESS; } -ls_status_t list_set_name(list_t *list, const char *name) +lsw_t list_set_name(list_t *list, const char *name) { if (TEST_FLAG(list->flag, LIST_NOT_SHARED)) { if (!name) { @@ -279,7 +300,7 @@ ls_status_t list_set_name(list_t *list, const char *name) } -ls_status_t list_resize(list_t *list, uint newScale) +lsw_t list_resize(list_t *list, uint newScale) { if (TEST_FLAG(list->flag, LIST_DYNAMIC_MODE)) return list_resize_dynamic(list, newScale); @@ -287,7 +308,7 @@ ls_status_t list_resize(list_t *list, uint newScale) return list_resize_static(list, newScale); } -ls_status_t list_resize_static(list_t *list, uint newScale) +lsw_t list_resize_static(list_t *list, uint newScale) { byte *newMem; uint newLen = newScale * list->blen; @@ -307,7 +328,7 @@ ls_status_t list_resize_static(list_t *list, uint newScale) return LSS_SUCCESS; } -ls_status_t list_resize_dynamic(list_t *list, uint newScale) +lsw_t list_resize_dynamic(list_t *list, uint newScale) { byte **newIndex; uint i = 0; @@ -331,7 +352,7 @@ ls_status_t list_resize_dynamic(list_t *list, uint newScale) return LSS_SUCCESS; } -ls_status_t list_set_record(list_t *list, uint id, +lsw_t list_set_record(list_t *list, uint id, const void *record, uint len) { if (TEST_FLAG(list->flag, LIST_DYNAMIC_MODE)) @@ -340,7 +361,7 @@ ls_status_t list_set_record(list_t *list, uint id, return list_set_static_record(list, id, record, len); } -ls_status_t list_set_static_record(list_t *list, uint id, +lsw_t list_set_static_record(list_t *list, uint id, const void *record, uint len) { if (id >= list->scale) @@ -350,21 +371,21 @@ ls_status_t list_set_static_record(list_t *list, uint id, return LSS_SUCCESS; } -ls_status_t list_set_dynamic_record(list_t *list, uint id, +lsw_t list_set_dynamic_record(list_t *list, uint id, const void *record, uint len) { - DynLenFlag *l; + rlen_t *l; uint mlen = 0; if (id >= list->scale) return LSS_BAD_ID; if (list->index[id]) return LSS_DYN_ID_EXIST; - mlen = len + sizeof(DynLenFlag); + mlen = len + sizeof(rlen_t); list->index[id] = (byte*)malloc(mlen); if (!list->index[id]) return LSS_MALLOC_ERR; - memcpy(list->index[id] + sizeof(DynLenFlag), record, len); - l = (DynLenFlag*)list->index[id]; + memcpy(list->index[id] + sizeof(rlen_t), record, len); + l = (rlen_t*)list->index[id]; *l = len; list->counter++; list->length += mlen; @@ -400,13 +421,13 @@ void *list_alloc(list_t *list, uint id, uint nbyte) if (TEST_FLAG(list->flag, LIST_DYNAMIC_MODE)) { if (list->index[id]) list_del_dynamic_record(list, id); - list->index[id] = (byte*)malloc(nbyte + sizeof(DynLenFlag)); + list->index[id] = (byte*)malloc(nbyte + sizeof(rlen_t)); if (!list->index[id]) return NULL; - *(DynLenFlag*)list->index[id] = nbyte; - list->length += (nbyte + sizeof(DynLenFlag)); + *(rlen_t*)list->index[id] = nbyte; + list->length += (nbyte + sizeof(rlen_t)); list->counter++; - return list->index[id] + sizeof(DynLenFlag); + return list->index[id] + sizeof(rlen_t); } else { /* LIST_STATIC_MODE */ if (nbyte > list->blen) return NULL; @@ -437,7 +458,7 @@ void *list_get_dynamic_record(list_t *list, uint id) return NULL; else { if (list->index[id]) - return (list->index[id] + sizeof(DynLenFlag)); + return (list->index[id] + sizeof(rlen_t)); else return NULL; } @@ -447,7 +468,7 @@ uint list_get_record_len(list_t *list, uint id) { if (TEST_FLAG(list->flag, LIST_DYNAMIC_MODE)) { if (list->index[id]) - return *(DynLenFlag*)list->index[id]; + return *(rlen_t*)list->index[id]; else return 0; } @@ -455,7 +476,7 @@ uint list_get_record_len(list_t *list, uint id) return list->blen; } -ls_status_t list_del_record(list_t *list, uint id) +lsw_t list_del_record(list_t *list, uint id) { if (TEST_FLAG(list->flag, LIST_DYNAMIC_MODE)) return list_del_dynamic_record(list, id); @@ -463,7 +484,7 @@ ls_status_t list_del_record(list_t *list, uint id) return list_del_static_record(list, id); } -ls_status_t list_del_static_record(list_t *list, uint id) +lsw_t list_del_static_record(list_t *list, uint id) { if (id >= list->scale) return LSS_BAD_ID; @@ -471,13 +492,13 @@ ls_status_t list_del_static_record(list_t *list, uint id) return LSS_SUCCESS; } -ls_status_t list_del_dynamic_record(list_t *list, uint id) +lsw_t list_del_dynamic_record(list_t *list, uint id) { if (id >= list->scale) return LSS_BAD_ID; if (list->index[id]) { - list->length -= sizeof(DynLenFlag); - list->length -= *(DynLenFlag*)list->index[id]; + list->length -= sizeof(rlen_t); + list->length -= *(rlen_t*)list->index[id]; list->counter--; free(list->index[id]); list->index[id] = NULL; @@ -485,7 +506,7 @@ ls_status_t list_del_dynamic_record(list_t *list, uint id) return LSS_SUCCESS; } -ls_status_t list_swap_record(list_t *list, +lsw_t list_swap_record(list_t *list, uint id1, uint id2) { if (TEST_FLAG(list->flag, LIST_DYNAMIC_MODE)) @@ -494,7 +515,7 @@ ls_status_t list_swap_record(list_t *list, return list_swap_static_record(list, id1, id2); } -ls_status_t list_swap_static_record(list_t *list, +lsw_t list_swap_static_record(list_t *list, uint id1, uint id2) { if (id1 >= list->scale || id2 >= list->scale) @@ -504,7 +525,7 @@ ls_status_t list_swap_static_record(list_t *list, return LSS_SUCCESS; } -ls_status_t list_swap_dynamic_record(list_t *list, +lsw_t list_swap_dynamic_record(list_t *list, uint id1, uint id2) { byte *p; @@ -517,7 +538,7 @@ ls_status_t list_swap_dynamic_record(list_t *list, } #ifdef ENABLE_FOPS - ls_status_t list_export(list_t *list, const char *path, + lsw_t list_export(list_t *list, const char *path, const char *mode) { if (TEST_FLAG(list->flag, LIST_DYNAMIC_MODE)) @@ -547,7 +568,7 @@ ls_status_t list_swap_dynamic_record(list_t *list, } #ifdef ENABLE_ZLIB - static ls_status_t _list_export_static_zlib(list_t *list, + static lsw_t _list_export_static_zlib(list_t *list, const char *path, const char *mode) { ZLIB_FILE fp; @@ -557,7 +578,7 @@ ls_status_t list_swap_dynamic_record(list_t *list, } #endif - static ls_status_t _list_export_static_ansic(list_t *list, + static lsw_t _list_export_static_ansic(list_t *list, const char *path, const char *mode) { IO_FILE fp; @@ -566,7 +587,7 @@ ls_status_t list_swap_dynamic_record(list_t *list, return LSS_SUCCESS; } - ls_status_t list_export_static(list_t *list, const char *path, + lsw_t list_export_static(list_t *list, const char *path, const char *mode) { if (!mode) mode = LIST_EXPORT_MODE_DEF; @@ -585,11 +606,11 @@ ls_status_t list_swap_dynamic_record(list_t *list, #define PROCESS_EXPORT_DYN_RECORD(PREFIX) \ if (list->index[sc]) { \ if (!_is_little_endian()) \ - _memrev(list->index[sc], sizeof(DynLenFlag)); \ - PREFIX##fwrite(list->index[sc], sizeof(DynLenFlag) + \ - *(DynLenFlag*)list->index[sc], 1, fp); \ + _memrev(list->index[sc], sizeof(rlen_t)); \ + PREFIX##fwrite(list->index[sc], sizeof(rlen_t) + \ + *(rlen_t*)list->index[sc], 1, fp); \ if (!_is_little_endian()) { \ - _memrev(list->index[sc], sizeof(DynLenFlag)); \ + _memrev(list->index[sc], sizeof(rlen_t)); \ _memrev(&sc, sizeof(uint)); \ } \ PREFIX##fwrite(&sc, sizeof(uint), 1, fp); \ @@ -621,7 +642,7 @@ ls_status_t list_swap_dynamic_record(list_t *list, } #ifdef ENABLE_ZLIB - static ls_status_t _list_export_dynamic_zlib(list_t *list, + static lsw_t _list_export_dynamic_zlib(list_t *list, const char *path, const char *mode) { ZLIB_FILE fp; @@ -631,7 +652,7 @@ ls_status_t list_swap_dynamic_record(list_t *list, } #endif - static ls_status_t _list_export_dynamic_ansic(list_t *list, + static lsw_t _list_export_dynamic_ansic(list_t *list, const char *path, const char *mode) { IO_FILE fp; @@ -640,7 +661,7 @@ ls_status_t list_swap_dynamic_record(list_t *list, return LSS_SUCCESS; } - ls_status_t list_export_dynamic(list_t *list, const char *path, + lsw_t list_export_dynamic(list_t *list, const char *path, const char *mode) { if (!mode) @@ -667,19 +688,19 @@ ls_status_t list_swap_dynamic_record(list_t *list, return NULL; \ } \ memset(list->index, 0, list->scale * sizeof(byte*)); \ - while (PREFIX##fread(&len, sizeof(DynLenFlag), 1, fp)) { \ + while (PREFIX##fread(&len, sizeof(rlen_t), 1, fp)) { \ if (!_is_little_endian()) \ - _memrev(&len, sizeof(DynLenFlag)); \ - tmp = (byte*)malloc(len + sizeof(DynLenFlag)); \ + _memrev(&len, sizeof(rlen_t)); \ + tmp = (byte*)malloc(len + sizeof(rlen_t)); \ if (!tmp) { \ list->status |= LIST_IMPORT_ERROR; \ list->status |= LIST_MALLOC_ERROR; \ PREFIX##fclose(fp); \ return list; \ } \ - *(DynLenFlag*)tmp = len; \ + *(rlen_t*)tmp = len; \ PREFIX##fread(tmp + \ - sizeof(DynLenFlag), len, 1, fp); \ + sizeof(rlen_t), len, 1, fp); \ PREFIX##fread(&id, sizeof(uint), 1, fp); \ if (!_is_little_endian()) \ _memrev(&id, sizeof(uint)); \ @@ -701,7 +722,7 @@ ls_status_t list_swap_dynamic_record(list_t *list, byte *tmp; \ uint name_len = 0; \ uint id = 0; \ - DynLenFlag len = 0; \ + rlen_t len = 0; \ fp = PREFIX##fopen(path, "rb"); \ if (!fp) \ return NULL; \ @@ -831,7 +852,7 @@ ls_status_t list_swap_dynamic_record(list_t *list, return list; } - ls_status_t list_del_shared(list_t *list) + lsw_t list_del_shared(list_t *list) { uint shmlen; if (TEST_FLAG(list->flag, LIST_SHARED_USER)) @@ -920,71 +941,150 @@ ls_status_t list_swap_dynamic_record(list_t *list, } #endif /* ENABLE_SSHM */ -ls_status_t list_calc_hash_id(list_t *list, - void *data, uint len, uint arg, uint *id, __hashFx) +ccnt_t list_get_record_counter(list_t *list, uint id) +{ + if (TEST_FLAG(list->flag, LIST_DYNAMIC_MODE)) { + if (list->index[id]) + return 1; + else + return 0; + } else { /* LIST_STATIC_MODE */ + if (TEST_FLAG(list->flag, LIST_HASH_TABLE)) + return (*(ccnt_t*)(list->mem + id * list->blen)) >> 1; + } + return 1; +} + +int list_hash_table_test_id(list_t *list, uint id) +{ + return (*(ccnt_t*)(list->mem + id * list->blen)) & 1; +} + +list_t *list_new_hash_table(uint scale, uint blen) +{ + list_t *list; + if (!blen) /* support LIST_STATIC_MODE only */ + return NULL; + list = list_new_static(scale, blen + sizeof(ccnt_t)); + if (!list) + return NULL; + SET_FLAG(list->flag, LIST_UNRESIZABLE); + SET_FLAG(list->flag, LIST_HASH_TABLE); + return list; +} + +lsw_t list_hash_id_calc(list_t *list, + const void *data, uint *hi, uint *id) { uint nhash, cid; - if (hfx == NULL) - hfx = _djb_hash; - nhash = hfx(data, len, arg) % list->scale; + nhash = _hfx(data, _seed) % list->scale; + *hi = nhash; cid = nhash; - if (TEST_FLAG(list->flag, LIST_DYNAMIC_MODE)) { - while (list->index[cid]) { - cid++; - if (cid == list->scale) - cid = 0; - if (cid == nhash) - return LSS_ERR_LISTFULL; + while (list_hash_table_test_id(list, cid)) { + cid++; + if (cid == list->scale) + cid = 0; + if (cid == nhash) + return LSS_ERR_LISTFULL; + } + *id = cid; + return LSS_SUCCESS; +} + +lsw_t list_hash_table_insert(list_t *list, + const void *record, uint len) +{ + uint hi, id, dlen; + ccnt_t *hrec, *rrec; + lsw_t stat; + if (TEST_FLAG(list->flag, LIST_DYNAMIC_MODE)) + return LSS_BAD_OBJ; + if ((stat = list_hash_id_calc(list, record, &hi, &id))) + return stat; + hrec = (ccnt_t*)(list->mem + hi * list->blen); + rrec = (ccnt_t*)(list->mem + id * list->blen); + dlen = list->blen - sizeof(ccnt_t); + if (CCNT_VAL(*hrec) == CCNT_MAX) + return LSS_CCNT_MAX; + memcpy(rrec + 1, record, len > dlen ? dlen : len); + (*hrec) += CCNT_INC; + (*rrec) |= 1; /* SET FLAG */ + return LSS_SUCCESS; +} + +lsw_t list_hash_table_find(list_t *list, const void *key, uint *id) +{ + uint nhash, cid; + byte *rec; + ccnt_t nrec; + if (TEST_FLAG(list->flag, LIST_DYNAMIC_MODE)) + return LSS_BAD_OBJ; + nhash = _hfx(key, _seed) % list->scale; + cid = nhash; + rec = list->mem + cid * list->blen; + nrec = (*(ccnt_t*)(list->mem + cid * list->blen)) >> 1; + if (!nrec) + return LSS_OBJ_NOFOUND; + while (nrec--) { + if (_hfx(rec + sizeof(ccnt_t), + _seed) % list->scale == nhash) { + if (!_cmp(rec + sizeof(ccnt_t), key)) { + *id = cid; + return LSS_SUCCESS; + } } - } else { /* LIST_STATIC_MODE */ - while (list_test_record(list, cid, 0, list->blen)) { - cid++; - if (cid == list->scale) - cid = 0; - if (cid == nhash) - return LSS_ERR_LISTFULL; + cid++; + if (cid == nhash) + return LSS_OBJ_NOFOUND; + if (cid == list->scale) { + cid = 0; + rec = list->mem; + } else { + rec += list->blen; } } - *id = cid; return LSS_SUCCESS; } -ls_status_t list_search_by_hash(list_t *list, - void *data, uint len, uint arg, __hashFx, - __compFx, void *pattern, uint plen, uint *fid) +lsw_t list_hash_table_del(list_t *list, const void *key) { uint nhash, id; - if (hfx == NULL) - hfx = _djb_hash; - nhash = hfx(data, len, arg) % list->scale; + byte *rec, *csr; + ccnt_t nrec; + if (TEST_FLAG(list->flag, LIST_DYNAMIC_MODE)) + return LSS_BAD_OBJ; + nhash = _hfx(key, _seed) % list->scale; + rec = list->mem + nhash * list->blen; + csr = rec; + nrec = (*(ccnt_t*)rec) >> 1; + if (!nrec) + return LSS_SUCCESS; id = nhash; - if (TEST_FLAG(list->flag, LIST_DYNAMIC_MODE)) { - while (list->index[id]) { - if (!cfx(list->index[id] + - sizeof(DynLenFlag), pattern, plen)) { - *fid = id; - return LSS_SUCCESS; + while (1) { + if (_hfx(csr + sizeof(ccnt_t), + _seed) % list->scale == nhash) { + if (!_cmp(csr + sizeof(ccnt_t), key)) { + nrec--; + if (!nrec) + break; } - id++; - if (id == list->scale) - id = 0; - if (id == nhash) - return LSS_OBJ_NOFOUND; } - } else { /* LIST_STATIC_MODE */ - while (list_test_record(list, id, 0, list->blen)) { - if (!cfx(list->index[id], pattern, plen)) { - *fid = id; - return LSS_SUCCESS; - } - id++; - if (id == list->scale) - id = 0; - if (id == nhash) + id++; + if (id == nhash) { + if (nrec) return LSS_OBJ_NOFOUND; + return LSS_BAD_OBJ; + } + if (id == list->scale) { + id = 0; + csr = list->mem; + } else { + csr += list->blen; } } - return LSS_OBJ_NOFOUND; + (*(ccnt_t*)csr) ^= 1; /* CLR FLAG */ + (*(ccnt_t*)rec) -= CCNT_INC; + return LSS_SUCCESS; } void list_print_info(list_t *list, void *stream) @@ -1014,10 +1114,10 @@ void list_print_info(list_t *list, void *stream) fprintf(fp, "[block length] = %d\n", list->blen); } -void operation_status(ls_status_t ops_stat) +void list_print_status(lsw_t stat, void *stream) { - FILE *fp = stderr; - switch (ops_stat) { + FILE *fp = stream ? (FILE*)stream : stdout; + switch (stat) { case LSS_SUCCESS: fprintf(fp, "Operation Succeeded!\n"); break; @@ -1056,3 +1156,4 @@ void operation_status(ls_status_t ops_stat) break; } } + diff --git a/src/util_list.h b/src/util_list.h index 5db35dc..64c9b85 100644 --- a/src/util_list.h +++ b/src/util_list.h @@ -12,21 +12,23 @@ #define uint unsigned int #endif -typedef unsigned char ls_status_t; +typedef unsigned char lsw_t; /*========== operation status ===========*/ -#define LSS_STATUS_ -#define LSS_SUCCESS 0x00 -#define LSS_BAD_ID 0x01 -#define LSS_MALLOC_ERR 0x02 -#define LSS_DYN_ID_EXIST 0x03 -#define LSS_BAD_OBJ 0x04 -#define LSS_ARG_ILL 0x05 -#define LSS_LNAME_ERR 0x06 -#define LSS_FILE_ERR 0x07 -#define LSS_SHM_ERR 0x08 -#define LSS_ERR_LISTFULL 0x09 -#define LSS_OBJ_NOFOUND 0x0A +enum LSS_STATUS_ { + LSS_SUCCESS = 0, + LSS_BAD_ID, + LSS_MALLOC_ERR, + LSS_DYN_ID_EXIST, + LSS_BAD_OBJ, + LSS_ARG_ILL, + LSS_LNAME_ERR, + LSS_FILE_ERR, + LSS_SHM_ERR, + LSS_ERR_LISTFULL, + LSS_OBJ_NOFOUND, + LSS_CCNT_MAX +}; #define SET_BIT(val, bitn) (val |=(1<<(bitn))) #define CLR_BIT(val, bitn) (val&=~(1<<(bitn))) @@ -37,8 +39,22 @@ typedef unsigned char ls_status_t; #define TEST_FLAG(flag, bft) \ !(((bft & 0x0F) << (bft >> 4)) ^ (flag & (1 << (bft >> 4)))) -#define DYN_LENGTH_TYPE uint -typedef DYN_LENGTH_TYPE DynLenFlag; +/* + * CONFLICT_COUNTER: Only used in hast table under static mode, limited + * the number of conflicted records to 127 + * 0 1 2 3 4 5 6 7 + * x x x x x x x f + * \__.KEPT THIS BIT + */ +#define CCNT_INC 0x02 /* (1 << 1)*/ +#define CCNT_MAX 0x7F +#define CCNT_VAL(cnt) (cnt >> 1) + +#define CONFLICT_COUNTER byte +#define REC_LENGTH_TYPE uint + +typedef CONFLICT_COUNTER ccnt_t; +typedef REC_LENGTH_TYPE rlen_t; /* Do not edit LIST_NAME_LEN unless necessary */ #ifndef LIST_NAME_LEN @@ -53,7 +69,7 @@ typedef DYN_LENGTH_TYPE DynLenFlag; * Record on dynamic mode : * uint length | record |, when export : * uint length | record | id - * Notice: length of a dynamic record will not count DynLenFlag + * Notice: length of a dynamic record will not count rlen_t * * index record(Each record will allocate memory via "malloc") * index0----->rec0 @@ -102,6 +118,8 @@ struct list_info { #define LIST_FLAG_DEFAULT 0x00 #define LIST_STATIC_MODE 0x00 #define LIST_DYNAMIC_MODE 0x01 +#define LIST_HASH_NOT_SET 0x40 +#define LIST_HASH_TABLE 0x41 #define LIST_RESIZABLE 0x50 #define LIST_UNRESIZABLE 0x51 #define LIST_SHARED_USER 0x60 @@ -116,11 +134,7 @@ struct list_info { #define LIST_MALLOC_ERROR 0x01 #define LIST_IMPORT_ERROR 0x02 -/* Tips: - * Overload "list_new" under cpp - * list_t *list_new(uint scale); - * list_t *list_new(uint scale, uint blen); - */ +list_t *list_new(uint scale, uint blen); list_t *list_new_static(uint scale, uint blen); list_t *list_new_dynamic(uint scale); @@ -128,25 +142,24 @@ list_t *list_clone(list_t *list); list_t *list_clone_static(list_t *list); list_t *list_clone_dynamic(list_t *list); -ls_status_t list_del(list_t *list); -ls_status_t list_del_static(list_t *list); -ls_status_t list_del_dynamic(list_t *list); +lsw_t list_del(list_t *list); +lsw_t list_del_static(list_t *list); +lsw_t list_del_dynamic(list_t *list); -ls_status_t list_resize(list_t *list, uint newScale); -ls_status_t list_resize_static(list_t *list, uint newScale); -ls_status_t list_resize_dynamic(list_t *list, uint newScale); +lsw_t list_resize(list_t *list, uint newScale); +lsw_t list_resize_static(list_t *list, uint newScale); +lsw_t list_resize_dynamic(list_t *list, uint newScale); -ls_status_t list_set_name(list_t *list, const char *name); +lsw_t list_set_name(list_t *list, const char *name); -ls_status_t list_set_record(list_t *list, uint id, +lsw_t list_set_record(list_t *list, uint id, const void *record, uint len); -ls_status_t list_set_static_record(list_t *list, uint id, +lsw_t list_set_static_record(list_t *list, uint id, const void *record, uint len); -ls_status_t list_set_dynamic_record(list_t *list, uint id, +lsw_t list_set_dynamic_record(list_t *list, uint id, const void *record, uint len); -int list_test_record(list_t *list, uint id, uint offset, - uint nbyte); +int list_test_record(list_t *list, uint id, uint offset, uint nbyte); void *list_alloc(list_t *list, uint id, uint nbyte); @@ -157,18 +170,15 @@ void *list_get_dynamic_record(list_t *list, uint id); uint list_get_record_len(list_t *list, uint id); /* #define list_get_static_record_len */ #define list_get_dynamic_record_len(r) \ - (*((DynLenFlag*)((unsigned char*)r - sizeof(DynLenFlag)))) + (*((rlen_t*)((unsigned char*)r - sizeof(rlen_t)))) -ls_status_t list_del_record(list_t *list, uint id); -ls_status_t list_del_static_record(list_t *list, uint id); -ls_status_t list_del_dynamic_record(list_t *list, uint id); +lsw_t list_del_record(list_t *list, uint id); +lsw_t list_del_static_record(list_t *list, uint id); +lsw_t list_del_dynamic_record(list_t *list, uint id); -ls_status_t list_swap_record(list_t *list, - uint id1, uint id2); -ls_status_t list_swap_static_record(list_t *list, - uint id1, uint id2); -ls_status_t list_swap_dynamic_record(list_t *list, - uint id1, uint id2); +lsw_t list_swap_record(list_t *list, uint id1, uint id2); +lsw_t list_swap_static_record(list_t *list, uint id1, uint id2); +lsw_t list_swap_dynamic_record(list_t *list, uint id1, uint id2); #define IO_FILE FILE* #define IO_fopen fopen @@ -196,21 +206,21 @@ ls_status_t list_swap_dynamic_record(list_t *list, #define LIST_EXPORT_MODE_DEF "wb" #endif -ls_status_t list_export(list_t *list, const char *path, +lsw_t list_export(list_t *list, const char *path, const char *mode); /* * Exported file structure of Static LIST * name_len | list->name | list | list->mem */ -ls_status_t list_export_static(list_t *list, const char *path, +lsw_t list_export_static(list_t *list, const char *path, const char *mode); /* * Exported file structure of Dynamic LIST * name_len | list->name | list | *index[0:N] */ -ls_status_t list_export_dynamic(list_t *list, const char *path, +lsw_t list_export_dynamic(list_t *list, const char *path, const char *mode); list_t *list_import(const char *path); @@ -230,33 +240,53 @@ list_t *list_import(const char *path); list_t *list_link_shared(uint len, uint key); #define list_shared_shm_len(list) \ (sizeof(LIST) + LIST_NAME_LEN + list->length) - ls_status_t list_del_shared(list_t *list); + lsw_t list_del_shared(list_t *list); #define list_export_shared list_export_static list_t *list_import_shared(const char *path, uint key); #endif /* ENABLE_SSHM */ -/* - * simple hash function - */ -#define __hashFx uint hfx(void*, uint, uint) -#define __compFx int cfx(void*, void*, uint) - #define list_set_unresizable(list) \ SET_FLAG(list->flag, LIST_UNRESIZABLE) #define list_set_resizable(list) \ SET_FLAG(list->flag, LIST_RESIZABLE) +/* + * Hash table functions, LIST_STATIC_MODE only - | Counter | Data | + */ +typedef uint (*__hashFx)(const void*, uint); +typedef int (*__compFx)(const void*, const void*); -ls_status_t list_calc_hash_id(list_t *list, - void *data, uint len, uint arg, uint *id, __hashFx); +void list_set_hash_fn(__hashFx hfx); +void list_set_hash_seed(uint seed); -ls_status_t list_search_by_hash(list_t *list, - void *data, uint len, uint arg, __hashFx, +int list_hash_table_test_id(list_t *list, uint id); + +ccnt_t list_get_record_counter(list_t *list, uint id); + +list_t *list_new_hash_table(uint scale, uint blen); + +lsw_t list_hash_id_calc(list_t *list, + const void *data, uint *hi, uint *id); + +lsw_t list_hash_table_insert(list_t *list, + const void *record, uint len); + +lsw_t list_hash_table_find(list_t *list, const void *key, uint *id); + +lsw_t list_hash_table_del(list_t *list, const void *key); + +/* +lsw_t list_calc_hash_id(list_t *list, + void *data, uint len, uint seed, uint *id, __hashFx); + +lsw_t list_search_by_hash(list_t *list, + void *data, uint len, uint seed, __hashFx, __compFx, void *pattern, uint plen, uint *fid); +*/ /*================= Debug =================*/ #define list_ops operation_status void list_print_info(list_t *list, void *stream); -void operation_status(ls_status_t ops_stat); +void list_print_status(lsw_t stat, void *stream); #undef byte #undef uint @@ -266,3 +296,4 @@ void operation_status(ls_status_t ops_stat); #endif #endif /* _LIST_H_ */ +