dragonbox
dragonbox copied to clipboard
C++11?
I need a port of this to C++11
It'll be a lot of work. Since the new quarter has begun, I can't afford much time to it, but I'll try.
Would love it if C++11 version of this is made available. Great work guys!
I'm sure everyone here already knows this, but I'll mention it for those who don't: constexpr if
can be emulated in C++11 by tagged dispatching using std::true_type
and std::false_type
:
Instead of
if constexpr(condition)
{
do_this(arg1);
}
else
{
do_that(arg2);
}
one can do:
do_this_or_that(std::integral_constant<bool, condition>{}, arg1, arg2);
inline void do_this_or_that(std::true_type, int arg1, int arg2)
{
do_this(arg1);
}
inline void do_this_or_that(std::false_type, int arg1, int arg2)
{
do_that(arg2);
}
Any decent compiler will optimize this into the equivalent if constexpr
code.
The downside of course is more code, and the need to pass variables as arguments. The upside is compatibility with C++11 and (presumably) wider adoption.
std::bool_constant
doesn't exist prior to C++17, but one can easily define their own template alias that does the same thing:
template <bool condition>
using meta_bool = std::integral_constant<bool, condition>;
then
do_this_or_that(meta_bool<condition>{}, arg1, arg2);
EDIT: Added the missing inline
that I forgot.
According to this 2020 survey, 46% responded that they regularly use C++11, so it's far from being dead.
I can understand wanting to use the latest C++ features for writing an in-house application, but for open-source libraries, IMHO, it's better to be conservative in the minimum C++ version required if you want the widest possible adoption.
if you want the widest possible adoption.
GitHub stars and forks are what give my life meaning and value
GitHub stars and forks are what give my life meaning and value
@vinniefalco, I'm working on a serialization library intended to be used in conjunction with Asio and your Beast library. It's currently closed source, but I may be able to convince my employer to make it open source in the future. I'm deliberately constraining my serialization library to C++11 so that its language requirements matches that of yours. I would love to make use of Dragonbox for fast float-to-string conversions, but it would then artificially bump the requirements of my library up to C++17.
I would love to make use of Dragonbox for fast float-to-string conversions
I agree that requiring C++17 will definitely reduce the size of the potential audience. If you want, you could just crib the RYU algorithm from Boost.JSON which perform float-to-string conversions. It is comparable in terms of performance and requires only C++11: https://github.com/boostorg/json/tree/develop/include/boost/json/detail/ryu
Or you can use the original Ryu which I think is in C? https://github.com/ulfjack/ryu
I failed to understand why you cannot build the latest toolchain/cross-toolchain. It is extremely simple okay?
If this was universally true, you wouldn't see so many projects which still use C++11.
That is universally true.
Then why are there so many projects which use C++11? From https://www.jetbrains.com/lp/devecosystem-2020/cpp/
Why are 46% of projects using only C++11? If it is "extremely simple?"
Let's keep the discussion civil.
that is not zero-overhead tbh. On Microsoft ABI, even empty objects would waste registers
If the code is all inline, wouldn't the compiler optimize the function call away, regardless of ABI?
I failed to understand why you cannot build the latest toolchain/cross-toolchain. It is extremely simple okay? Even on windows.
It's not me you need to convince, but the 46% of my library's potential audience who still use C++11 (see survey link in my above post). If it were a in-house project, then I could of course use the latest toolchains if I so choose.
Another thing to keep in mind is that many open source projects are included in Linux distros, so they are constrained to the "standard" compiler versions used in those distros.
To be fair, I can understand the point of view that new libraries adopting C++17 helps to the encourage the industry in moving on past C++11. I guess it's up to the author to decide what's important for them: wider adoption or the joy/convenience of using the latest C++ language features.
If the code is all inline, wouldn't the compiler optimize the function call away, regardless of ABI?
Yes, the compiler sees right through it with full optimizations turned on. And if it doesn't, that's a problem with the compiler which should be fixed there as well.
Then just add the inline
that I forgot.
It seems there are diminishing returns (really, no returns) on additional dialogue with this individual.
@vinniefalco He got kicked out of the Reddit C++ subforum, as well as the Ryu Github repo. Not hard to imagine why.
You don't pay the author either. We're simply making a feature request and presented some evidence on the number of C++11 users. I'm trying to stay civil here, but you turned this into a angry rant. Even if you're technically correct, people won't take you seriously if you don't remain calm and respectful.
If you admire Linus Torvalds so much, perhaps you should do like him and try to learn some empathy: https://arstechnica.com/gadgets/2018/09/linus-torvalds-apologizes-for-years-of-being-a-jerk-takes-time-off-to-learn-empathy/
Of course if the author declines this C++11 feature request, I'll respect that decision and will use another alternative, such as Ryu, or forking this project.
I have said all I have to say about this subject. Good day to you.
I know people are hating me because I am speaking the sad truth.
There are ways of arguing what you believe is the truth without coming off as a jerk. It's not what you say that people dislike, it's how you say it that comes off as insulting. I'm not telling you this to belittle you, but to help you become a better person.
If you call other people's work "trash", then it's the same as insulting those people directly. One can critique another person's work without being insulting.
If you can have people respect you for both your knowledge and your good manners, then you will truly become an individual with "power".
Oh god. What's happening here 😅
@ecorm Thanks for the statistics, the percentage of C++11 looks greater than I expected. It sounds worth to give a try. Right now I do not have time, probably until the beginning of the summer break. Probably I'll work on it after dealing with the items in my personal to-do queue, like coming up with a solution for the issue #11, updating the benchmark, etc..
FYI, @abolz has reimplemented Dragonbox, and AFAIK this implementation does not have lots of compiler-torturing nonsenses mine has, so it is probably C++11 or C++03. He also has an arguably better decimal-to-string conversion routine, which requires a little bit more preconditions but has greater performance. You might be interested to check out the repository.
(It was my goal to provide as many customization options as possible because I aimed to provide a library that serves as a building block for float-to-string conversion library, not such a library itself. That's one reason for those compiler-torturing nonsenses. Another (possibly-related) reason is that I hate magic numbers and tried to minimize their occurrences. Probably these are just overengineering, common to amateurs😕)
Or, fmt
should be a viable option as well, which uses Dragonbox internally. Since the version 7.1.0
, it has far better performance compared to the version I tested against in the benchmark. And I believe fmt
is compatible with C++11. Could be C++14, but I think fmt
is targeting C++11 and any presence of non-C++11 features should be bugs that you can report.
@jk-jeon Thanks for the information. I was unaware of abolz' implementation. It looks like it's just what I need with Javascript-like behavior for use with JSON.
I aimed to provide a library that serves as a building block for float-to-string conversion library
I discovered on my own that converting a number between base 2 and base 10 is in fact quite difficult :) Thank you for this library.
Given that the implementation embedded in fmt
is already C++11-compatible, re-extracting that into a separate repo should not be a big effort. The ported version will have a much smaller set of configurable policies, but it should not be a big issue to most of the potential users.
But before doing that, I'd like to change some interfaces (and finally release the version1 tag). I'll get back to this after that.
Hi, I know this conversation is about C++11, but anyway, in case anyone is interested, I have just adapted the code to C++14, in the branch cxx14, in my fork.
It might be not that difficult to convert it from there to C++11.
Btw, thanks for this amazing algorithm.
@robhz786 Oh thank you so much! I'll refer to it when I work on the C++11 port!
Going back to the use of if constexpr
statements... If the condition is a known constant at compile-time, all decent compilers will optimize-out the branch never taken. Instead of if constexpr
, you could do something like:
#if __cplusplus >= 201703L
#define JKJ_CONSTEXPR_IF if constexpr
#else
#define JKJ_CONSTEXPR_IF if
#endif
This of course assumes that the leftover unused branch does not result in compile errors in the case of a simple if
statement. I didn't bother to check in the code where if constexpr
could be safely substituted with JKJ_CONSTEXPR_IF
, but I just wanted to pass along the general idea.
@ecorm Thanks for sharing this!
I'm planning C++11 support (along with constexpr support for C++20) for the next release!
Jetbrains have not published any infographics of their 2022 survey.
There is, however, page 19 of the 2022 Annual C++ Developer Survey "Lite", presumably run by the ISO committee.
Snapshot of relevant chart, which I share here under the Fair Use Doctrine for the purpose of discussion:
For C++17, 20% have responded "Partial: Lim...", and around 12% have responded "No: Not allo...". Compare that to ~8% and ~2% respectively for C++11.
Please note that this is not a "nag" to support C++11 for this library. It's just that this issue has become a convenient place for me to keep track of C++11/C++17 usage throughout the years. :grin:
Great chart, @ecorm . It does show that a C++11 version would gain a potential user base of 1/5 of respondents. The previous plots have to be taken with a pinch of salt. Just because someone is using C++11 does not mean they can't or won't use something newer.
As much as I agree about library compatibility, I think @jk-jeon should feel free to not make it a priority. This is an academic endeavor, after all, and grad school will absolutely not reward the effort (been there). And it must be a lot of effort, as no-one has submitted a PR in 2.5 years. If anything, it would be a net negative because it would make further research harder as the code would be more difficult to work with.
@alugowski Thanks so much for your kind words.
This is an academic endeavor, after all, and grad school will absolutely not reward the effort (been there).
Haha. This project indeed has nothing to do with what I'm supposed to do in my grad school life. I'm really not supposed to waste my time on this but I just can't stop it because it's so fun. At this point I am trying to minimize my time working on this, but I'll never entirely give up on this project.
It does show that a C++11 version would gain a potential user base of 1/5 of respondents.
If you look at the "No: Not Allowed" column on page 20, the difference between C++11 and C++17 is only around 10%. I'm starting to question my own self-imposition of C++11 in my open-source libraries. It would be nice to get rid of my string_view
and optional
polyfills, as well as being able to use if constexpr
, generic lambdas, auto return types, etc.
It does show that a C++11 version would gain a potential user base of 1/5 of respondents.
If you look at the "No: Not Allowed" column on page 20, the difference between C++11 and C++17 is only around 10%. I'm starting to question my own self-imposition of C++11 in my open-source libraries. It would be nice to get rid of my
string_view
andoptional
polyfills, as well as being able to useif constexpr
, generic lambdas, auto return types, etc.
You are far more patient than I. One datapoint is what Python extensions can be safely built in. That's been C++17 for quite a while. And most are built in a container with 2014 in its name ;)
Features needed to be replaced:
- [x] Terse
static_assert
- [x]
inline constexpr
variables - [x] Structured bindings
- [x]
constexpr
table building - [x] Some other instances of generalized
constexpr
functions (Done except for the policy nonsenses) - [x]
XXX_v
inline variables for<type_traits>
- [x]
XXX_t
type aliases - [x]
if constexpr
- [x] Deduced return type
- [x] Digit separators
- [x] Nested namespace definition
@mborland Dear Matt, if this doesn't take your precious time too much, could you let me know of anything else you recall?