[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Using gperf to allow switch-case over strings (in c++17)
From: |
Bruno Haible |
Subject: |
Re: Using gperf to allow switch-case over strings (in c++17) |
Date: |
Mon, 27 Dec 2021 15:16:31 +0100 |
Hello Viktor,
> > But it is a performance killer! gperf is meant to generate fast code,
> > and one of the necessary requirements is that the arrays are prepared
> > once only (and preferrably in read-only storage).
>
> I agree. I worried about this, but hadn't checked it so far.
>
> Without adding it to gperf sources yet, I manually made the tables
> static constexpr class-members (see attachment test.cpp). I'm not
> sure I understand the assembler code (-S) correctly, but I think
> this should solve the issue.
> @Bruno: What do you say about this version?
You can see and understand the generated code e.g. with the following commands:
g++ -std=c++17 -Wall -S -O -fno-inline -fno-asynchronous-unwind-tables
-fno-exceptions -fno-rtti test.cpp
versus
g++ -std=c++17 -Wall -S -O -fno-inline -fno-asynchronous-unwind-tables
-fno-exceptions -fno-rtti test_public.cpp
As you can see, the generated code for test.cpp (function 'hash') is short
and fast, as it should be.
Note: -std=c++17 works; whereas with -std=c++14 the arrays are omitted from
the code generation and thus produce a link error:
$ g++ -std=c++14 -Wall -O test.cpp
/usr/bin/ld: /tmp/ccX8EHUt.o: in function `main':
test.cpp:(.text+0x86): undefined reference to `Perfect_Hash::asso_values'
/usr/bin/ld: test.cpp:(.text+0x9a): undefined reference to
`Perfect_Hash::wordlist'
collect2: error: ld returned 1 exit status
Additionally, g++ version 7 or newer is needed:
$ g++-version 7.5.0 -std=c++17 -Wall -O test.cpp
$ g++-version 6.5.0 -std=c++17 -Wall -O test.cpp
/usr/bin/ld: /tmp/ccIxvjfr.o: in function `main':
test.cpp:(.text+0x6f): undefined reference to `Perfect_Hash::asso_values'
/usr/bin/ld: test.cpp:(.text+0x84): undefined reference to
`Perfect_Hash::wordlist'
collect2: error: ld returned 1 exit status
And how about other compilers, e.g. clang 13?
$ clang++ -S -std=c++17 -Wall -O test.cpp
test.gperf:19:15: error: constexpr function never produces a constant
expression [-Winvalid-constexpr]
constexpr int foo(const char* s)
^
test.gperf:21:47: note: non-constexpr function 'strlen' cannot be used in a
constant expression
const char* x = Perfect_Hash::in_word_set(s, strlen(s));
^
test.gperf:34:8: error: case value is not a constant expression
case foo("monday"):
^~~~~~~~~~~~~
test.gperf:21:47: note: non-constexpr function 'strlen' cannot be used in a
constant expression
const char* x = Perfect_Hash::in_word_set(s, strlen(s));
^
test.gperf:34:8: note: in call to 'foo(&"monday"[0])'
case foo("monday"):
^
test.gperf:35:8: error: case value is not a constant expression
case foo("tuesday"):
^~~~~~~~~~~~~~
test.gperf:21:47: note: non-constexpr function 'strlen' cannot be used in a
constant expression
const char* x = Perfect_Hash::in_word_set(s, strlen(s));
^
test.gperf:35:8: note: in call to 'foo(&"tuesday"[0])'
case foo("tuesday"):
^
test.gperf:36:8: error: case value is not a constant expression
case foo("wednesday"):
^~~~~~~~~~~~~~~~
test.gperf:21:47: note: non-constexpr function 'strlen' cannot be used in a
constant expression
const char* x = Perfect_Hash::in_word_set(s, strlen(s));
^
test.gperf:36:8: note: in call to 'foo(&"wednesday"[0])'
case foo("wednesday"):
^
test.gperf:37:8: error: case value is not a constant expression
case foo("thursday"):
^~~~~~~~~~~~~~~
test.gperf:21:47: note: non-constexpr function 'strlen' cannot be used in a
constant expression
const char* x = Perfect_Hash::in_word_set(s, strlen(s));
^
test.gperf:37:8: note: in call to 'foo(&"thursday"[0])'
case foo("thursday"):
^
test.gperf:38:8: error: case value is not a constant expression
case foo("friday"):
^~~~~~~~~~~~~
test.gperf:21:47: note: non-constexpr function 'strlen' cannot be used in a
constant expression
const char* x = Perfect_Hash::in_word_set(s, strlen(s));
^
test.gperf:38:8: note: in call to 'foo(&"friday"[0])'
case foo("friday"):
^
test.gperf:41:8: error: case value is not a constant expression
case foo("saturday"):
^~~~~~~~~~~~~~~
test.gperf:21:47: note: non-constexpr function 'strlen' cannot be used in a
constant expression
const char* x = Perfect_Hash::in_word_set(s, strlen(s));
^
test.gperf:41:8: note: in call to 'foo(&"saturday"[0])'
case foo("saturday"):
^
test.gperf:42:8: error: case value is not a constant expression
case foo("sunday"):
^~~~~~~~~~~~~
test.gperf:21:47: note: non-constexpr function 'strlen' cannot be used in a
constant expression
const char* x = Perfect_Hash::in_word_set(s, strlen(s));
^
test.gperf:42:8: note: in call to 'foo(&"sunday"[0])'
case foo("sunday"):
^
8 errors generated.
Likewise with '-std=c++20'.
So, test.cpp would work, but only with g++.
In my experience, it is a bad idea to build on features that only a single
C++ compiler supports. (I did that once, and regretted it deeply later.)
Therefore I would advise to wait until the various compilers implement
'constexpr' in the same way. If, by that time, strlen() is allowed in
'constexpr', it would be useful to extend gperf accordingly. Until then,
it is not useful.
Bruno