Heap: container or range?

Andrei Alexandrescu SeeWebsiteForEmail at erdani.org
Fri Jan 30 10:10:18 PST 2009


Sergey Gromov wrote:
> Thu, 29 Jan 2009 21:26:39 -0800, Andrei Alexandrescu wrote:
> 
>> Sean Kelly wrote:
>>> Sean Kelly wrote:
>>>> Andrei Alexandrescu wrote:
>>>>> Ah, never mind all that. I realized that I can't have a heap range. 
>>>>> This is because heaps must mutate the underlying range in-place and 
>>>>> any copy will mess the heap up. Here's the example that clarify it 
>>>>> for me:
>>>>>
>>>>>         int[] a = [ 4, 1, 3, 2, 16, 9, 10, 14, 8, 7 ];
>>>>>         auto h = Heap!(int[])(a);
>>>>>         assert(equal(take(5, h) == [ 8, 9, 10, 14, 16 ]);
>>>>>
>>>>> At this point the mutations done by take messed up h already!!
>>>> Hm... so assuming this is a min heap, I have:
>>>>
>>>> a = [4,1,3,2,16,9,10,14,8,7];
>>>> h = [1,2,3,4,7,9,10,14,8,16];
>>>> take(5, h);
>>>> h = [8,10,9,16,14];
>>>>
>>>> Shouldn't take call next repeatedly on the heap, which will in turn 
>>>> perform a popHeap operation?  It's difficult to be sure what the 
>>>> result will be after take(5,h) occurs, but it should still be a valid 
>>>> heap, correct?
>>> Oh, I would also expect:
>>>
>>> a = [8,10,9,16,14, garbage];
>>>
>>> Since it isn't aware of the length adjustment.  Perhaps this is what you 
>>> meant?
>>>
>>> Sean
>> Yah, that's what I meant. h still thinks its length is 10 and that those 
>> 10 elements respect the heap property.
> 
> Actually, if ranges are by value, I'd expect
> 
> assert(equal(take(5, h) == take(5, h)));

Me too. It does work indeed BUT NOT FOR INPUT RANGES. So in short you 
are showing yet another reason why heaps can't be good ranges.

> OTOH, I'd expect something like the following to also work:
> 
> auto f = new File("blah.txt");
> auto top = take(10, f.lines);

That also works (just that in the new std.stdio File is a struct, so 
it's not dynamically allocated). However, f.lines is understandably an 
input range so this will NOT work:

auto f = new File("blah.txt");
assert(equal(take(5, f.lines) == take(5, f.lines)));

The two f.lines instances operate on the same underlying file handle, so 
they are input ranges: advancing one advances all others.

> I.e. I'd expect some ranges to be Translators, and others to be
> Mutators.  Translators are read-only views into underlying anything
> which may involve some expensive bookkeeping.  Mutators are basically
> references into a particular container and make sure that the container
> and other Mutators stay consistent.

I think the distinction is input vs. forward and mutable vs. immutable 
ranges (the latter distinction is not checked in yet).

Andrei



More information about the Digitalmars-d mailing list