Ranges usages
monarch_dodra
monarchdodra at gmail.com
Thu Nov 22 01:29:38 PST 2012
On Thursday, 22 November 2012 at 01:14:23 UTC, bearophile wrote:
>
> [SNIP]
>
> Thank you,
> bye,
> bearophile
I'd argue that your first "compress1" isn't range correct either
anyways, because "w ~ ch;" (which will allocate) is not part of
the range interface.
Neither is "w = [ch];" (which will also allocate)
Given the allocations in the first example, I'd hardly consider
the performance comparison fair.
How about this?
int[] compress3(immutable T[] original) {
int[Ta] dictionary;
foreach (i; 0 .. 256)
dictionary[cast(Ta)[i]] = i;
int[] result;
size_t start, end;
Ta w;
foreach (i, ch; original) {
auto wc = original[start .. end + 1];
if (wc in dictionary) {
w = wc;
++end;
} else {
w = original[start .. end];
result ~= dictionary[w];
dictionary[wc] = dictionary.length - 1;
start = i;
end = i + 1;
}
}
return w.empty ? result : (result ~ dictionary[w]);
}
This is "range correct". Being range correct, it doesn't allocate
either.
I would have preferred writing "wc = wc.ptr[0 .. wc.length +
1]"... but that's not range correct...
I'd be thrilled if you (quickly) benched my compress3.
----
Also: I'd suggest you avoid code such as:
int[] result;
for (...)
result ~= xxx ;
Unless you take the time to manually call assumeUnique, this will
reallocate on *each*and*every* append. You are better off using
an actual appender:
auto result = appender!int();
for (...)
result.put(x);
return result.data;
My benching experiences have shown performance gains with
appender as early as the 2nd insertion.
--------
Back to topic though:
My limited range experience has shown me that:
1. They are *incredibly* easy to chain and adapt.
2. RA ranges are (mostly) just as powerful as iterators or raw
arrays.
3. If all you want to do is iterate forward, than any flavor of
range will rock.
The "HUGE" flaw I see with ranges though, is in regards to
bidirectional ranges, and their ability to "only shrink, never
grow". In particular, it is not possible to "slice" an Bidir
right through the middle. "iterate until you find x, and then
return the slice *up-to* x". Iterators can do it just fine.
The (IMO) tell-tale symptom are all the algorithms that return a
"take" for bidirectional ranges. "take" is nice and all, but in
that case, I think it is subverting your range's type.
In particular, own of the "great power" of a bidirectional range,
is to define a sequence by "all elements between a start and end
point". What's cool about this definition is that it means that
if you insert new element between the bounds, they will be taken
into account by the range.
"Take" subverts that in that the sequence becomes a "start +
index", so inserting new items in the underlying _container_ will
just bump the last items out of your rake range.
--------
Well, that's my rant anyways: Range are an incredibly powerful
abstract notion, but when you want to get down and dirty with
them, they tend to create a bit of friction compared to some
lower level abstractions...
But overall: Worth it.
More information about the Digitalmars-d
mailing list