import datetime; import std.range,std.algorithm,std.stdio,std.traits; ///Infinite range producing natural powers of functor f using given seed s : /// f(s), f(f(s)), f(f(f(s))), ... struct PowerRange(Fn,T) if(isCallable!Fn){ Fn _fn; T _val; this(Fn fn,T val){ _val = val; _fn = fn; // could be parametrized to start with different index popFront(); } void popFront(){ _val = _fn(_val); } bool empty()const nothrow{ return false; } typeof(this) save(){ return this; } T front(){ return _val; } } PowerRange!(Fn,TP) powersOf(Fn,TP)(Fn fn,TP start){ return PowerRange!(Fn,TP)(fn,start); } unittest{ auto r = powersOf((int x){ return x*2; }, 1); assert(array(take(r,10)) == [2,4,8,16,32,64,128,256,512,1024]); static assert(isForwardRange!(typeof(r))); } ///Range that confines given infinite forward timepoint range ///the result is forward range containing only inters struct ConfinedForwardRange(Range,I) if( isForwardRange!Range ){ private Range _range; private I _interval; static if(__traits(compiles,_interval.begin())){ alias typeof(_interval.begin()) TP; }else static if (is(_interval.end)){ alias typeof(_interval.end()) TP; }else static assert(0); private bool _empty; this(Range range, I interval){ _range = range; _interval = interval; _empty = !_interval.contains(_range.front()); } TP front(){ assert(!empty); return _range.front(); } typeof(this) save(){ return this; } bool empty() { return _empty; } void popFront(){ _range.popFront(); _empty = !_interval.contains(_range.front()); } } ConfinedForwardRange!(Range,I) confine(Range,I)(Range range,I interval) { return ConfinedForwardRange!(Range,I)(range,interval); } ///Infinite forward range of timepoints obtained ///by continiously applying add!dur to a given timepoint struct SimpleRange(TP,Direction dir=Direction.Fwd) if(isTimePoint!(TP)){ TP _cur; Duration _step; static if(__traits(compiles,_cur.year)){ int _ystep, _mstep; this(TP start, int years, int months=0,Duration step=dur!"days"(0)){ _cur = start; _step = step; _ystep = years; _mstep = months; } } this(TP start, Duration step){ _cur = start; _step = step; } void popFront(){ static if(dir == Direction.fwd){ static if(__traits(compiles,_cur.year)){ _cur.add!"years"(_ystep); _cur.add!"months"(_mstep); } _cur += _step; }else{ _cur -= _step; static if(__traits(compiles,_cur.year)){ _cur.add!"months"(-_mstep); _cur.add!"years"(-_ystep); } } } bool empty(){ return false; } TP front(){ return _cur; } typeof(this) save(){ return this; } } /// Helper function, constructs forward range of timepoints of a given interval, striding by adding duration d ConfinedForwardRange!(SimpleRange!(typeof(I.begin),Direction.fwd),I) fwdRange(I)(I interval, Duration d){ alias typeof(interval.begin) TP; return confine(SimpleRange!(TP,Direction.fwd)(interval.begin,d), interval); } /// Helper function, constructs forward range of timepoints of a given interval, striding by adding duration d, then months, then years ConfinedForwardRange!(SimpleRange!(typeof(I.begin),Direction.fwd),I) fwdRange(I)(I interval, int years, int months=0,Duration d=dur!"days"(0)){ alias typeof(interval.begin) TP; return confine(SimpleRange!(TP,Direction.fwd)(interval.begin,years,months,d), interval); } /// Helper function, constructs forward range of timepoints of a given interval, striding backwards by subtracting duration d ConfinedForwardRange!(SimpleRange!(typeof(I.end),Direction.bwd),I) bwdRange(I)(I interval, Duration d){ alias typeof(interval.end) TP; auto r = confine(SimpleRange!(TP,Direction.bwd)(interval.end,d), interval); r.popFront(); //interval is open ended, which means the last time point is NOT in the interval return r; } /// Helper function, constructs forward range of timepoints of a given interval, striding backwards by subtracting duration d, then months, then years ConfinedForwardRange!(SimpleRange!(typeof(I.end),Direction.bwd),I) bwdRange(I)(I interval, int years, int months=0, Duration d=dur!"days"(0)){ alias typeof(interval.end) TP; auto r = confine(SimpleRange!(TP,Direction.bwd)(interval.end,years,months,d), interval); r.popFront(); //interval is open ended, which means the last time point is NOT in the interval return r; } //that should be packed in a unittest void main(){ auto evd = IRange.everyDayOfWeek!(Date)(DayOfWeek.monday); auto inf = powersOf(evd, Date(2010,Month.dec,11)); writeln(take(inf,5));//next 5 mondays auto interval = Interval!Date(Date(2010,Month.dec,1),Date(2010,Month.dec,20)); auto conf = confine(inf,interval); writeln(conf);//mondays in given interval writeln(fwdRange(interval, dur!"days"(2))); //2010-Dec-01, 2010-Dec-03... writeln(bwdRange(interval, dur!"days"(3))); //interval is open ended, so: 2010-Dec-17, 2010-Dec-14, 2010-Dec-11... auto interval2 = Interval!Date(Date(2010,Month.mar,3),Date(2022,Month.apr,2)); writeln(fwdRange(interval2, 1, 2)); //2010-Mar-03, 2011-May-03, 2012-Jul-03, 2013-Sep-03, 2014-Nov-03, 2016-Jan-03.. writeln(bwdRange(interval2, 2, 1)); //interval is open ended, so: 2020-Mar-02, 2018-Feb-02, 2016-Jan-02, 2013-Dec-02, 2011-Nov-02 ... }