| Thread overview | |||||||
|---|---|---|---|---|---|---|---|
|
April 26, 2009 Small iterators/algorithm usage feedback | ||||
|---|---|---|---|---|
| ||||
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.
| ||||
April 26, 2009 Re: Small iterators/algorithm usage feedback | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Denis Koroskin | 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 | |||
April 26, 2009 Re: Small iterators/algorithm usage feedback | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Denis Koroskin | == 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. | |||
April 26, 2009 Re: Small iterators/algorithm usage feedback | ||||
|---|---|---|---|---|
| ||||
Posted in reply to dsimcha | 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 | |||
April 27, 2009 Re: Small iterators/algorithm usage feedback | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Denis Koroskin | 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 | |||
Copyright © 1999-2021 by the D Language Foundation
Permalink
Reply