What exactly is so Rust'y in the code? If to compare with C/C++? What is the main benefit of using Rust? Or is it just a test like "you can do that in Rust too"?
What exactly is so Rust'y in the code? If to compare with C/C++? What is the main benefit of using Rust? Or is it just a test like "you can do that in Rust too"?
C seems to be used only for SSE intrinsics support. ~16 LoC of "C".
This is all C in the whole project, if you really think you can call it as such:
https://github.com/google/font-rs/blob/master/src/accumulate...
void accumulate_sse(const float *in, uint8_t *out, uint32_t n) {
__m128 offset = _mm_setzero_ps();
__m128i mask = _mm_set1_epi32(0x0c080400);
__m128 sign_mask = _mm_set1_ps(-0.f);
for (int i = 0; i < n; i += 4) {
__m128 x = _mm_load_ps(&in[i]);
x = _mm_add_ps(x, _mm_castsi128_ps(_mm_slli_si128(_mm_castps_si128(x), 4)));
x = _mm_add_ps(x, _mm_shuffle_ps(_mm_setzero_ps(), x, 0x40));
x = _mm_add_ps(x, offset);
__m128 y = _mm_andnot_ps(sign_mask, x); // fabs(x)
y = _mm_min_ps(y, _mm_set1_ps(1.0f));
y = _mm_mul_ps(y, _mm_set1_ps(255.0f));
__m128i z = _mm_cvtps_epi32(y);
z = _mm_shuffle_epi8(z, mask);
_mm_store_ss((float *)&out[i], (__m128)z);
offset = _mm_shuffle_ps(x, x, _MM_SHUFFLE(3, 3, 3, 3));
}
}
Also consider top level: https://github.com/google/font-rs/tree/master/src> What is the main benefit of using Rust?
Safety and performance.
From the article:
"With the SIMD speedup, font-rs is approximately 7.6x faster than FreeType in larger sizes (keep in mind that 42 pixels/em is the default for xxhdpi Android devices)."
One of the big gains mentioned in the article for Rust was using iterators instead of a one-time-use vector, which is very hard in C, would currently be best done with Boost in C++, but is a core idiom in Rust.
For optimized real-world code, the innermost, hottest, loop is almost always machine-specific, and a superset of C is used if the language of implementation doesn't have intrinsics for the particular machine feature one wants to access.
I have only dabbled in Rust, but it is common to see other high-level languages where given X amount of effort the high-level language implementation is faster than a C implementation that could be implemented with a similar amount of effort. It's almost certainly possible to create an iterator version with a custom stack allocator in C that matches the performance of the Rust version, but you will be creating an ad-hoc, informally specified, buggy version of two of rust's core features[1].
C++ is a different beast entirely as the language is on track to completely reinvent itself every 6 years, so it's likely in a few years that you could port the Rust version nearly unchanged to C++17 or C++20, and there's probably a Boost library that allows it now.
Maybe misundestood somethin. But hard or requiring boost? Isn't this basically what you meant?
class enumerating_parser { uint8_t* pos; uint8_t* end; enumerating_parser(const uint8_t* bytes, int len):pos(), end(pos + len){} bool next(ParserResult& out){ if(pos == end) return false; // do parsing here and move pointer forward } };
Rust has algebraic datatypes, memory safety, pattern matching, etc, - those are actual things that are, if not hard, then at least tiringly verbose to do in C and C++;
0: enumerating_parser now becomes struct enumerating_parser{}, the constructor becomes a factory function while next() takes in the parser as a state parameter.
Further, Rust's monomorphizing approach to generics means that you can count on efficient code. Iterators over a slice typically elide the bounds checking, reliably.
Of course you can use these patterns in other languages, but you lose something, specifically, clarity and safety. I believe that's the reason you see them used all the time in Rust and rarely in C and C++.
My answer was to the specific claim that an iterator using the "next" formulation would be hard to use in C++ - it's not, and it makes several pieces of code much nicer than using the default iteration scheme of raw index or pointer-hopping.
So, the intent was not to make a statement "we can do that in C++, Rust has no merit in this regard" but rather, "you should not shy away from this nice pattern if you are forced to use C++ in your daily work". This intent was not that obvious in the message's context, though.
i.e. enumerating_parser p(source, source_len); ParseResult r; while(p.next(r)){// forward context of r forwards}.
So use unsigned len or add more code to check your inputs or just use Rust where this sort of unsafe pointer arithmetic doesn't even compile.
"Oooh, it's made a lot of progress recently! Funny thing, I actually started experimenting with this stuff pre-Rust 1.0. Last I looked at the SIMD crate, it was missing a whole bunch of stuff, and my style is to use fairly exotic SIMD instructions when they can help (for example, _mm_shuffle_epi8 is available in tmmintrin.h but not pmmintrin.h.
This is a technology demo, so using a not-yet stabilized feature seems in scope. Perhaps I'll try the SIMD crate for writing the ARM version."
You might have missed that in his post.