## digitalmars.D - Small iterators/algorithm usage feedback

• Denis Koroskin (37/37) Apr 26 2009 I have just started using iterators and algorithms a little.
• Derek Parnell (9/21) Apr 26 2009 I merely wrote my own version of strrpos() etc ... I at least know what ...
• dsimcha (15/52) Apr 26 2009 Phobos/druntime.
• Brad Roberts (46/99) Apr 26 2009 I haven't played with any of the recent changes, so I figured this might
• Andrei Alexandrescu (8/17) Apr 26 2009 I think you are confusing iterators with ranges. Iterators are gone from
"Denis Koroskin" <2korden gmail.com> writes:
```I have just started using iterators and algorithms a little.
Given a full file path, a needed to get folder name where it is located, and a
name of the that file.

Using C and its standard library, I can do it as follows:

auto pos = strrpos(fullFilePath, '/'); // strrpos = strpos-reverse
string dirName = fullFilePath[0..pos];
string fileName = fullFilePath[pos+1..\$];

It's very simple, I'd use it, but there is no strrpos (nor strpos) in
Phobos/druntime.
So I tried using the following code:

auto it = find(retro(fullFilePath), '/'); // returns Iterator!(Retro!(string))

The hardest part is complete, I thought, but I was wrong.

Now, I realized that I can't do anything with this iterator.
I tried get a position, but the following code failed:

int pos = rBegin(fullFilePath) - it;

Error: incompatible types for ((rBegin(fullFilePath)) - (it)):
'Iterator!(Retro!(string))' and 'Iterator!(Retro!(string))'

Apparently, there is no opSub() in an Iterator's method set.

Okay, let's take a row pointer to a char and calculate the position by hand:

int pos = &(*it) - fullFilePath.ptr; // a common C++ practice

But it failed, too:
Error: it.opStar() is not an lvalue.

Oh, well, you can't take an address of a temporary, let's store it first:

ref immutable(char) c = *it;
immutable(char)* ptr = &c;

Error: found 'ref' instead of statement

Oops, let's write a workaround:

{
return &c;
}

Error: function unwrap (ref immutable(char) c) does not match parameter types
(immutable(char))

Oh, it looks like "*it" doesn't return a reference but a copy :(

Next, I thought: that's probably right. It's probably error-prone and
disallowed on purpose. It may be better and closer to range-style to get
subranges out of a these iterators (begin..it)/(it..end) and finish the task:

string dirName = range(begin(fullFilePath), it);
string fileName = range(it + 1, end(fullFilePath));

But that failed, too:

Error: template std.iterator.range(T) does not match any function template
declaration

I tried different other combinations, but all of them failed.

I hope I missed something very simple, but that's what I experienced (being a
professional C++ developer who knows, uses and loves STL). I believe others may
have similar difficulties, too, so I thought it may be helpful to post my
experience here. I hope it'll be constructive.
```
Apr 26 2009
Derek Parnell <derek psych.ward> writes:
```On Mon, 27 Apr 2009 01:53:27 +0400, Denis Koroskin wrote:

I have just started using iterators and algorithms a little.
Given a full file path, a needed to get folder name where
it is located, and a name of the that file.

Using C and its standard library, I can do it as follows:

auto pos = strrpos(fullFilePath, '/'); // strrpos = strpos-reverse
string dirName = fullFilePath[0..pos];
string fileName = fullFilePath[pos+1..\$];

It's very simple, I'd use it, but there is no strrpos (nor strpos) in
Phobos/druntime.
So I tried using the following code: ...

I merely wrote my own version of strrpos() etc ... I at least know what it
does and why it does it. But this was before any of the 'range' stuff in D
was thought of.

Sorry I can't be of any help.

--
Derek Parnell
Melbourne, Australia
skype: derek.j.parnell
```
Apr 26 2009
dsimcha <dsimcha yahoo.com> writes:
```== Quote from Denis Koroskin (2korden gmail.com)'s article
I have just started using iterators and algorithms a little.
Given a full file path, a needed to get folder name where it is located, and a

name of the that file.
Using C and its standard library, I can do it as follows:
auto pos = strrpos(fullFilePath, '/'); // strrpos = strpos-reverse
string dirName = fullFilePath[0..pos];
string fileName = fullFilePath[pos+1..\$];
It's very simple, I'd use it, but there is no strrpos (nor strpos) in

Phobos/druntime.
So I tried using the following code:
auto it = find(retro(fullFilePath), '/'); // returns Iterator!(Retro!(string))
The hardest part is complete, I thought, but I was wrong.
Now, I realized that I can't do anything with this iterator.
I tried get a position, but the following code failed:
int pos = rBegin(fullFilePath) - it;
Error: incompatible types for ((rBegin(fullFilePath)) - (it)):

'Iterator!(Retro!(string))' and 'Iterator!(Retro!(string))'
Apparently, there is no opSub() in an Iterator's method set.
Okay, let's take a row pointer to a char and calculate the position by hand:
int pos = &(*it) - fullFilePath.ptr; // a common C++ practice
But it failed, too:
Error: it.opStar() is not an lvalue.
Oh, well, you can't take an address of a temporary, let's store it first:
ref immutable(char) c = *it;
immutable(char)* ptr = &c;
Error: found 'ref' instead of statement
Oops, let's write a workaround:
{
return &c;
}
Error: function unwrap (ref immutable(char) c) does not match parameter types

(immutable(char))
Oh, it looks like "*it" doesn't return a reference but a copy :(
Next, I thought: that's probably right. It's probably error-prone and
disallowed

on purpose. It may be better and closer to range-style to get subranges out of a
these iterators (begin..it)/(it..end) and finish the task:
string dirName = range(begin(fullFilePath), it);
string fileName = range(it + 1, end(fullFilePath));
But that failed, too:
Error: template std.iterator.range(T) does not match any function template

declaration
I tried different other combinations, but all of them failed.
I hope I missed something very simple, but that's what I experienced (being a

professional C++ developer who knows, uses and loves STL). I believe others may
have similar difficulties, too, so I thought it may be helpful to post my
experience here. I hope it'll be constructive.

Yes, std.algorithm is supposed to be very generic, rather than focusing on doing
one thing well.  This is good when you have some very generic needs, but since
strings are such a common thing, we have std.string.rfind to handle exactly what
you're looking for without massive template gymnastics.
```
Apr 26 2009
```dsimcha wrote:
== Quote from Denis Koroskin (2korden gmail.com)'s article
I have just started using iterators and algorithms a little.
Given a full file path, a needed to get folder name where it is located, and a

name of the that file.
Using C and its standard library, I can do it as follows:
auto pos = strrpos(fullFilePath, '/'); // strrpos = strpos-reverse
string dirName = fullFilePath[0..pos];
string fileName = fullFilePath[pos+1..\$];
It's very simple, I'd use it, but there is no strrpos (nor strpos) in

Phobos/druntime.
So I tried using the following code:
auto it = find(retro(fullFilePath), '/'); // returns Iterator!(Retro!(string))
The hardest part is complete, I thought, but I was wrong.
Now, I realized that I can't do anything with this iterator.
I tried get a position, but the following code failed:
int pos = rBegin(fullFilePath) - it;
Error: incompatible types for ((rBegin(fullFilePath)) - (it)):

'Iterator!(Retro!(string))' and 'Iterator!(Retro!(string))'
Apparently, there is no opSub() in an Iterator's method set.
Okay, let's take a row pointer to a char and calculate the position by hand:
int pos = &(*it) - fullFilePath.ptr; // a common C++ practice
But it failed, too:
Error: it.opStar() is not an lvalue.
Oh, well, you can't take an address of a temporary, let's store it first:
ref immutable(char) c = *it;
immutable(char)* ptr = &c;
Error: found 'ref' instead of statement
Oops, let's write a workaround:
{
return &c;
}
Error: function unwrap (ref immutable(char) c) does not match parameter types

(immutable(char))
Oh, it looks like "*it" doesn't return a reference but a copy :(
Next, I thought: that's probably right. It's probably error-prone and
disallowed

on purpose. It may be better and closer to range-style to get subranges out of
a
these iterators (begin..it)/(it..end) and finish the task:
string dirName = range(begin(fullFilePath), it);
string fileName = range(it + 1, end(fullFilePath));
But that failed, too:
Error: template std.iterator.range(T) does not match any function template

declaration
I tried different other combinations, but all of them failed.
I hope I missed something very simple, but that's what I experienced (being a

professional C++ developer who knows, uses and loves STL). I believe others may
have similar difficulties, too, so I thought it may be helpful to post my
experience here. I hope it'll be constructive.

Yes, std.algorithm is supposed to be very generic, rather than focusing on
doing
one thing well.  This is good when you have some very generic needs, but since
strings are such a common thing, we have std.string.rfind to handle exactly
what
you're looking for without massive template gymnastics.

I haven't played with any of the recent changes, so I figured this might
be a fun exercise to try myself as well.  Here's what I ended up with:

import std.algorithm;
import std.range;
import std.stdio;

void main()
{
string inputpath = "/a/b";

auto parts = splitter(inputpath, "/");
parts.popFront; // remove unwanted empty element
writeln("split parts:");
foreach(a; parts)
writefln("  a = %s", a);

auto file = retro(parts).popFront;  // line 19
writefln("file = %s", file);
writeln("remainder:");
foreach(a; parts)
writefln("  a = %s", a);

auto path = reduce!(q{a ~= "/" ~ b})("", parts);
writefln("path = %s", path);
}

The problem is that splitter isn't a bi-dir range, so it fails with:
./path.d(19): Error: template std.range.retro(R) if
(isBidirectionalRange!(R)) does not match any function template declaration
./path.d(19): Error: template std.range.retro(R) if
(isBidirectionalRange!(R)) cannot deduce template function from argument
types !()(Splitter!(immutable(char)[],immutable(char)[]))
./path.d(19): Error: no property 'popFront' for type 'int'

Comment out lines 19 and 20 just to confirm the rest works:
split parts:
a = a
a = b
remainder:
a = a
a = b
path = /a/b

Looking at the code behind Splitter.. it shouldn't be hard to fix, but I
haven't yet.

Obviously this code does more string (and thus memory) manipulation than
strictly necessary to do this job.  So, for the sake of completeness to
this thread... Denis, you're aware of std.path and its basename and
dirname functions, right?  I assume from the first post in the thread
that this is an exercise of using ranges and algorithms.

Later,
```
Apr 26 2009
Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
```Denis Koroskin wrote:
I have just started using iterators and algorithms a little.
Given a full file path, a needed to get folder name where it is located,
and a name of the that file.

Using C and its standard library, I can do it as follows:

auto pos = strrpos(fullFilePath, '/'); // strrpos = strpos-reverse
string dirName = fullFilePath[0..pos];
string fileName = fullFilePath[pos+1..\$];

I think you are confusing iterators with ranges. Iterators are gone from
Phobos.

(fixed code)

auto pos = find(retro(fullFilePath)).length - 1;
auto dirname = fullFilePath[0..pos];
auto filename = fullFilePath[pos+1..\$];

Andrei
```
Apr 26 2009