The rfind challenge

Timon Gehr timon.gehr at gmx.ch
Tue Jan 15 05:30:42 PST 2013


On 01/15/2013 12:53 PM, FG wrote:
> On 2013-01-15 06:51, Andrei Alexandrescu wrote:
>> If r is a forward range but not better, this is rather simple:
>>
>> R rfind(R, E)(R range, E element)
>> {
>>      for (;;)
>>      {
>>          auto ahead = range.save.find(element);
>>          if (ahead.empty) return range;
>>          range = ahead;
>>      }
>> }
>
> That example creates an infinite loop. Needs a popFront:
>
>      R rfind(R, E)(R range, E element)
>      {
>          if (range.empty) return range;
>          for (;;)
>          {
>              auto ahead = range.save;
>              ahead.popFront();
>              ahead = ahead.find(element);
>              if (ahead.empty) return range;
>              range = ahead;
>          }
>      }
>

That is buggy too.

> Another thing: if the element is not found, I think an empty range
> should be returned and not the whole range.

Yup.

R rfind(R, E)(R range,E element){
     auto r=range.find(element);
     if(r.empty) return r;
     for(;;){
         auto ahead=r.save;
         ahead.popFront();
         ahead=ahead.find(element);
         if(ahead.empty) return r;
         r=ahead;
     }
}


Full proof (assuming purity of the range primitives):

/+pure+/ R tail(R)(R r)out(result){
     assert(result=={
         auto a=r;
         a.popFront();
         return a;
     }());
}body{
     auto a=r;
     a.popFront();
     return a;
}

/+pure+/ R rfind(R, E)(R range,E element)out(result){
	assert(range.find(element).empty&&result.empty||!range.find(element).empty&&!result.empty&&result.front==element&&result.tail.find(element).empty);
}body{
     auto r=range.find(element);
     assert(r==range.find(element)&&(r.empty||r.front==element));
     if(r.empty){
         assert(r==range.find(element)&&r.empty);
         return r;
         /+assert(result==range.find(element)&&result.empty);
         assert(range.find(element).empty&&result.empty);+/
     }
     assert(r==range.find(element)&&!r.empty&&r.front==element);
     assert(!range.find(element).empty&&!r.empty&&r.front==element);
     for(;;){
 
assert(true&&!range.find(element).empty&&!r.empty&&r.front==element);
 
assert(!range.find(element).empty&&!r.empty&&r.front==element&&!r.empty);
         auto ahead=r.save;
 
assert(!range.find(element).empty&&!r.empty&&r.front==element&&!ahead.empty&&ahead==r.save);
         ahead.popFront();
 
assert(!range.find(element).empty&&!r.empty&&r.front==element&&ahead=={
             auto ahead=r.save;
             ahead.popFront();
             return ahead;
         }());
 
assert(!range.find(element).empty&&!r.empty&&r.front==element&&ahead==r.tail);
         ahead=ahead.find(element);
 
assert(!range.find(element).empty&&!r.empty&&r.front==element&&(ahead.empty||ahead.front==element)&&ahead==r.tail.find(element));
         if(ahead.empty){
 
assert(!range.find(element).empty&&ahead.empty&&!r.empty&&r.front==element&&ahead==r.tail.find(element));
             return r;
 
/+assert(!range.find(element).empty&&ahead.empty&&!result.empty&&result.front==element&&ahead==result.tail.find(element));
 
assert(!range.find(element).empty&&!result.empty&&result.front==element&&result.tail.find(element).empty);+/
         }
 
assert(!range.find(element).empty&&!ahead.empty&&ahead.front==element);
         r=ahead;
         assert(!range.find(element).empty&&!r.empty&&r.front==element);
     }
     assert(false);
}





More information about the Digitalmars-d mailing list