jk-jeon / dragonbox

Reference implementation of Dragonbox in C++
Apache License 2.0
532 stars 36 forks source link

C++11? #8

Open vinniefalco opened 3 years ago

vinniefalco commented 3 years ago

I need a port of this to C++11

jk-jeon commented 3 years ago

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.

stainleebakhla commented 3 years ago

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

ecorm commented 3 years ago

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 commented 3 years ago

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.

vinniefalco commented 3 years ago

if you want the widest possible adoption.

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

ecorm commented 3 years ago

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.

vinniefalco commented 3 years ago

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 commented 3 years ago

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 commented 3 years ago

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

ecorm commented 3 years ago

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.

vinniefalco commented 3 years ago

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 commented 3 years ago

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

ecorm commented 3 years ago

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

ecorm commented 3 years ago

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 commented 3 years ago

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

jk-jeon commented 3 years ago

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.

ecorm commented 3 years ago

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

vinniefalco commented 3 years ago

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.

jk-jeon commented 3 years ago

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.

robhz786 commented 3 years ago

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.

jk-jeon commented 3 years ago

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

ecorm commented 3 years ago

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 commented 2 years ago

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

C++ language standards adoption

jk-jeon commented 2 years ago

@ecorm Thanks for sharing this!

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

ecorm commented 1 year ago

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:

alugowski commented 1 year ago

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.

jk-jeon commented 1 year ago

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

ecorm commented 1 year ago

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.

alugowski commented 1 year ago

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

jk-jeon commented 1 year ago

Features needed to be replaced:

@mborland Dear Matt, if this doesn't take your precious time too much, could you let me know of anything else you recall?

mborland commented 1 year ago

Those are most of the big ones. Lesser issues:

If you want to reference anything I refactored all of the dragon box and floff code in charconv to be in a folder by itself here. I support back to Clang 3.5 and GCC 5. I ended up dropping the GCC 4.X series because of broken aggregate initialization of u128 in the caches. Let me know if you have any additional question and I'll do my best to answer them.

jk-jeon commented 1 year ago

@mborland Thanks a lot, it's really helpful!

jk-jeon commented 1 year ago

I mostly finished this but I need some rigorous testing. I'll do it shortly but PR is welcomed!

jk-jeon commented 1 year ago

Okay, it now at least compiles successfully with:

C++11:

C++14:

C++17:

C++20:

Still PR's with a decent set of tests is very much welcomed!

vinniefalco commented 10 months ago

Wow, that's pretty amazing :) Thank you so much. It is true that C++11 is getting pretty old, and my general advice is to target C++ for new libraries. However for something like this, which is such a profound low-level building block that has performance implications, giving people stuck on C++11 access to using the library is a bigger win. Thanks.

ecorm commented 4 months ago

ISO's 2024 Annual C++ Developer Survey "Lite" is out: https://isocpp.org/files/papers/CppDevSurvey-2024-summary.pdf

image image

"Pretty much all" for C+11 is 91% versus 78% for C++17.

jk-jeon commented 4 months ago

@ecorm I remember you said you're just using this thread as a convenient place for tracking the language standard adoption, but I will use your posting as an opportunity to write down the remaining stuffs that need to be done😃

Once these are done I will close this issue. Hopefully in the near future!

ecorm commented 4 months ago

@jk-jeon I'm now adopting C++17 as the minimum version for my libraries, but float/string conversion library is far more fundamental than the niche stuff I'm doing.