www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Small iterators/algorithm usage feedback

reply "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:

immutable(char)* getAddress(ref immutable(char) c)
{
    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
next sibling parent 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
prev sibling next sibling parent reply 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:
 immutable(char)* getAddress(ref immutable(char) c)
 {
     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
parent Brad Roberts <braddr puremagic.com> writes:
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:
 immutable(char)* getAddress(ref immutable(char) c)
 {
     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, Brad
Apr 26 2009
prev sibling parent 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