join
Andrei Alexandrescu
SeeWebsiteForEmail at erdani.org
Tue Jan 18 11:25:55 PST 2011
I implemented a simple separatorless joiner as follows:
auto joiner(RoR)(RoR r)
if (isInputRange!RoR && isInputRange!(ElementType!RoR))
{
static struct Result
{
private:
RoR _items;
ElementType!RoR _current;
void prime()
{
for (;; _items.popFront())
{
if (_items.empty) return;
if (!_items.front.empty) break;
}
_current = _items.front;
_items.popFront();
}
public:
this(RoR r)
{
_items = r;
prime();
}
@property auto empty()
{
return _current.empty;
}
@property auto ref front()
{
assert(!empty);
return _current.front;
}
void popFront()
{
assert(!_current.empty);
_current.popFront();
if (_current.empty) prime();
}
static if (isForwardRange!RoR && isForwardRange!(ElementType!RoR))
{
@property auto save()
{
Result copy;
copy._items = _items.save;
copy._current = _current.save;
return copy;
}
}
}
return Result(r);
}
The code has a few properties that I'd like to discuss a bit:
1. It doesn't provide bidirectional primitives, although it often could.
The rationale is that implementing back and popBack incurs size and time
overheads that are difficult to justify. Most of the time people just
want to join stuff and go through it forward. The counterargument is
that providing those primitives would make join more interesting and
opens the door to other idioms. What say you?
2. joiner uses an idiom that I've experimented with in the past: it
defines a local struct and returns it. As such, joiner's type is
impossible to express without auto. I find that idiom interesting for
many reasons, among which the simplest is that the code is terse,
compact, and doesn't pollute the namespace. I'm thinking we should do
the same for Appender - it doesn't make much sense to create an Appender
except by calling the appender() function.
3. Walter, Don, kindly please fix ddoc so it works with auto. What used
to be an annoyance becomes a disabler for the idiom above. Currently it
is impossible to document joiner (aside from unsavory tricks).
4. I found the prime() idiom quite frequent when defining ranges.
Essentially prime() positions the troops by the border. Both the
constructor and popFront() call prime().
5. auto and auto ref rock - they allow simple, correct definitions.
6. Currently joiner() has a bug: it will not work as expected for
certain ranges. Which ranges are those, and how can the bug be fixed?
Andrei
More information about the Digitalmars-d
mailing list