diff --git a/src/input.cc b/src/input.cc index 10aa3b6..ed0caad 100644 --- a/src/input.cc +++ b/src/input.cc @@ -544,6 +544,10 @@ Input::read_input () option.set (CONST); else + if (is_declaration (line, line_end, lineno, "constexpr")) + option.set (CONSTEXPR); + else + if (is_declaration (line, line_end, lineno, "enum")) option.set (ENUM); else diff --git a/src/options.cc b/src/options.cc index f710f47..4de086c 100644 --- a/src/options.cc +++ b/src/options.cc @@ -158,6 +158,8 @@ Options::long_usage (FILE * stream) fprintf (stream, " -C, --readonly-tables Make the contents of generated lookup tables\n" " constant, i.e., readonly.\n"); + fprintf (stream, + " -x, --constexpr Generate C++17 \"constexpr\" specifier where applicable\n"); fprintf (stream, " -E, --enum Define constant values using an enum local to the\n" " lookup function rather than with defines.\n"); @@ -528,6 +530,7 @@ Options::~Options () _option_word & LENTABLE ? "enabled" : "disabled", _option_word & COMP ? "enabled" : "disabled", _option_word & CONST ? "enabled" : "disabled", + _option_word & CONSTEXPR ? "enabled" : "disabled", _option_word & ENUM ? "enabled" : "disabled", _option_word & INCLUDE ? "enabled" : "disabled", _option_word & GLOBAL ? "enabled" : "disabled", @@ -700,6 +703,7 @@ static const struct option long_options[] = { "seven-bit", no_argument, NULL, '7' }, { "compare-strncmp", no_argument, NULL, 'c' }, { "readonly-tables", no_argument, NULL, 'C' }, + { "constexpr", no_argument, NULL, 'x' }, { "enum", no_argument, NULL, 'E' }, { "includes", no_argument, NULL, 'I' }, { "global-table", no_argument, NULL, 'G' }, @@ -1030,6 +1034,11 @@ There is NO WARRANTY, to the extent permitted by law.\n\ _wordlist_name = /*getopt*/optarg; break; } + case 'x': /* Generate C++17 "constexpr" specifier where applicable */ + { + _option_word |= CONSTEXPR; + break; + } case 'Z': /* Set the class name. */ { _class_name = /*getopt*/optarg; diff --git a/src/options.h b/src/options.h index ec83b6d..bab9cbd 100644 --- a/src/options.h +++ b/src/options.h @@ -70,46 +70,49 @@ enum Option_Type /* Make the generated tables readonly (const). */ CONST = 1 << 9, + /* Generate C++17 "constexpr" specifier where applicable */ + CONSTEXPR = 1 << 10, + /* Use enum for constants. */ - ENUM = 1 << 10, + ENUM = 1 << 11, /* Generate #include statements. */ - INCLUDE = 1 << 11, + INCLUDE = 1 << 12, /* Make the keyword table a global variable. */ - GLOBAL = 1 << 12, + GLOBAL = 1 << 13, /* Use NULL strings instead of empty strings for empty table entries. */ - NULLSTRINGS = 1 << 13, + NULLSTRINGS = 1 << 14, /* Optimize for position-independent code. */ - SHAREDLIB = 1 << 14, + SHAREDLIB = 1 << 15, /* Generate switch output to save space. */ - SWITCH = 1 << 15, + SWITCH = 1 << 16, /* Don't include user-defined type definition in output -- it's already defined elsewhere. */ - NOTYPE = 1 << 16, + NOTYPE = 1 << 17, /* --- Algorithm employed by gperf --- */ /* Use the given key positions. */ - POSITIONS = 1 << 17, + POSITIONS = 1 << 18, /* Handle duplicate hash values for keywords. */ - DUP = 1 << 18, + DUP = 1 << 19, /* Don't include keyword length in hash computations. */ - NOLENGTH = 1 << 19, + NOLENGTH = 1 << 20, /* Randomly initialize the associated values table. */ - RANDOM = 1 << 20, + RANDOM = 1 << 21, /* --- Informative output --- */ /* Enable debugging (prints diagnostics to stderr). */ - DEBUG = 1 << 21 + DEBUG = 1 << 22 }; /* Class manager for gperf program Options. */ diff --git a/src/output.cc b/src/output.cc index 1e289b3..daa912a 100644 --- a/src/output.cc +++ b/src/output.cc @@ -64,6 +64,12 @@ static const char *const_readonly_array; /* The "const " qualifier, for the array type. */ static const char *const_for_struct; +/* The "constexpr " qualifier */ +static const char *constexpr_qualifier; + +/* The "constexpr " replacement for "static " qualifiers */ +static const char *constexpr_or_static; + /* Returns the smallest unsigned C type capable of holding integers up to N. */ @@ -288,9 +294,9 @@ output_upperlower_table () printf ("#ifndef GPERF_DOWNCASE\n" "#define GPERF_DOWNCASE 1\n" - "static %sunsigned char gperf_downcase[256] =\n" + "%s%sunsigned char gperf_downcase[256] =\n" " {", - const_readonly_array); + constexpr_or_static, const_readonly_array); for (c = 0; c < 256; c++) { if ((c % 15) == 0) @@ -313,8 +319,9 @@ output_upperlower_strcmp () { printf ("#ifndef GPERF_CASE_STRCMP\n" "#define GPERF_CASE_STRCMP 1\n" - "static int\n" - "gperf_case_strcmp "); + "%sint\n" + "gperf_case_strcmp ", + constexpr_or_static); printf (option[KRC] ? "(s1, s2)\n" " %schar *s1;\n" @@ -364,8 +371,9 @@ output_upperlower_strncmp () { printf ("#ifndef GPERF_CASE_STRNCMP\n" "#define GPERF_CASE_STRNCMP 1\n" - "static int\n" - "gperf_case_strncmp "); + "%sint\n" + "gperf_case_strncmp ", + constexpr_or_static); printf (option[KRC] ? "(s1, s2, n)\n" " %schar *s1;\n" @@ -425,8 +433,9 @@ output_upperlower_memcmp () { printf ("#ifndef GPERF_CASE_MEMCMP\n" "#define GPERF_CASE_MEMCMP 1\n" - "static int\n" - "gperf_case_memcmp "); + "%sint\n" + "gperf_case_memcmp ", + constexpr_or_static); printf (option[KRC] ? "(s1, s2, n)\n" " %schar *s1;\n" @@ -826,6 +835,7 @@ Output::output_hash_function () const if (option[KRC] | option[C] | option[ANSIC]) printf ("static "); + printf ("%s", constexpr_qualifier); printf ("unsigned int\n"); if (option[CPLUSPLUS]) printf ("%s::", option.get_class_name ()); @@ -854,9 +864,9 @@ Output::output_hash_function () const { /* The values in the asso_values array are all unsigned integers <= MAX_HASH_VALUE + 1. */ - printf (" static %s%s asso_values[] =\n" + printf (" %s%s%s asso_values[] =\n" " {", - const_readonly_array, + constexpr_or_static, const_readonly_array, smallest_integral_type (_max_hash_value + 1)); const int columns = 10; @@ -1007,9 +1017,9 @@ Output::output_keylength_table () const const int columns = 14; const char * const indent = option[GLOBAL] ? "" : " "; - printf ("%sstatic %s%s %s[] =\n" + printf ("%s%s%s%s %s[] =\n" "%s {", - indent, const_readonly_array, + indent, constexpr_or_static, const_readonly_array, smallest_integral_type (_max_key_len), option.get_lengthtable_name (), indent); @@ -1119,10 +1129,10 @@ Output::output_string_pool () const printf ("%s };\n", indent); - printf ("%sstatic %sstruct %s_t %s_contents =\n" + printf ("%s%s%sstruct %s_t %s_contents =\n" "%s {\n", - indent, const_readonly_array, option.get_stringpool_name (), - option.get_stringpool_name (), indent); + indent, constexpr_or_static, const_readonly_array, + option.get_stringpool_name (), option.get_stringpool_name (), indent); for (temp = _head, index = 0; temp; temp = temp->rest()) { KeywordExt *keyword = temp->first(); @@ -1271,8 +1281,8 @@ Output::output_keyword_table () const int index; KeywordExt_List *temp; - printf ("%sstatic ", - indent); + printf ("%s%s", + indent, constexpr_or_static); output_const_type (const_readonly_array, _wordlist_eltype); printf ("%s[] =\n" "%s {\n", @@ -1998,8 +2008,8 @@ Output::output_lookup_function () const because non-static inline functions must not reference static functions or variables, see ISO C 99 section 6.7.4.(3). */ - printf ("%s%s\n", - const_for_struct, _return_type); + printf ("%s%s%s\n", + constexpr_qualifier, const_for_struct, _return_type); if (option[CPLUSPLUS]) printf ("%s::", option.get_class_name ()); printf ("%s ", option.get_function_name ()); @@ -2060,6 +2070,17 @@ Output::output () else register_scs = "register "; + if (option[CPLUSPLUS] && option[CONSTEXPR]) + { + constexpr_qualifier = "constexpr "; + constexpr_or_static = constexpr_qualifier; + } + else + { + constexpr_qualifier = ""; + constexpr_or_static = "static "; + } + if (option[C] | option[ANSIC] | option[CPLUSPLUS]) { const_always = "const "; @@ -2185,13 +2206,13 @@ Output::output () printf ("class %s\n" "{\n" "private:\n" - " static inline unsigned int %s (const char *str, size_t len);\n" + " static %sinline unsigned int %s (const char *str, size_t len);\n" "public:\n" - " static %s%s%s (const char *str, size_t len);\n" + " static %s%s%s%s (const char *str, size_t len);\n" "};\n" "\n", - option.get_class_name (), option.get_hash_name (), - const_for_struct, _return_type, option.get_function_name ()); + option.get_class_name (), constexpr_qualifier, option.get_hash_name (), + constexpr_qualifier, const_for_struct, _return_type, option.get_function_name ()); output_hash_function ();