5 ms·
"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." Maybe misun
by fsloth 10y ago
"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."
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
}
};
- Rusky 10y agoHard in C, which your example is not, and which FreeType is.
- fsloth 10y agoNo, it's pretty much the same in C[0]. Sorry, my point was not laid out. It was not to be obnoxious, but that one can implement various pattern fairly succintly in C or C++ and thus "is difficult to do in language x" is not a very compelling argument there. 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.
- raphlinus 10y agoThe specific claim I'm making is that Rust has language (in the form of making it the default in `for` loops) and library (in the form of the `Iterator` trait) support for this pattern. 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++.
- fsloth 10y agoYes, I agree with your original analysis completely - well thought out languages with a richer basic type zoo are generally much more pleasant to deal with than 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.
- avita1 10y agoThis implementation uses an underlying, materialized array right? And that was the very thing that the author is trying to avoid.
- fsloth 10y agoNo. There is the original bytestorage for the data that is to be parsed - and is the only thing necessarily taking a chunk of memory - and the sink for the parsed data somewhere else. The state held by the enumerator itself is tiny. A pointer to the source buffer is held in the pos pointer. As the user extracts entities from the parser the pos pointer is just forwarded. There is of course the parsing code inside 'next' itself which was not included, but which knows what entities to expect and forwards the pos by the entity size while checking it does not go over the end. i.e. enumerating_parser p(source, source_len); ParseResult r; while(p.next(r)){// forward context of r forwards}.
- topspin 10y agoenumerating_parser look_ma_no_memory_safety(something, -1); // pos never == end 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.
- fsloth 10y agoYes, actual memory safety is a feature that Rust has, and C++ has lots of footguns. It still does not make using an enumerator correctly any harder.