www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Lazy range, extract only Nth element, set range size constraint?

reply biocyberman <biocyberman gmail.com> writes:
Following is the code for a more generalized Fibonacci range.

Questions:

1. How do I get only the value of the Nth (i.e. N = 25) element 
in an idiomatic way?

2. Can I set constraints in the range so that user gets warning 
if he asks for Nth element greater than a limit, say N> 30; or if 
the actually range value at N is greater than datatype limit 
(e.g. max long)? Maybe this should be done outside of the range, 
i.e. do check before accessing the range?

     #!/usr/bin/env rdmd
     import std.stdio : writeln;
     long multifactor = 4;
     int elemth = 25;

     struct FibonacciRange
     {
       long first = 1;
       long second = 1;

       bool empty() const  property
       {
        // how to stop at n = 30?
         return false;
       }

       void popFront()
       {
         long tmp = 0;
         tmp = first*multifactor + second;
         first = second;
         second = tmp;
       }

       long front() const  property
       {
         return first;
       }
     }

     void main()
     {
         import std.range : take;
         import std.array : array;

         FibonacciRange fib;

         auto fib10 = take(fib, elemth);
         long[] the10Fibs = array(fib10);
     }
Jul 09
parent ag0aep6g <anonymous example.com> writes:
On 07/09/2017 11:51 PM, biocyberman wrote:
 Following is the code for a more generalized Fibonacci range.
 
 Questions:
 
 1. How do I get only the value of the Nth (i.e. N = 25) element in an 
 idiomatic way?
As you've only got an input range, you have to popFront the 24 values that come before. You can use std.range.drop: ---- import std.range : drop; auto twentyfifth = fib.drop(24).front; ---- But if you're not sure that the range actually has 25 elements, you should check `empty`, of course: ---- import std.range : popFrontN; fib.popFrontN(24); /* or fib = fib.drop(24); */ if (!fib.empty) { auto twentyfifth = fib.front; } ----
 2. Can I set constraints in the range so that user gets warning if he 
 asks for Nth element greater than a limit, say N> 30;
You can keep track of N in FibonacciRange and when it hits 30 you throw an exception or print a message or just set `empty` to true. You can't make it a compilation warning/error as far as I can tell.
 or if the actually 
 range value at N is greater than datatype limit (e.g. max long)?
You can use std.experimental.checkedint to detect it at run time: ---- private bool _empty = false; bool empty() const property { return _empty; } void popFront() { import std.experimental.checkedint : checked, Throw; long tmp = 0; try tmp = (checked!Throw(first)*multifactor + second).get; catch (Throw.CheckFailure e) _empty = true; first = second; second = tmp; } ---- (There may be a smarter way than making the operation throw an exception and catching that.)
Jul 09