bug-gperf
[Top][All Lists]
Advanced

[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






reply via email to

[Prev in Thread] Current Thread [Next in Thread]