D Ranges in C#
Steven Schveighoffer
schveiguy at yahoo.com
Mon Jun 3 08:31:40 PDT 2013
On Sat, 01 Jun 2013 04:11:59 -0400, bearophile <bearophileHUGS at lycos.com>
wrote:
> David Piepgrass:
>> In fact, most STL algorithms require exactly two iterators--a
>> range--and none require only a single iterator<
>
> I think there are some C++ data structures that store many single
> iterators. If you instead store ranges you double the data amount.
This is true. In dcollections, I have the concept of cursors. These are
1 or 0 element ranges (they are 0 after the first popFront). For almost
all cases, they require an extra boolean to designate the "empty" state.
So while not consuming 2x, it's more like 1.5x-ish. Because of alignment,
it pretty much requires 2x. There have been suggestions on utilizing
perhaps unused bits in the pointer to designate the empty flag, but I'm a
bit aprehensive on that, especially if the node is GC-managed.
But besides the space requirements the *concept* of a single-element
pointer is very much needed. And cursors fill that role.
As an example, std.algorithm.find consumes a range until it finds the
specific value. It then returns a range of the remaining data. But what
if you wanted the range of the data UNTIL the first value?
In std.container, we have three functions to deal with this, upperBound,
lowerBound, and equalRange. But even with these, it can be difficult to
construct intersections of these two ranges.
In dcollections, we have one function, find, which returns a cursor. Then
using the cursor, you can construct the range you need:
auto r = mymap[mymap.find(5)..$]; // opDollar not supported yet, but will
be.
auto rbefore = mymap[mymap.begin()..mymap.find(5)];
All of this is safe and correct, and I think it reads rather well.
There are other good places where single-element ranges are useful. It is
important to note that a cursor is NOT equivalent to a range of one
element. Such a range in a node-based container has two node pointers. A
cursor MUST only point at exactly one element. This is important when
considering cursor invalidation -- removing an element unreferenced by a
cursor should not invalidate that cursor (depending on how the container
is structured). For example, adding a new value to a hash set, or
removing an unrelated value from a hash set may invalidate all ranges, but
not cursors.
-Steve
More information about the Digitalmars-d
mailing list