mirror of
https://github.com/dlang/phobos.git
synced 2025-05-11 06:28:28 +03:00
Moved split from string to array, made one more pass through array
This commit is contained in:
parent
907a34e7f2
commit
331dd3a489
5 changed files with 538 additions and 488 deletions
252
std/algorithm.d
252
std/algorithm.d
|
@ -269,19 +269,20 @@ unittest
|
|||
fibsSquares.popFront;
|
||||
assert(fibsSquares.front == 9);
|
||||
|
||||
auto repeatMap = map!"a"(repeat(1));
|
||||
static assert(isInfinite!(typeof(repeatMap)));
|
||||
auto repeatMap = map!"a"(repeat(1));
|
||||
static assert(isInfinite!(typeof(repeatMap)));
|
||||
|
||||
auto intRange = map!"a"([1,2,3]);
|
||||
static assert(isRandomAccessRange!(typeof(intRange)));
|
||||
|
||||
foreach(DummyType; AllDummyRanges)
|
||||
{
|
||||
DummyType d;
|
||||
auto m = map!"a * a"(d);
|
||||
|
||||
auto intRange = map!"a"([1,2,3]);
|
||||
static assert(isRandomAccessRange!(typeof(intRange)));
|
||||
|
||||
foreach(DummyType; AllDummyRanges) {
|
||||
DummyType d;
|
||||
auto m = map!"a * a"(d);
|
||||
|
||||
static assert(propagatesRangeType!(typeof(m), DummyType));
|
||||
assert(equal(m, [1,4,9,16,25,36,49,64,81,100]));
|
||||
}
|
||||
static assert(propagatesRangeType!(typeof(m), DummyType));
|
||||
assert(equal(m, [1,4,9,16,25,36,49,64,81,100]));
|
||||
}
|
||||
}
|
||||
|
||||
// reduce
|
||||
|
@ -1453,9 +1454,9 @@ public:
|
|||
/// Ditto
|
||||
Splitter!(Range, Separator)
|
||||
splitter(Range, Separator)(Range r, Separator s)
|
||||
if (is(typeof(ElementType!(Range).init == ElementType!(Separator).init))
|
||||
if (is(typeof(ElementType!Range.init == ElementType!Separator.init))
|
||||
||
|
||||
is(typeof(ElementType!(Range).init == Separator.init))
|
||||
is(typeof(ElementType!Range.init == Separator.init))
|
||||
)
|
||||
{
|
||||
return typeof(return)(r, s);
|
||||
|
@ -1528,7 +1529,7 @@ Splits a range using another range as a separator. This can be used
|
|||
with any range type, but is most popular with string types.
|
||||
*/
|
||||
struct Splitter(Range, Separator)
|
||||
if (is(typeof(Range.init.front == Separator.init.front)))
|
||||
if (is(typeof(Range.init.front == Separator.init.front) : bool))
|
||||
{
|
||||
private:
|
||||
Range _input;
|
||||
|
@ -1721,7 +1722,8 @@ struct Splitter(alias isTerminator, Range,
|
|||
Slice = Select!(is(typeof(Range.init[0 .. 1])),
|
||||
Range,
|
||||
ElementType!(Range)[]))
|
||||
if(!is(isTerminator)) {
|
||||
if(!is(isTerminator))
|
||||
{
|
||||
private Range _input;
|
||||
private size_t _end;
|
||||
private alias unaryFun!isTerminator _isTerminator;
|
||||
|
@ -1867,25 +1869,87 @@ assert(equal(joiner(["Mary", "has", "a", "little", "lamb"], "..."),
|
|||
"Mary...has...a...little...lamb"));
|
||||
----
|
||||
*/
|
||||
auto joiner(Range, Separator)(Range r, Separator sep)
|
||||
auto joiner(RoR, Separator)(RoR r, Separator sep)
|
||||
if (isForwardRange!RoR && isInputRange!(ElementType!RoR)
|
||||
&& isForwardRange!Separator
|
||||
&& is(ElementType!Separator : ElementType!(ElementType!RoR)))
|
||||
{
|
||||
struct Result
|
||||
static struct Result
|
||||
{
|
||||
private:
|
||||
Range _items;
|
||||
Separator _sep, _currentSep;
|
||||
public:
|
||||
@property bool empty()
|
||||
private RoR _items;
|
||||
private ElementType!RoR _current;
|
||||
private Separator _sep, _currentSep;
|
||||
|
||||
private void useSeparator()
|
||||
{
|
||||
return _items.empty;
|
||||
assert(_currentSep.empty && _current.empty,
|
||||
"joiner: internal error");
|
||||
if (_sep.empty)
|
||||
{
|
||||
// Advance to the next range in the
|
||||
// input
|
||||
//_items.popFront();
|
||||
for (;; _items.popFront())
|
||||
{
|
||||
if (_items.empty) return;
|
||||
if (!_items.front.empty) break;
|
||||
}
|
||||
_current = _items.front;
|
||||
_items.popFront();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Must make sure something is coming after the
|
||||
// separator - it's a separator, not a terminator!
|
||||
if (_items.empty) return;
|
||||
_currentSep = _sep.save;
|
||||
assert(!_currentSep.empty);
|
||||
}
|
||||
}
|
||||
@property ElementType!(ElementType!Range) front()
|
||||
|
||||
private void useItem()
|
||||
{
|
||||
assert(_currentSep.empty && _current.empty,
|
||||
"joiner: internal error");
|
||||
// Use the input
|
||||
if (_items.empty) return;
|
||||
_current = _items.front;
|
||||
_items.popFront();
|
||||
if (!_current.empty)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// No data in the current item - toggle to use the
|
||||
// separator
|
||||
useSeparator();
|
||||
}
|
||||
|
||||
this(RoR items, Separator sep)
|
||||
{
|
||||
_items = items;
|
||||
_sep = sep;
|
||||
useItem();
|
||||
// We need the separator if the input has at least two
|
||||
// elements
|
||||
if (_current.empty && _items.empty)
|
||||
{
|
||||
// Vacate the whole thing
|
||||
_currentSep = _currentSep.init;
|
||||
}
|
||||
}
|
||||
|
||||
@property auto empty()
|
||||
{
|
||||
return _current.empty && _currentSep.empty;
|
||||
}
|
||||
|
||||
@property ElementType!(ElementType!RoR) front()
|
||||
{
|
||||
assert(!empty);
|
||||
if (!_currentSep.empty) return _currentSep.front;
|
||||
if (!_items.front.empty) return _items.front.front;
|
||||
assert(false);
|
||||
assert(!_current.empty);
|
||||
return _current.front;
|
||||
}
|
||||
|
||||
void popFront()
|
||||
{
|
||||
assert(!empty);
|
||||
|
@ -1893,47 +1957,33 @@ auto joiner(Range, Separator)(Range r, Separator sep)
|
|||
if (!_currentSep.empty)
|
||||
{
|
||||
_currentSep.popFront();
|
||||
if (_currentSep.empty)
|
||||
{
|
||||
// Explore the next item in the range
|
||||
if (_items.front.empty)
|
||||
{
|
||||
// Null item, will write a new separator
|
||||
_items.popFront();
|
||||
if (!_items.empty)
|
||||
{
|
||||
_currentSep = _sep.save;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!_currentSep.empty) return;
|
||||
useItem();
|
||||
}
|
||||
else
|
||||
{
|
||||
// we're using the range
|
||||
assert(!_items.empty && !_items.front.empty);
|
||||
_items.front.popFront();
|
||||
if (_items.front.empty)
|
||||
{
|
||||
_items.popFront();
|
||||
if (!_items.empty)
|
||||
{
|
||||
_currentSep = _sep.save;
|
||||
}
|
||||
}
|
||||
_current.popFront();
|
||||
if (!_current.empty) return;
|
||||
useSeparator();
|
||||
}
|
||||
assert(empty || !_currentSep.empty || !_items.front.empty);
|
||||
// We need to re-prime the range
|
||||
}
|
||||
}
|
||||
auto result = Result(r, sep);
|
||||
if (!r.empty && r.front.empty)
|
||||
{
|
||||
result._items.popFront();
|
||||
if (!result.empty)
|
||||
|
||||
static if (isForwardRange!RoR && isForwardRange!(ElementType!RoR))
|
||||
{
|
||||
result._currentSep = result._sep.save;
|
||||
@property auto save()
|
||||
{
|
||||
Result copy;
|
||||
copy._items = _items.save;
|
||||
copy._current = _current.save;
|
||||
copy._sep = _sep.save;
|
||||
copy._currentSep = _currentSep.save;
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return Result(r, sep);
|
||||
}
|
||||
|
||||
unittest
|
||||
|
@ -1941,9 +1991,9 @@ unittest
|
|||
debug(std_algorithm) scope(success)
|
||||
writeln("unittest @", __FILE__, ":", __LINE__, " done.");
|
||||
static assert(isInputRange!(typeof(joiner([""], ""))));
|
||||
static assert(!isForwardRange!(typeof(joiner([""], ""))));
|
||||
assert(equal(joiner([""], "xyz"), ""));
|
||||
assert(equal(joiner(["", ""], "xyz"), "xyz"));
|
||||
static assert(isForwardRange!(typeof(joiner([""], ""))));
|
||||
assert(equal(joiner([""], "xyz"), ""), text(joiner([""], "xyz")));
|
||||
assert(equal(joiner(["", ""], "xyz"), "xyz"), text(joiner(["", ""], "xyz")));
|
||||
assert(equal(joiner(["", "abc"], "xyz"), "xyzabc"));
|
||||
assert(equal(joiner(["abc", ""], "xyz"), "abcxyz"));
|
||||
assert(equal(joiner(["abc", "def"], "xyz"), "abcxyzdef"));
|
||||
|
@ -1951,6 +2001,82 @@ unittest
|
|||
"Mary...has...a...little...lamb"));
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
static if (isInfinite!(ElementType!RoR))
|
||||
{
|
||||
enum bool empty = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
@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);
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(std_algorithm) scope(success)
|
||||
writeln("unittest @", __FILE__, ":", __LINE__, " done.");
|
||||
static assert(isInputRange!(typeof(joiner([""]))));
|
||||
static assert(isForwardRange!(typeof(joiner([""]))));
|
||||
assert(equal(joiner([""]), ""));
|
||||
assert(equal(joiner(["", ""]), ""));
|
||||
assert(equal(joiner(["", "abc"]), "abc"));
|
||||
assert(equal(joiner(["abc", ""]), "abc"));
|
||||
assert(equal(joiner(["abc", "def"]), "abcdef"));
|
||||
assert(equal(joiner(["Mary", "has", "a", "little", "lamb"]),
|
||||
"Maryhasalittlelamb"));
|
||||
assert(equal(joiner(std.range.repeat("abc", 3)), "abcabcabc"));
|
||||
}
|
||||
|
||||
// uniq
|
||||
/**
|
||||
Iterates unique consecutive elements of the given range (functionality
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue