-
-
Notifications
You must be signed in to change notification settings - Fork 748
Fix generate to be correctly implemented range. #4528
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3146,41 +3146,36 @@ Take!(Repeat!T) repeat(T)(T value, size_t n) | |
| } | ||
|
|
||
| /** | ||
| Given callable ($(REF isCallable, std,traits)) $(D fun), create as a range | ||
| whose front is defined by successive calls to $(D fun()). | ||
| Given callable ($(REF isCallable, std,traits)) `fun`, create as a range | ||
| whose front is defined by successive calls to `fun()`. | ||
| This is especially useful to call function with global side effects (random | ||
| functions), or to create ranges expressed as a single delegate, rather than | ||
| an entire $(D front)/$(D popFront)/$(D empty) structure. | ||
| $(D fun) maybe be passed either a template alias parameter (existing | ||
| function, delegate, struct type defining static $(D opCall)... ) or | ||
| a run-time value argument (delegate, function object... ). | ||
| an entire `front`/`popFront`/`empty` structure. | ||
| `fun` maybe be passed either a template alias parameter (existing | ||
| function, delegate, struct type defining `static opCall`) or | ||
| a run-time value argument (delegate, function object). | ||
| The result range models an InputRange | ||
| ($(REF isInputRange, std,range,primitives)). | ||
| The resulting range will call $(D fun()) on every call to $(D front), | ||
| and only when $(D front) is called, regardless of how the range is | ||
| iterated. | ||
| It is advised to compose generate with either | ||
| $(REF cache, std,algorithm,iteration) or $(REF array, std,array), or to use it in a | ||
| foreach loop. | ||
| A by-value foreach loop means that the loop value is not $(D ref). | ||
| The resulting range will call `fun()` on construction, and every call to | ||
| `popFront`, and the cached value will be returned when `front` is called. | ||
|
|
||
| Params: | ||
| fun = is the $(D isCallable) that gets called on every call to front. | ||
|
|
||
| Returns: an $(D inputRange) that returns a new value generated by $(D Fun) on | ||
| any call to $(D front). | ||
| Returns: an `inputRange` where each element represents another call to fun. | ||
| */ | ||
| auto generate(Fun)(Fun fun) | ||
| if (isCallable!fun) | ||
| { | ||
| return Generator!(Fun)(fun); | ||
| auto gen = Generator!(Fun)(fun); | ||
| gen.popFront(); // prime the first element | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Params: section is missing now?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not needed, basically said the same thing as Returns section. |
||
| return gen; | ||
| } | ||
|
|
||
| /// ditto | ||
| auto generate(alias fun)() | ||
| if (isCallable!fun) | ||
| { | ||
| return Generator!(fun)(); | ||
| auto gen = Generator!(fun)(); | ||
| gen.popFront(); // prime the first element | ||
| return gen; | ||
| } | ||
|
|
||
| /// | ||
|
|
@@ -3219,7 +3214,6 @@ unittest | |
| format("%(%s %)", r); | ||
| } | ||
|
|
||
| //private struct Generator(bool onPopFront, bool runtime, Fun...) | ||
| private struct Generator(Fun...) | ||
| { | ||
| static assert(Fun.length == 1); | ||
|
|
@@ -3231,18 +3225,41 @@ private: | |
| else | ||
| alias fun = Fun[0]; | ||
|
|
||
| enum returnByRef_ = (functionAttributes!fun & FunctionAttribute.ref_) ? true : false; | ||
| static if (returnByRef_) | ||
| ReturnType!fun *elem_; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Space between required Likewise, at least one if and one foreach below.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK. that is so not clear from the error message 😄 |
||
| else | ||
| ReturnType!fun elem_; | ||
| public: | ||
| /// Range primitives | ||
| enum empty = false; | ||
|
|
||
| /// ditto | ||
| auto ref front() @property | ||
| static if (returnByRef_) | ||
| { | ||
| return fun(); | ||
| /// ditto | ||
| ref front() @property | ||
| { | ||
| return *elem_; | ||
| } | ||
| /// ditto | ||
| void popFront() | ||
| { | ||
| elem_ = &fun(); | ||
| } | ||
| } | ||
| else | ||
| { | ||
| /// ditto | ||
| auto front() @property | ||
| { | ||
| return elem_; | ||
| } | ||
| /// ditto | ||
| void popFront() | ||
| { | ||
| elem_ = fun(); | ||
| } | ||
| } | ||
|
|
||
| /// ditto | ||
| void popFront() {} | ||
| } | ||
|
|
||
| @safe unittest | ||
|
|
@@ -3270,6 +3287,37 @@ public: | |
| assert(equal(generate(op).take(10), repeat(5).take(10))); | ||
| } | ||
|
|
||
| // verify ref mechanism works | ||
| @system unittest | ||
| { | ||
| int[10] arr; | ||
| int idx; | ||
|
|
||
| ref int fun() { | ||
| auto x = idx++; | ||
| idx %= arr.length; | ||
| return arr[x]; | ||
| } | ||
| int y = 1; | ||
| foreach (ref x; generate!(fun).take(20)) | ||
| { | ||
| x += y++; | ||
| } | ||
| import std.algorithm.comparison : equal; | ||
| assert(equal(arr[], iota(12, 32, 2))); | ||
| } | ||
|
|
||
| // assure front isn't the mechanism to make generate go to the next element. | ||
| @safe unittest | ||
| { | ||
| int i; | ||
| auto g = generate!(() => ++i); | ||
| auto f = g.front; | ||
| assert(f == g.front); | ||
| g = g.drop(5); // reassign because generate caches | ||
| assert(g.front == f + 5); | ||
| } | ||
|
|
||
| /** | ||
| Repeats the given forward range ad infinitum. If the original range is | ||
| infinite (fact that would make $(D Cycle) the identity application), | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would add a note here about following the clarified range rules with a link, when #4511 is pulled
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most expect ranges to behave this way, the updating of the rules is just a formal presentation of what everyone already knows. So I don't think a link is necessary.