-
-
Notifications
You must be signed in to change notification settings - Fork 739
Add std.range.tail #3855
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
Add std.range.tail #3855
Conversation
780bdc5
to
d856f3a
Compare
{ | ||
static immutable input = [1, 2, 3]; | ||
static immutable expectedOutput = [2, 3]; | ||
assert(input.tail(2) == expectedOutput); |
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.
static assert
?
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.
It's for checking @nogc
, so no
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.
You can do both at the same time, no?
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.
What do you mean?
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.
If you change it to a static assert, you can test CTFE and @nogc at the same time, right?
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.
Compile-time evaluated expressions are not restricted by the attributes of the surrounding function.
When it comes to testing CTFE, this isn't generally done for most of our library. To wit, the only function in std.range.package that tests CTFE appears to be takeNone
. This isn't entirely unreasonable because CTFE restrictions aren't really relevant in high level code.
However, issues do crop up when optimizations are applied, such as for array
and find
. In this case it's obvious that no CTFE restrictions are violated, but perhaps in some strange future this algorithm too could be optimized with some kind of low level trick. When testing CTFE though, it's not enough to test just one application - not only will different input types produce different functions, but CTFE restrictions only apply when they are encountered in the path currently being executed.
In this particular case CTFE can be tested decently well by just adding a single line to the static foreach, so I did that. It's not that simple in general.
@MetaLang, I missed your comment, but the answer is probably: checking both for |
Yes, I realized this just after I posted the comment so I deleted it. |
d856f3a
to
d7950e9
Compare
LGTM. I like tail better than advanceWithin; instantly makes sense to posix users. |
The idea behind TakeExactly is to provide extra information to the user. The length of the result is already computed so it's more informative to make it part of the result. Otherwise that information is lost. |
} | ||
else | ||
{ | ||
if (range.empty) |
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.
No need for this - just move scout.popFront()
to the end of the loop below.
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.
It means more calls to save
when the length of range
is 0
or n + 1
, but I suppose there's no reason to optimize for these cases.
d7950e9
to
374a75c
Compare
The current implementation is cute, but is it any different from the following? immutable length = range.walkLength; // note: O(1) when range has length
auto tail = range.drop(n > length? length - n : 0); // note: O(1) when range has slicing |
673857a
to
76cb935
Compare
} | ||
|
||
auto tail = range.save; | ||
while(!scout.empty) |
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.
Nitpick: space between while
and (
.
Other than that, LGTM. |
Suggested by Andrei Alexandrescu in this thread: http://forum.dlang.org/post/n3sfgg$1hpm$3@digitalmars.com
76cb935
to
a16cfc0
Compare
Fixed. Reimplementing this in user code requires at least one variable which makes it tedious for range composition, so even if the implementation offers no significant advantage in terms of performance or range capabilities (both input and output), I think it's worth including. Further, I think the branch for |
.lineSplitter | ||
.tail(2) | ||
.joiner("\n") | ||
.equal("two\nthree")); |
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.
Just now in a script I could have used just this pattern (lineSplitter
+ tail
) to parse some output from a child process. Neat.
I think I should add a path for bidirectional ranges with length. What about bidirectional ranges without length, though? Should we assume the beginning of the tail is closer to the end than the beginning? |
I'd say that that's a pretty safe assumption. |
When If When So I guess iterating from the back is the slightly better choice overall. |
Erm, iterating from the back is not readily possible. Not sure what I was thinking. |
If you add the ability to make |
How so? |
You could make a static array as a buffer |
E[n] buffer;
auto remainder = range.retro.take(n).copy(buffer[].retro);
auto result = buffer[remainder.length .. $]; Whether or not this is appropriate for a standard library function aside, I think it's inappropriate for |
ping @andralex Is this OK to merge? Are the objections you raised about using |
Oh, I forgot to mention that the implementation does use I haven't linked this to an issue report yet. (edit: or would a manual changelog entry be preferable?) |
I think so |
Auto-merge toggled on |
For symmetry I truly feel that |
@nordlow, what do you mean? The front version of |
@nordlow that won't work. Some ranges define |
@andralex Ok. |
Forum thread:
http://forum.dlang.org/post/n3sfgg$1hpm$3@digitalmars.com
Differences from Andrei's suggestion:
Range
, notTakeExactly!Range
- the end of the resulting range is always the same as the input so this checks out and is a useful artifact.hasLength
.I thought
tail
was clever so I named it that, but I'll happily change it to the originally proposedadvanceWithin
if people want that.