diff --git a/src/binary_c_code_options.h b/src/binary_c_code_options.h index a730013705105d9af1faf774b5a09624d0aa783a..6e4a5c3a269edf4a79ef21308df4247708e3fa1d 100644 --- a/src/binary_c_code_options.h +++ b/src/binary_c_code_options.h @@ -1086,5 +1086,14 @@ void Print_trace(void); */ //#define STARDATA_DIFFSTATS +/* + * Improved command-line argument parser: this maps + * the cmd_line_args array to a set of data indexed by the + * first character of each argument. Thus there is a little + * memory cost, but it takes ~20% of the time to parse + * arguments. + */ +#define ALPHA_ARGS + #endif //BINARY_C_CODE_OPTIONS_H diff --git a/src/binary_c_function_macros.h b/src/binary_c_function_macros.h index 2691b13e73571c6f16a50ec9b998ac7a44e537c1..e8f55b81b48fdda3f88ff8f3c7c9bf8d325fbdf9 100644 --- a/src/binary_c_function_macros.h +++ b/src/binary_c_function_macros.h @@ -1491,5 +1491,13 @@ #define Strings_equal(A,B) (strcmp((A),(B))==0) #define Memory_equal(A,B,C) (memcmp((A),(B),(C))==0) + +/* + * ASCII convenience macros + */ +#define ASCII_upper_case(N) Boolean_((N)>64 && (N)<91) +#define ASCII_lower_case(N) Boolean_((N)>96 && (N)<123) +#define ASCII_letter(N) (ASCII_lower_case(N) || ASCII_upper_case(N)) + #endif // BINARY_C_FUNCTION_MACROS_H diff --git a/src/binary_c_structures.h b/src/binary_c_structures.h index 3af4b9b1cede160af017f58a82d4f86473f52c01..473603f7b3f3be66e6d0d74e00ec5c14e728793d 100644 --- a/src/binary_c_structures.h +++ b/src/binary_c_structures.h @@ -277,6 +277,8 @@ struct store_t { * the evolution loop, when a system is not being evolved. * Thus the tmpstore will not disappear during stellar evolution. * + * You should not free the tmpstore yourself, use free_tmpstore. + * * The tmpstore should be considered as non-persistent storage, * so any data that is not required outside a subroutine should * only be allocated and freed inside that subroutine. @@ -284,6 +286,10 @@ struct store_t { */ struct tmpstore_t { struct cmd_line_arg_t *cmd_line_args; +#ifdef ALPHA_ARGS + struct cmd_line_arg_t ** cmd_line_args_alpha; + unsigned int * cmd_line_args_alpha_count; +#endif//ALPHA_ARGS #ifdef KICK_CDF_TABLE struct data_table_t * cdf_table; #endif//KICK_CDF_TABLE diff --git a/src/setup/parse_arguments.c b/src/setup/parse_arguments.c index 489b378be5ec8dea2846e25b128e0877bf635b33..1255761d9fed219ea11532df0e12d0b0e2fefecb 100644 --- a/src/setup/parse_arguments.c +++ b/src/setup/parse_arguments.c @@ -4,6 +4,10 @@ #include "cmd_line_function_macros.h" #include "cmd_line_macro_pairs.h" +#ifdef ALPHA_ARGS +#define Aprint(...) /* do nothing */ +#endif//ALPHA_ARGS + static Boolean match_scanf(char * arg, struct cmd_line_arg_t * cmd_line_arg, int * offset_p); @@ -22,8 +26,16 @@ void parse_arguments(const int start, * and rebuild. Do NOT change this function! * * See also argument_setting_functions.c and batchmode.c + * + * If argv is NULL, this is a call to set up our part + * of the tmpstore, after which we just return without parsing. + * + * Similarly, if stardata->tmpstore->cmd_line_args + * is NULL by argv is non-NULL, we set up the tmpstore, and then + * we parse the arguments. */ - if(argv==NULL) + if(unlikely(argv==NULL || + stardata->tmpstore->cmd_line_args == NULL)) { /* make static table */ struct tmpstore_t * tmpstore = stardata->tmpstore; @@ -50,20 +62,103 @@ void parse_arguments(const int start, set_cmd_line_macro_pairs(stardata, cmd_line_args2, arg_count); + +#ifdef ALPHA_ARGS + /* + * Allocate space for the alpha map: this is + * an array of pointers with index given by the + * a map from the first character to an index + * between 0 and 51 (inclusive). + */ + tmpstore->cmd_line_args_alpha = + Malloc(sizeof(struct cmd_line_arg_t *)*26*2); + + /* + * Set all counts to zero + */ + tmpstore->cmd_line_args_alpha_count = Calloc(26*2,sizeof(unsigned int)); + + unsigned int u; + for(u=0;u<2;u++) + { + /* + * u = 0 -> lower case + * u = 1 -> upper case + */ + unsigned int a; + const unsigned int offset = u == 0 ? 97 : 65; + for(a=0;a<26;a++) + { + /* + * Hence the char that is the first letter + */ + unsigned char c = offset + a; + const unsigned int index = a + u * 26; + Aprint("allocate alpha structure %d (char %d = %c = %c)\n", + a, + (int)c, + offset+a, + c); + /* + * NULL the array (its index is zero, set by memset above) + */ + tmpstore->cmd_line_args_alpha[index] = NULL; + + /* + * Loop over cmd_line_args2 to find the appropriate + * mapping + */ + for(i=0;i<arg_count;i++) + { + if(cmd_line_args2[i].name[0] == c) + { + Aprint("mapped arg %s here\n", + cmd_line_args2[i].name); + /* + * Increase size + */ + tmpstore->cmd_line_args_alpha[index] = Realloc( + tmpstore->cmd_line_args_alpha[index], + sizeof(struct cmd_line_arg_t) * + (1+tmpstore->cmd_line_args_alpha_count[index])); + + /* + * Copy the arg data into the sublist + */ + memcpy(&tmpstore->cmd_line_args_alpha[index][tmpstore->cmd_line_args_alpha_count[index]], + &cmd_line_args2[i], + sizeof(struct cmd_line_arg_t)); + + /* + * Expand count for the next item + */ + tmpstore->cmd_line_args_alpha_count[index]++; + + Aprint("new count[index=%d] %d\n", + index, + tmpstore->cmd_line_args_alpha_count[index]); + } + } + } + } +#endif // ALPHA_ARGS /* copy to tmpstore */ Dprint("Allocate %zu bytes for cmd_line_args table\n", sizeof(cmd_line_args2)); if(tmpstore->cmd_line_args==NULL) + { tmpstore->cmd_line_args=Malloc(sizeof(cmd_line_args2)); - memcpy(tmpstore->cmd_line_args,cmd_line_args2,sizeof(cmd_line_args2)); + } + memcpy(tmpstore->cmd_line_args, + cmd_line_args2, + sizeof(cmd_line_args2)); tmpstore->arg_count = arg_count; Dprint("Arg table built : we have %d args (argc=%d)\n", tmpstore->arg_count,argc); - - return; } - else + + if(likely(argv != NULL)) { /* * Parse command line arguments @@ -91,13 +186,64 @@ void parse_arguments(const int start, /* ignore leading -- */ if((arg[0]=='-') && (arg[1]=='-')) arg += 2; - + + +#ifdef ALPHA_ARGS + /* + * Override cmd_line_args with the appropriate + * alpha-selected list + */ + Aprint("Check arg %s first char %c (ASCII letter? %s : upper case? %s, lower case? %s)\n", + arg, + arg[0], + Yesno(ASCII_letter(arg[0])), + Yesno(ASCII_upper_case(arg[0])), + Yesno(ASCII_lower_case(arg[0])) + ); + + int arg_count; + if(ASCII_letter(arg[0])) + { + /* + * First character is a letter: use the alpha map + */ + const unsigned int u = ASCII_lower_case(arg[0]) ? 0 : 1; + const unsigned int offset = u == 0 ? 97 : 65; + const unsigned int index = arg[0] - offset + 26 * u; + + arg_count = stardata->tmpstore->cmd_line_args_alpha_count[index]; + cmd_line_args = stardata->tmpstore->cmd_line_args_alpha[index]; + Aprint("Using alpha map for %c (offset %d) index %d : arg_count = %d\n", + arg[0],offset,index,arg_count); + } + else + { + /* + * Not ASCII : use the whole store + */ + arg_count = stardata->tmpstore->arg_count; + cmd_line_args = stardata->tmpstore->cmd_line_args; + } +#else + /* + * No map: check the whole cmd_line_args in tmpstore + */ + const int arg_count = stardata->tmpstore->arg_count; + cmd_line_args = stardata->tmpstore->cmd_line_args; +#endif//ALPHA_ARGS + + /* check this argument against all those in the list */ int i,offset; Boolean success=FALSE; - for(i=0;i<stardata->tmpstore->arg_count;i++) - { - //Dprint("compare \"%s\" and \"%s\"\n",arg,cmd_line_args[i].name); + + for(i=0;i< +#ifndef ALPHA_ARGS + stardata->tmpstore-> +#endif//!ALPHA_ARGS + arg_count;i++) + { + Dprint("compare \"%s\" and \"%s\"\n",arg,cmd_line_args[i].name); if( Strings_equal(arg,cmd_line_args[i].name) || @@ -105,7 +251,7 @@ void parse_arguments(const int start, cmd_line_args[i].type == ARG_FLOAT_SCANF) && match_scanf(arg,&cmd_line_args[i],&offset) == TRUE) ) - + { Dprint("match \"%s\" (at arg table %d, type %d, pointer %p : cf log_filename at %p) repeat = %d\n", arg, @@ -146,7 +292,7 @@ void parse_arguments(const int start, /* code to check if the next arg exists when it's required */ #define Next_arg_check if(c+1>argc || argv[c+1]==NULL) \ { \ - Exit_binary_c(BINARY_C_SETUP_UNKNOWN_ARGUMENT, \ + Exit_binary_c(BINARY_C_SETUP_UNKNOWN_ARGUMENT, \ "Exit because cmd line arg #%d \"%s\" requires a value which is not the next argument (c+1=%d argc=%d prev arg =\"%s\" next arg = \"%s\").", \ c, \ arg, \ @@ -225,17 +371,22 @@ void parse_arguments(const int start, cmd_line_args[i].type,i); } } - i = stardata->tmpstore->arg_count + 1; /* matched : break out of i loop */ + + i = +#ifndef ALPHA_ARGS + stardata->tmpstore-> +#endif//!ALPHA_ARGS + arg_count + 1; /* matched : break out of i loop */ } - } + } /* exit on error */ - if(success==FALSE) - { - Dprint( + if(success==FALSE) + { + Dprint( "Exit because given cmd line arg \"%s\" (number %d) failed to match any known argument.", arg,c); - Exit_binary_c( + Exit_binary_c( BINARY_C_SETUP_UNKNOWN_ARGUMENT, "Exit because given cmd line arg \"%s\" (number %d) failed to match any known argument (prev args are \"%s\" and \"%s\").", arg, @@ -243,8 +394,8 @@ void parse_arguments(const int start, argv[c<=1?0:c-2], argv[c<=0?1:c-1] ); - } - } /* loop over cmd line args */ + } + } /* loop over cmd line args */ Dprint("Finished processing cmd line arguments\n"); #ifdef DEBUG_FAIL_ON_NAN @@ -254,9 +405,9 @@ void parse_arguments(const int start, stardata->preferences->allow_debug_inf = allow_debug_inf_was; #endif - /* - * Special cases - */ +/* + * Special cases + */ if(Is_not_zero(stardata->star[0].mass) && Is_not_zero(stardata->star[1].mass)) { @@ -284,10 +435,10 @@ void parse_arguments(const int start, } - /* - * If we are using log times, choose the next max_evolution_time that - * correponds to an exact number of log timesteps - */ +/* + * If we are using log times, choose the next max_evolution_time that + * correponds to an exact number of log timesteps + */ #if defined NUCSYN && defined NUCSYN_YIELDS if(stardata->preferences->yields_logtimes == TRUE) { @@ -300,6 +451,7 @@ void parse_arguments(const int start, } } +/********************************************************************/ static Boolean match_scanf(char * arg, struct cmd_line_arg_t * cmd_line_arg, @@ -317,7 +469,7 @@ static Boolean match_scanf(char * arg, /* * Scan argpairs */ - int i; + unsigned int i; for(i=0; i<cmd_line_arg->nargpairs; i++) { if(Strings_equal(arg,cmd_line_arg->argpairs[i].string)) diff --git a/src/setup/version.c b/src/setup/version.c index b1e9225ee0e326dd669535287b4586b8d7122d3f..aaf08408f450d0eb5f27ae42431d7882fa618f53 100644 --- a/src/setup/version.c +++ b/src/setup/version.c @@ -768,6 +768,7 @@ void version(struct stardata_t * RESTRICT const stardata) #ifdef Debug_stop_expression Show_string_macro(Debug_stop_expression); #endif + Macrotest(ALPHA_ARGS); Macrotest(USE_ANSI_COLOURS); Macrotest(USE_POINTER_LOOPS);