dragonbox icon indicating copy to clipboard operation
dragonbox copied to clipboard

C++11?

Open vinniefalco opened this issue 3 years ago • 38 comments

I need a port of this to C++11

vinniefalco avatar Oct 05 '20 23:10 vinniefalco

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.

jk-jeon avatar Oct 06 '20 22:10 jk-jeon

Would love it if C++11 version of this is made available. Great work guys!

stainleebakhla avatar Mar 01 '21 17:03 stainleebakhla

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.

ecorm avatar Mar 27 '21 22:03 ecorm

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.

ecorm avatar Mar 27 '21 22:03 ecorm

if you want the widest possible adoption.

GitHub stars and forks are what give my life meaning and value

vinniefalco avatar Mar 28 '21 00:03 vinniefalco

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.

ecorm avatar Mar 28 '21 00:03 ecorm

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

vinniefalco avatar Mar 28 '21 00:03 vinniefalco

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.

vinniefalco avatar Mar 28 '21 02:03 vinniefalco

That is universally true.

Then why are there so many projects which use C++11? From https://www.jetbrains.com/lp/devecosystem-2020/cpp/

image

Why are 46% of projects using only C++11? If it is "extremely simple?"

vinniefalco avatar Mar 28 '21 02:03 vinniefalco

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.

ecorm avatar Mar 28 '21 02:03 ecorm

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.

vinniefalco avatar Mar 28 '21 02:03 vinniefalco

Then just add the inline that I forgot.

ecorm avatar Mar 28 '21 02:03 ecorm

It seems there are diminishing returns (really, no returns) on additional dialogue with this individual.

vinniefalco avatar Mar 28 '21 02:03 vinniefalco

@vinniefalco He got kicked out of the Reddit C++ subforum, as well as the Ryu Github repo. Not hard to imagine why.

ecorm avatar Mar 28 '21 02:03 ecorm

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.

ecorm avatar Mar 28 '21 03:03 ecorm

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".

ecorm avatar Mar 28 '21 03:03 ecorm

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 avatar Mar 28 '21 08:03 jk-jeon

@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.

ecorm avatar Mar 28 '21 17:03 ecorm

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.

vinniefalco avatar Mar 28 '21 19:03 vinniefalco

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.

jk-jeon avatar May 14 '21 22:05 jk-jeon

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 avatar May 23 '21 14:05 robhz786

@robhz786 Oh thank you so much! I'll refer to it when I work on the C++11 port!

jk-jeon avatar May 24 '21 06:05 jk-jeon

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 avatar May 26 '21 19:05 ecorm

C++ language standards adoption from the jetbrains report done in 2021:

C++ language standards adoption

ecorm avatar May 15 '22 01:05 ecorm

@ecorm Thanks for sharing this!

I'm planning C++11 support (along with constexpr support for C++20) for the next release!

jk-jeon avatar May 17 '22 18:05 jk-jeon

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:

Screenshot from 2023-01-16 17-43-06

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:

ecorm avatar Jan 16 '23 21:01 ecorm

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 avatar Jan 20 '23 04:01 alugowski

@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.

jk-jeon avatar Jan 21 '23 04:01 jk-jeon

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.

ecorm avatar Feb 05 '23 00:02 ecorm

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.

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 ;)

alugowski avatar Feb 07 '23 01:02 alugowski

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?

jk-jeon avatar Aug 12 '23 04:08 jk-jeon