mirror of
https://github.com/dlang/phobos.git
synced 2025-05-12 23:29:01 +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;
|
fibsSquares.popFront;
|
||||||
assert(fibsSquares.front == 9);
|
assert(fibsSquares.front == 9);
|
||||||
|
|
||||||
auto repeatMap = map!"a"(repeat(1));
|
auto repeatMap = map!"a"(repeat(1));
|
||||||
static assert(isInfinite!(typeof(repeatMap)));
|
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(propagatesRangeType!(typeof(m), DummyType));
|
||||||
static assert(isRandomAccessRange!(typeof(intRange)));
|
assert(equal(m, [1,4,9,16,25,36,49,64,81,100]));
|
||||||
|
}
|
||||||
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]));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// reduce
|
// reduce
|
||||||
|
@ -1453,9 +1454,9 @@ public:
|
||||||
/// Ditto
|
/// Ditto
|
||||||
Splitter!(Range, Separator)
|
Splitter!(Range, Separator)
|
||||||
splitter(Range, Separator)(Range r, Separator s)
|
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);
|
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.
|
with any range type, but is most popular with string types.
|
||||||
*/
|
*/
|
||||||
struct Splitter(Range, Separator)
|
struct Splitter(Range, Separator)
|
||||||
if (is(typeof(Range.init.front == Separator.init.front)))
|
if (is(typeof(Range.init.front == Separator.init.front) : bool))
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
Range _input;
|
Range _input;
|
||||||
|
@ -1721,7 +1722,8 @@ struct Splitter(alias isTerminator, Range,
|
||||||
Slice = Select!(is(typeof(Range.init[0 .. 1])),
|
Slice = Select!(is(typeof(Range.init[0 .. 1])),
|
||||||
Range,
|
Range,
|
||||||
ElementType!(Range)[]))
|
ElementType!(Range)[]))
|
||||||
if(!is(isTerminator)) {
|
if(!is(isTerminator))
|
||||||
|
{
|
||||||
private Range _input;
|
private Range _input;
|
||||||
private size_t _end;
|
private size_t _end;
|
||||||
private alias unaryFun!isTerminator _isTerminator;
|
private alias unaryFun!isTerminator _isTerminator;
|
||||||
|
@ -1867,25 +1869,87 @@ assert(equal(joiner(["Mary", "has", "a", "little", "lamb"], "..."),
|
||||||
"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:
|
private RoR _items;
|
||||||
Range _items;
|
private ElementType!RoR _current;
|
||||||
Separator _sep, _currentSep;
|
private Separator _sep, _currentSep;
|
||||||
public:
|
|
||||||
@property bool empty()
|
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 (!_currentSep.empty) return _currentSep.front;
|
||||||
if (!_items.front.empty) return _items.front.front;
|
assert(!_current.empty);
|
||||||
assert(false);
|
return _current.front;
|
||||||
}
|
}
|
||||||
|
|
||||||
void popFront()
|
void popFront()
|
||||||
{
|
{
|
||||||
assert(!empty);
|
assert(!empty);
|
||||||
|
@ -1893,47 +1957,33 @@ auto joiner(Range, Separator)(Range r, Separator sep)
|
||||||
if (!_currentSep.empty)
|
if (!_currentSep.empty)
|
||||||
{
|
{
|
||||||
_currentSep.popFront();
|
_currentSep.popFront();
|
||||||
if (_currentSep.empty)
|
if (!_currentSep.empty) return;
|
||||||
{
|
useItem();
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// we're using the range
|
// we're using the range
|
||||||
assert(!_items.empty && !_items.front.empty);
|
_current.popFront();
|
||||||
_items.front.popFront();
|
if (!_current.empty) return;
|
||||||
if (_items.front.empty)
|
useSeparator();
|
||||||
{
|
|
||||||
_items.popFront();
|
|
||||||
if (!_items.empty)
|
|
||||||
{
|
|
||||||
_currentSep = _sep.save;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
assert(empty || !_currentSep.empty || !_items.front.empty);
|
// We need to re-prime the range
|
||||||
}
|
}
|
||||||
}
|
|
||||||
auto result = Result(r, sep);
|
static if (isForwardRange!RoR && isForwardRange!(ElementType!RoR))
|
||||||
if (!r.empty && r.front.empty)
|
|
||||||
{
|
|
||||||
result._items.popFront();
|
|
||||||
if (!result.empty)
|
|
||||||
{
|
{
|
||||||
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
|
unittest
|
||||||
|
@ -1941,9 +1991,9 @@ unittest
|
||||||
debug(std_algorithm) scope(success)
|
debug(std_algorithm) scope(success)
|
||||||
writeln("unittest @", __FILE__, ":", __LINE__, " done.");
|
writeln("unittest @", __FILE__, ":", __LINE__, " done.");
|
||||||
static assert(isInputRange!(typeof(joiner([""], ""))));
|
static assert(isInputRange!(typeof(joiner([""], ""))));
|
||||||
static assert(!isForwardRange!(typeof(joiner([""], ""))));
|
static assert(isForwardRange!(typeof(joiner([""], ""))));
|
||||||
assert(equal(joiner([""], "xyz"), ""));
|
assert(equal(joiner([""], "xyz"), ""), text(joiner([""], "xyz")));
|
||||||
assert(equal(joiner(["", ""], "xyz"), "xyz"));
|
assert(equal(joiner(["", ""], "xyz"), "xyz"), text(joiner(["", ""], "xyz")));
|
||||||
assert(equal(joiner(["", "abc"], "xyz"), "xyzabc"));
|
assert(equal(joiner(["", "abc"], "xyz"), "xyzabc"));
|
||||||
assert(equal(joiner(["abc", ""], "xyz"), "abcxyz"));
|
assert(equal(joiner(["abc", ""], "xyz"), "abcxyz"));
|
||||||
assert(equal(joiner(["abc", "def"], "xyz"), "abcxyzdef"));
|
assert(equal(joiner(["abc", "def"], "xyz"), "abcxyzdef"));
|
||||||
|
@ -1951,6 +2001,82 @@ unittest
|
||||||
"Mary...has...a...little...lamb"));
|
"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
|
// uniq
|
||||||
/**
|
/**
|
||||||
Iterates unique consecutive elements of the given range (functionality
|
Iterates unique consecutive elements of the given range (functionality
|
||||||
|
|
527
std/array.d
527
std/array.d
|
@ -1,31 +1,24 @@
|
||||||
// Written in the D programming language.
|
// Written in the D programming language.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Copyright: Copyright Andrei Alexandrescu 2008 - 2009.
|
Copyright: Copyright Andrei Alexandrescu 2008-.
|
||||||
License: <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>.
|
|
||||||
|
License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
|
||||||
|
|
||||||
Authors: $(WEB erdani.org, Andrei Alexandrescu)
|
Authors: $(WEB erdani.org, Andrei Alexandrescu)
|
||||||
*/
|
*/
|
||||||
/*
|
|
||||||
Copyright Andrei Alexandrescu 2008 - 2009.
|
|
||||||
Distributed under the Boost Software License, Version 1.0.
|
|
||||||
(See accompanying file LICENSE_1_0.txt or copy at
|
|
||||||
http://www.boost.org/LICENSE_1_0.txt)
|
|
||||||
*/
|
|
||||||
module std.array;
|
module std.array;
|
||||||
|
|
||||||
import std.c.stdio;
|
|
||||||
import core.memory;
|
import core.memory;
|
||||||
import std.algorithm, std.conv, std.encoding, std.exception, std.range,
|
import std.algorithm, std.conv, std.ctype, std.encoding, std.exception,
|
||||||
std.string, std.traits, std.typecons, std.utf;
|
std.intrinsic, std.range, std.string, std.traits, std.typecons, std.utf;
|
||||||
private import std.c.string : memcpy;
|
import std.c.string : memcpy;
|
||||||
private import std.intrinsic : bsr;
|
version(unittest) import std.stdio, std.typetuple;
|
||||||
version(unittest) private import std.stdio, std.typetuple;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Returns a newly-allocated dynamic array consisting of a copy of the input
|
Returns a newly-allocated dynamic array consisting of a copy of the
|
||||||
range, static array, dynamic array, or class or struct with an $(D opApply)
|
input range, static array, dynamic array, or class or struct with an
|
||||||
function $(D r). Note that narrow strings are handled
|
$(D opApply) function $(D r). Note that narrow strings are handled as
|
||||||
as a special case in an overload.
|
a special case in an overload.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
@ -85,27 +78,16 @@ This is handled as a special case and always returns a $(D dchar[]),
|
||||||
$(D const(dchar)[]), or $(D immutable(dchar)[]) depending on the constness of
|
$(D const(dchar)[]), or $(D immutable(dchar)[]) depending on the constness of
|
||||||
the input.
|
the input.
|
||||||
*/
|
*/
|
||||||
ElementType!String[] array(String)(String str) if(isNarrowString!String)
|
ElementType!String[] array(String)(String str) if (isNarrowString!String)
|
||||||
{
|
{
|
||||||
static if(is(typeof(return) == immutable))
|
return to!(typeof(return))(str);
|
||||||
{
|
|
||||||
return to!(immutable(dchar)[])(str);
|
|
||||||
}
|
|
||||||
else static if(is(typeof(return) == const))
|
|
||||||
{
|
|
||||||
return to!(const(dchar)[])(str);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return to!(dchar[])(str);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
version(unittest)
|
unittest
|
||||||
{
|
{
|
||||||
struct TestArray { int x; string toString() { return .to!string(x); } }
|
static struct TestArray { int x; string toString() { return .to!string(x); } }
|
||||||
|
|
||||||
struct OpAssign
|
static struct OpAssign
|
||||||
{
|
{
|
||||||
uint num;
|
uint num;
|
||||||
this(uint num) { this.num = num; }
|
this(uint num) { this.num = num; }
|
||||||
|
@ -115,7 +97,7 @@ version(unittest)
|
||||||
void opAssign(T)(T rhs) { this.num = rhs.num; }
|
void opAssign(T)(T rhs) { this.num = rhs.num; }
|
||||||
}
|
}
|
||||||
|
|
||||||
struct OpApply
|
static struct OpApply
|
||||||
{
|
{
|
||||||
int opApply(int delegate(ref int) dg)
|
int opApply(int delegate(ref int) dg)
|
||||||
{
|
{
|
||||||
|
@ -129,10 +111,7 @@ version(unittest)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
unittest
|
|
||||||
{
|
|
||||||
auto a = array([1, 2, 3, 4, 5][]);
|
auto a = array([1, 2, 3, 4, 5][]);
|
||||||
//writeln(a);
|
//writeln(a);
|
||||||
assert(a == [ 1, 2, 3, 4, 5 ]);
|
assert(a == [ 1, 2, 3, 4, 5 ]);
|
||||||
|
@ -170,12 +149,9 @@ equivalent to $(D empty(array)).
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
----
|
----
|
||||||
void main()
|
auto a = [ 1, 2, 3 ];
|
||||||
{
|
assert(!a.empty);
|
||||||
auto a = [ 1, 2, 3 ];
|
assert(a[3 .. $].empty);
|
||||||
assert(!a.empty);
|
|
||||||
assert(a[3 .. $].empty);
|
|
||||||
}
|
|
||||||
----
|
----
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -199,12 +175,9 @@ equivalent to $(D save(array)).
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
----
|
----
|
||||||
void main()
|
auto a = [ 1, 2, 3 ];
|
||||||
{
|
auto b = a.save;
|
||||||
auto a = [ 1, 2, 3 ];
|
assert(b is a);
|
||||||
auto b = a.save;
|
|
||||||
assert(b is a);
|
|
||||||
}
|
|
||||||
----
|
----
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -219,44 +192,36 @@ arrays. Due to the fact that nonmember functions can be called with
|
||||||
the first argument using the dot notation, $(D array.popFront) is
|
the first argument using the dot notation, $(D array.popFront) is
|
||||||
equivalent to $(D popFront(array)).
|
equivalent to $(D popFront(array)).
|
||||||
|
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
----
|
----
|
||||||
void main()
|
int[] a = [ 1, 2, 3 ];
|
||||||
{
|
a.popFront;
|
||||||
int[] a = [ 1, 2, 3 ];
|
assert(a == [ 2, 3 ]);
|
||||||
a.popFront;
|
|
||||||
assert(a == [ 2, 3 ]);
|
|
||||||
}
|
|
||||||
----
|
----
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void popFront(A)(ref A a)
|
void popFront(A)(ref A a)
|
||||||
if(!isNarrowString!A && isDynamicArray!A && isMutable!A && !is(A == void[]))
|
if (!isNarrowString!A && isDynamicArray!A && isMutable!A && !is(A == void[]))
|
||||||
{
|
{
|
||||||
alias typeof(A[0]) T;
|
|
||||||
assert(a.length, "Attempting to popFront() past the end of an array of "
|
assert(a.length, "Attempting to popFront() past the end of an array of "
|
||||||
~ T.stringof);
|
~ typeof(a[0]).stringof);
|
||||||
a = a[1 .. $];
|
a = a[1 .. $];
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
//@@@BUG 2608@@@
|
auto a = [ 1, 2, 3 ];
|
||||||
//auto a = [ 1, 2, 3 ];
|
a.popFront();
|
||||||
int[] a = [ 1, 2, 3 ];
|
|
||||||
a.popFront;
|
|
||||||
assert(a == [ 2, 3 ]);
|
assert(a == [ 2, 3 ]);
|
||||||
|
|
||||||
static assert(!__traits(compiles, popFront!(immutable int[])));
|
static assert(!__traits(compiles, popFront!(immutable int[])));
|
||||||
|
static assert(!__traits(compiles, popFront!(void[])));
|
||||||
}
|
}
|
||||||
|
|
||||||
void popFront(A)(ref A a)
|
void popFront(A)(ref A a)
|
||||||
if(isNarrowString!A && isMutable!A)
|
if (isNarrowString!A && isMutable!A)
|
||||||
{
|
{
|
||||||
alias typeof(a[0]) T;
|
|
||||||
assert(a.length, "Attempting to popFront() past the end of an array of "
|
assert(a.length, "Attempting to popFront() past the end of an array of "
|
||||||
~ T.stringof);
|
~ typeof(a[0]).stringof);
|
||||||
a = a[std.utf.stride(a, 0) .. $];
|
a = a[std.utf.stride(a, 0) .. $];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,17 +248,14 @@ equivalent to $(D popBack(array)).
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
----
|
----
|
||||||
void main()
|
int[] a = [ 1, 2, 3 ];
|
||||||
{
|
a.popBack();
|
||||||
int[] a = [ 1, 2, 3 ];
|
assert(a == [ 1, 2 ]);
|
||||||
a.popBack;
|
|
||||||
assert(a == [ 1, 2 ]);
|
|
||||||
}
|
|
||||||
----
|
----
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void popBack(A)(ref A a)
|
void popBack(A)(ref A a)
|
||||||
if(isDynamicArray!A && !isNarrowString!A && isMutable!A && !is(A == void[]))
|
if (isDynamicArray!A && !isNarrowString!A && isMutable!A && !is(A == void[]))
|
||||||
{
|
{
|
||||||
assert(a.length);
|
assert(a.length);
|
||||||
a = a[0 .. $ - 1];
|
a = a[0 .. $ - 1];
|
||||||
|
@ -301,17 +263,15 @@ if(isDynamicArray!A && !isNarrowString!A && isMutable!A && !is(A == void[]))
|
||||||
|
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
//@@@BUG 2608@@@
|
auto a = [ 1, 2, 3 ];
|
||||||
//auto a = [ 1, 2, 3 ];
|
a.popBack();
|
||||||
int[] a = [ 1, 2, 3 ];
|
|
||||||
a.popBack;
|
|
||||||
assert(a == [ 1, 2 ]);
|
assert(a == [ 1, 2 ]);
|
||||||
|
|
||||||
static assert(!__traits(compiles, popBack!(immutable int[])));
|
static assert(!__traits(compiles, popBack!(immutable int[])));
|
||||||
|
static assert(!__traits(compiles, popBack!(void[])));
|
||||||
}
|
}
|
||||||
|
|
||||||
void popBack(A)(ref A a)
|
@trusted void popBack(A)(ref A a)
|
||||||
if(is(A : const(char)[]) && isMutable!A)
|
if (is(A : const(char)[]) && isMutable!A)
|
||||||
{
|
{
|
||||||
immutable n = a.length;
|
immutable n = a.length;
|
||||||
const p = a.ptr + n;
|
const p = a.ptr + n;
|
||||||
|
@ -333,7 +293,7 @@ if(is(A : const(char)[]) && isMutable!A)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
assert(false, "Invalid UTF character at end of string");
|
throw new UtfException("Invalid UTF character at end of string");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,7 +302,6 @@ unittest
|
||||||
string s = "hello\xE2\x89\xA0";
|
string s = "hello\xE2\x89\xA0";
|
||||||
s.popBack();
|
s.popBack();
|
||||||
assert(s == "hello", s);
|
assert(s == "hello", s);
|
||||||
|
|
||||||
string s3 = "\xE2\x89\xA0";
|
string s3 = "\xE2\x89\xA0";
|
||||||
auto c = s3.back;
|
auto c = s3.back;
|
||||||
assert(c == cast(dchar)'\u2260');
|
assert(c == cast(dchar)'\u2260');
|
||||||
|
@ -352,17 +311,18 @@ unittest
|
||||||
static assert(!__traits(compiles, popBack!(immutable char[])));
|
static assert(!__traits(compiles, popBack!(immutable char[])));
|
||||||
}
|
}
|
||||||
|
|
||||||
void popBack(A)(ref A a)
|
@trusted void popBack(A)(ref A a)
|
||||||
if(is(A : const(wchar)[]) && isMutable!A)
|
if (is(A : const(wchar)[]) && isMutable!A)
|
||||||
{
|
{
|
||||||
assert(a.length);
|
assert(a.length);
|
||||||
if (a.length == 1)
|
if (a.length <= 1) // this is technically == but costs nothing and is safer
|
||||||
{
|
{
|
||||||
a = a[0 .. 0];
|
a = a[0 .. 0];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
immutable c = a[$ - 2];
|
// We can go commando from here on, we're safe; length is > 1
|
||||||
a = a[0 .. $ - 1 - (c >= 0xD800 && c <= 0xDBFF)];
|
immutable c = a.ptr[a.length - 2];
|
||||||
|
a = a.ptr[0 .. a.length - 1 - (c >= 0xD800 && c <= 0xDBFF)];
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
unittest
|
||||||
|
@ -383,31 +343,30 @@ equivalent to $(D front(array)).
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
----
|
----
|
||||||
void main()
|
int[] a = [ 1, 2, 3 ];
|
||||||
{
|
assert(a.front == 1);
|
||||||
int[] a = [ 1, 2, 3 ];
|
|
||||||
assert(a.front == 1);
|
|
||||||
}
|
|
||||||
----
|
----
|
||||||
*/
|
*/
|
||||||
ref typeof(A[0]) front(A)(A a)
|
ref T front(T)(T[] a)
|
||||||
if (is(typeof(A[0])) && !isNarrowString!A && !is(typeof(A[0]) : const(void)))
|
if (!isNarrowString!(T[]) && !is(T[] == void[]))
|
||||||
{
|
{
|
||||||
assert(a.length, "Attempting to fetch the front of an empty array");
|
assert(a.length, "Attempting to fetch the front of an empty array");
|
||||||
return a[0];
|
return a[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
dchar front(A)(A a) if (is(typeof(A[0])) && isNarrowString!A)
|
dchar front(A)(A a) if (isNarrowString!A)
|
||||||
{
|
{
|
||||||
assert(a.length, "Attempting to fetch the front of an empty array");
|
assert(a.length, "Attempting to fetch the front of an empty array");
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
return decode(a, i);
|
return decode(a, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto
|
unittest
|
||||||
void front(T)(T[] a, T v) if (!isNarrowString!A)
|
|
||||||
{
|
{
|
||||||
assert(a.length); a[0] = v;
|
auto a = [ 1, 2 ];
|
||||||
|
a.front = 4;
|
||||||
|
assert(a.front == 4);
|
||||||
|
assert(a == [ 4, 2 ]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -418,27 +377,15 @@ equivalent to $(D back(array)).
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
----
|
----
|
||||||
void main()
|
int[] a = [ 1, 2, 3 ];
|
||||||
{
|
assert(a.back == 3);
|
||||||
int[] a = [ 1, 2, 3 ];
|
|
||||||
assert(a.back == 3);
|
|
||||||
}
|
|
||||||
----
|
----
|
||||||
*/
|
*/
|
||||||
ref typeof(A.init[0]) back(A)(A a)
|
ref typeof(A.init[0]) back(A)(A a)
|
||||||
if (is(typeof(A.init[0])) && !isNarrowString!A
|
if (isDynamicArray!A && !isNarrowString!A
|
||||||
&& !is(typeof(A.init[0]) : const(void)))
|
&& !is(typeof(A.init[0]) : const(void)))
|
||||||
{
|
{
|
||||||
// @@@BUG@@@ The assert below crashes the unittest due to a bug in
|
assert(a.length, "Attempting to fetch the back of an empty array");
|
||||||
// the compiler
|
|
||||||
version (bug4426)
|
|
||||||
{
|
|
||||||
assert(a.length, "Attempting to fetch the back of an empty array");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
assert(a.length);
|
|
||||||
}
|
|
||||||
return a[$ - 1];
|
return a[$ - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -451,7 +398,7 @@ unittest
|
||||||
}
|
}
|
||||||
|
|
||||||
dchar back(A)(A a)
|
dchar back(A)(A a)
|
||||||
if (is(typeof(A.init[0])) && isNarrowString!A && a[0].sizeof < 4)
|
if (isDynamicArray!A && isNarrowString!A)
|
||||||
{
|
{
|
||||||
assert(a.length, "Attempting to fetch the back of an empty array");
|
assert(a.length, "Attempting to fetch the back of an empty array");
|
||||||
auto n = a.length;
|
auto n = a.length;
|
||||||
|
@ -459,7 +406,7 @@ if (is(typeof(A.init[0])) && isNarrowString!A && a[0].sizeof < 4)
|
||||||
if (n >= 1 && (p[-1] & 0b1100_0000) != 0b1000_0000)
|
if (n >= 1 && (p[-1] & 0b1100_0000) != 0b1000_0000)
|
||||||
{
|
{
|
||||||
--n;
|
--n;
|
||||||
return std.utf.decode(a, n);
|
return decode(a, n);
|
||||||
}
|
}
|
||||||
else if (n >= 2 && (p[-2] & 0b1100_0000) != 0b1000_0000)
|
else if (n >= 2 && (p[-2] & 0b1100_0000) != 0b1000_0000)
|
||||||
{
|
{
|
||||||
|
@ -527,46 +474,49 @@ unittest
|
||||||
Inserts $(D stuff) in $(D container) at position $(D pos).
|
Inserts $(D stuff) in $(D container) at position $(D pos).
|
||||||
*/
|
*/
|
||||||
void insert(T, Range)(ref T[] array, size_t pos, Range stuff)
|
void insert(T, Range)(ref T[] array, size_t pos, Range stuff)
|
||||||
|
if (isInputRange!Range && is(ElementType!Range : T))
|
||||||
{
|
{
|
||||||
static if (is(typeof(stuff[0])))
|
static if (hasLength!Range)
|
||||||
{
|
{
|
||||||
// presumably an array
|
// @@@BUG 2130@@@
|
||||||
alias stuff toInsert;
|
// immutable
|
||||||
//assert(!overlap(array, toInsert));
|
// size_t delta = toInsert.length,
|
||||||
|
// size_t oldLength = array.length,
|
||||||
|
// size_t newLength = oldLength + delta;
|
||||||
|
immutable
|
||||||
|
delta = stuff.length,
|
||||||
|
oldLength = array.length,
|
||||||
|
newLength = oldLength + delta;
|
||||||
|
|
||||||
|
// Reallocate the array to make space for new content
|
||||||
|
array = (cast(T*) core.memory.GC.realloc(array.ptr,
|
||||||
|
newLength * array[0].sizeof))[0 .. newLength];
|
||||||
|
assert(array.length == newLength);
|
||||||
|
|
||||||
|
// Move data in pos .. pos + stuff.length to the end of the array
|
||||||
|
foreach_reverse (i; pos .. oldLength)
|
||||||
|
{
|
||||||
|
// This will be guaranteed to not throw
|
||||||
|
move(array[i], array[i + delta]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy stuff into array
|
||||||
|
copy(stuff, array[pos .. pos + stuff.length]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// presumably only one element
|
auto app = appender!(T[])();
|
||||||
auto toInsert = (&stuff)[0 .. 1];
|
app.put(array[0 .. pos]);
|
||||||
|
app.put(stuff);
|
||||||
|
app.put(array[pos .. $]);
|
||||||
|
array = app.data;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// @@@BUG 2130@@@
|
/// Ditto
|
||||||
// immutable
|
void insert(T)(ref T[] array, size_t pos, T stuff)
|
||||||
// size_t delta = toInsert.length,
|
{
|
||||||
// size_t oldLength = array.length,
|
return insert(array, pos, (&stuff)[0 .. 1]);
|
||||||
// size_t newLength = oldLength + delta;
|
|
||||||
immutable
|
|
||||||
delta = toInsert.length,
|
|
||||||
oldLength = array.length,
|
|
||||||
newLength = oldLength + delta;
|
|
||||||
|
|
||||||
// Reallocate the array to make space for new content
|
|
||||||
array = (cast(T*) core.memory.GC.realloc(array.ptr,
|
|
||||||
newLength * array[0].sizeof))[0 .. newLength];
|
|
||||||
assert(array.length == newLength);
|
|
||||||
|
|
||||||
// Move data in pos .. pos + stuff.length to the end of the array
|
|
||||||
foreach_reverse (i; pos .. oldLength)
|
|
||||||
{
|
|
||||||
// This will be guaranteed to not throw
|
|
||||||
move(array[i], array[i + delta]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy stuff into array
|
|
||||||
foreach (e; toInsert)
|
|
||||||
{
|
|
||||||
array[pos++] = e;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
unittest
|
||||||
|
@ -579,7 +529,7 @@ unittest
|
||||||
}
|
}
|
||||||
|
|
||||||
// @@@ TODO: document this
|
// @@@ TODO: document this
|
||||||
bool sameHead(T)(in T[] lhs, in T[] rhs)
|
pure bool sameHead(T)(in T[] lhs, in T[] rhs)
|
||||||
{
|
{
|
||||||
return lhs.ptr == rhs.ptr;
|
return lhs.ptr == rhs.ptr;
|
||||||
}
|
}
|
||||||
|
@ -588,9 +538,9 @@ bool sameHead(T)(in T[] lhs, in T[] rhs)
|
||||||
* Return an array that consists of $(D s) (which must be an input
|
* Return an array that consists of $(D s) (which must be an input
|
||||||
* range) repeated $(D n) times.
|
* range) repeated $(D n) times.
|
||||||
*/
|
*/
|
||||||
|
S replicate(S)(S s, size_t n) if (isSomeString!S)
|
||||||
S multiply(S)(S s, size_t n) if (isSomeString!S)
|
|
||||||
{
|
{
|
||||||
|
// Optimization for return join(std.range.repeat(s, n));
|
||||||
if (n == 0)
|
if (n == 0)
|
||||||
return S.init;
|
return S.init;
|
||||||
if (n == 1)
|
if (n == 1)
|
||||||
|
@ -609,102 +559,228 @@ S multiply(S)(S s, size_t n) if (isSomeString!S)
|
||||||
return cast(S) r;
|
return cast(S) r;
|
||||||
}
|
}
|
||||||
|
|
||||||
ElementType!S[] multiply(S)(S s, size_t n)
|
ElementType!S[] replicate(S)(S s, size_t n)
|
||||||
if (isInputRange!S && !isSomeString!S)
|
if (isInputRange!S && !isSomeString!S)
|
||||||
{
|
{
|
||||||
if (n == 0)
|
return join(std.range.repeat(s, n));
|
||||||
return null;
|
|
||||||
static if (hasLength!S)
|
|
||||||
{
|
|
||||||
auto r = new Unqual!(typeof(s[0]))[n * s.length];
|
|
||||||
if (s.length == 1)
|
|
||||||
r[] = s[0];
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto len = s.length;
|
|
||||||
immutable nlen = n * len;
|
|
||||||
for (size_t i = 0; i < nlen; i += len)
|
|
||||||
{
|
|
||||||
copy(s, r[i .. i + len]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cast(typeof(return)) r;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Appender!(ElementType!S) a;
|
|
||||||
for (; !s.empty; s.popFront())
|
|
||||||
{
|
|
||||||
a.put(s.front);
|
|
||||||
}
|
|
||||||
return a.data;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
debug(string) printf("array.repeat.unittest\n");
|
debug(std_array) printf("array.repeat.unittest\n");
|
||||||
|
|
||||||
foreach (S; TypeTuple!(string, wstring, dstring, char[], wchar[], dchar[]))
|
foreach (S; TypeTuple!(string, wstring, dstring, char[], wchar[], dchar[]))
|
||||||
{
|
{
|
||||||
S s;
|
S s;
|
||||||
|
|
||||||
s = multiply(to!S("1234"), 0);
|
s = replicate(to!S("1234"), 0);
|
||||||
assert(s is null);
|
assert(s is null);
|
||||||
s = multiply(to!S("1234"), 1);
|
s = replicate(to!S("1234"), 1);
|
||||||
assert(cmp(s, "1234") == 0);
|
assert(cmp(s, "1234") == 0);
|
||||||
s = multiply(to!S("1234"), 2);
|
s = replicate(to!S("1234"), 2);
|
||||||
assert(cmp(s, "12341234") == 0);
|
assert(cmp(s, "12341234") == 0);
|
||||||
s = multiply(to!S("1"), 4);
|
s = replicate(to!S("1"), 4);
|
||||||
assert(cmp(s, "1111") == 0);
|
assert(cmp(s, "1111") == 0);
|
||||||
s = multiply(cast(S) null, 4);
|
s = replicate(cast(S) null, 4);
|
||||||
assert(s is null);
|
assert(s is null);
|
||||||
}
|
}
|
||||||
|
|
||||||
int[] a = [ 1, 2, 3 ];
|
int[] a = [ 1, 2, 3 ];
|
||||||
assert(multiply(a, 3) == [1, 2, 3, 1, 2, 3, 1, 2, 3]);
|
assert(replicate(a, 3) == [1, 2, 3, 1, 2, 3, 1, 2, 3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************
|
||||||
|
Split $(D s[]) into an array of words, using whitespace as delimiter.
|
||||||
|
*/
|
||||||
|
|
||||||
|
S[] split(S)(S s) if (isSomeString!S)
|
||||||
|
{
|
||||||
|
size_t istart;
|
||||||
|
bool inword = false;
|
||||||
|
S[] result;
|
||||||
|
|
||||||
|
foreach (i; 0 .. s.length)
|
||||||
|
{
|
||||||
|
switch (s[i])
|
||||||
|
{
|
||||||
|
case ' ': case '\t': case '\f': case '\r': case '\n': case '\v':
|
||||||
|
if (inword)
|
||||||
|
{
|
||||||
|
result ~= s[istart .. i];
|
||||||
|
inword = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (!inword)
|
||||||
|
{
|
||||||
|
istart = i;
|
||||||
|
inword = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (inword)
|
||||||
|
result ~= s[istart .. $];
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
foreach (S; TypeTuple!(string, wstring, dstring))
|
||||||
|
{
|
||||||
|
debug(string) printf("string.split1\n");
|
||||||
|
|
||||||
|
S s = " peter paul\tjerry ";
|
||||||
|
S[] words;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
words = split(s);
|
||||||
|
assert(words.length == 3);
|
||||||
|
i = cmp(words[0], "peter");
|
||||||
|
assert(i == 0);
|
||||||
|
i = cmp(words[1], "paul");
|
||||||
|
assert(i == 0);
|
||||||
|
i = cmp(words[2], "jerry");
|
||||||
|
assert(i == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto splitter(String)(String s) if (isSomeString!String)
|
||||||
|
{
|
||||||
|
return std.algorithm.splitter!isspace(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
auto a = " a bcd ef gh ";
|
||||||
|
assert(equal(splitter(a), ["", "a", "bcd", "ef", "gh"][]));
|
||||||
|
a = "";
|
||||||
|
assert(splitter(a).empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************
|
||||||
|
* Split $(D r) into an array, using $(D delim) as the delimiter.
|
||||||
|
*/
|
||||||
|
Unqual!(S1)[] split(S1, S2)(S1 s, S2 delim)
|
||||||
|
if (isForwardRange!(Unqual!S1) && isForwardRange!S2)
|
||||||
|
{
|
||||||
|
Unqual!S1 us = s;
|
||||||
|
auto app = appender!(Unqual!(S1)[])();
|
||||||
|
foreach (word; std.algorithm.splitter(us, delim))
|
||||||
|
{
|
||||||
|
app.put(word);
|
||||||
|
}
|
||||||
|
return app.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
debug(std_array) printf("array.split\n");
|
||||||
|
foreach (S; TypeTuple!(string, wstring, dstring,
|
||||||
|
immutable(string), immutable(wstring), immutable(dstring),
|
||||||
|
char[], wchar[], dchar[],
|
||||||
|
const(char)[], const(wchar)[], const(dchar)[]))
|
||||||
|
{
|
||||||
|
S s = to!S(",peter,paul,jerry,");
|
||||||
|
int i;
|
||||||
|
|
||||||
|
auto words = split(s, ",");
|
||||||
|
assert(words.length == 5, text(words.length));
|
||||||
|
i = cmp(words[0], "");
|
||||||
|
assert(i == 0);
|
||||||
|
i = cmp(words[1], "peter");
|
||||||
|
assert(i == 0);
|
||||||
|
i = cmp(words[2], "paul");
|
||||||
|
assert(i == 0);
|
||||||
|
i = cmp(words[3], "jerry");
|
||||||
|
assert(i == 0);
|
||||||
|
i = cmp(words[4], "");
|
||||||
|
assert(i == 0);
|
||||||
|
|
||||||
|
auto s1 = s[0 .. s.length - 1]; // lop off trailing ','
|
||||||
|
words = split(s1, ",");
|
||||||
|
assert(words.length == 4);
|
||||||
|
i = cmp(words[3], "jerry");
|
||||||
|
assert(i == 0);
|
||||||
|
|
||||||
|
auto s2 = s1[1 .. s1.length]; // lop off leading ','
|
||||||
|
words = split(s2, ",");
|
||||||
|
assert(words.length == 3);
|
||||||
|
i = cmp(words[0], "peter");
|
||||||
|
assert(i == 0);
|
||||||
|
|
||||||
|
auto s3 = to!S(",,peter,,paul,,jerry,,");
|
||||||
|
|
||||||
|
words = split(s3, ",,");
|
||||||
|
//printf("words.length = %d\n", words.length);
|
||||||
|
assert(words.length == 5);
|
||||||
|
i = cmp(words[0], "");
|
||||||
|
assert(i == 0);
|
||||||
|
i = cmp(words[1], "peter");
|
||||||
|
assert(i == 0);
|
||||||
|
i = cmp(words[2], "paul");
|
||||||
|
assert(i == 0);
|
||||||
|
i = cmp(words[3], "jerry");
|
||||||
|
assert(i == 0);
|
||||||
|
i = cmp(words[4], "");
|
||||||
|
assert(i == 0);
|
||||||
|
|
||||||
|
auto s4 = s3[0 .. s3.length - 2]; // lop off trailing ',,'
|
||||||
|
words = split(s4, ",,");
|
||||||
|
assert(words.length == 4);
|
||||||
|
i = cmp(words[3], "jerry");
|
||||||
|
assert(i == 0);
|
||||||
|
|
||||||
|
auto s5 = s4[2 .. s4.length]; // lop off leading ',,'
|
||||||
|
words = split(s5, ",,");
|
||||||
|
assert(words.length == 3);
|
||||||
|
i = cmp(words[0], "peter");
|
||||||
|
assert(i == 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************
|
/********************************************
|
||||||
* Concatenate all the ranges in $(D ror) together into one array;
|
* Concatenate all the ranges in $(D ror) together into one array;
|
||||||
* use $(D sep) as the separator.
|
* use $(D sep) as the separator if present, otherwise none.
|
||||||
*/
|
*/
|
||||||
|
ElementEncodingType!(ElementType!RoR)[]
|
||||||
ElementType!RoR join(RoR, R)(RoR ror, R sep)
|
join(RoR, R)(RoR ror, R sep)
|
||||||
if (isInputRange!RoR && isInputRange!(typeof(ror.front))
|
if (isInputRange!RoR && isInputRange!(ElementType!RoR) && isForwardRange!R)
|
||||||
&& !(isSomeString!(typeof(ror.front)) && isSomeString!R))
|
|
||||||
{
|
{
|
||||||
return copy(joiner(ror, sep), appender!(ElementType!RoR)()).data;
|
if (ror.empty) return typeof(return).init;
|
||||||
|
auto iter = joiner(ror, sep);
|
||||||
|
static if (isForwardRange!RoR && hasLength!RoR
|
||||||
|
&& (hasLength!(ElementType!RoR) || isSomeString!(ElementType!RoR))
|
||||||
|
&& hasLength!R)
|
||||||
|
{
|
||||||
|
immutable resultLen = reduce!"a + b.length"(cast(size_t) 0, ror.save)
|
||||||
|
+ sep.length * (ror.length - 1);
|
||||||
|
auto result = new ElementEncodingType!(ElementType!RoR)[resultLen];
|
||||||
|
copy(iter, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return copy(iter, appender!(typeof(return))).data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Specialization for strings
|
/// Ditto
|
||||||
typeof(RoR.init[0]) join(RoR, R)(RoR words, R sep)
|
ElementEncodingType!(ElementType!RoR)[] join(RoR)(RoR ror)
|
||||||
if (isSomeString!(typeof(words[0])) && isSomeString!R)
|
if (isInputRange!RoR && isInputRange!(ElementType!RoR))
|
||||||
{
|
{
|
||||||
if (!words.length) return null;
|
auto iter = joiner(ror);
|
||||||
auto sep2 = to!(typeof(return))(sep);
|
static if (hasLength!RoR && hasLength!(ElementType!RoR))
|
||||||
immutable seplen = sep2.length;
|
|
||||||
size_t len = (words.length - 1) * seplen;
|
|
||||||
|
|
||||||
foreach (i; 0 .. words.length)
|
|
||||||
len += words[i].length;
|
|
||||||
|
|
||||||
auto result = new Unqual!(typeof(words.front[0]))[len];
|
|
||||||
|
|
||||||
size_t j;
|
|
||||||
foreach (i; 0 .. words.length)
|
|
||||||
{
|
{
|
||||||
if (i > 0)
|
immutable resultLen = reduce!"a + b.length"(cast(size_t) 0, ror.save);
|
||||||
{
|
auto result = new Unqual!(ElementEncodingType!(ElementType!RoR))[resultLen];
|
||||||
result[j .. j + seplen] = sep2;
|
copy(iter, result);
|
||||||
j += seplen;
|
return cast(typeof(return)) result;
|
||||||
}
|
}
|
||||||
immutable wlen = words[i].length;
|
else
|
||||||
result[j .. j + wlen] = words[i];
|
{
|
||||||
j += wlen;
|
return copy(iter, appender!(typeof(return))).data;
|
||||||
}
|
}
|
||||||
assert(j == len);
|
|
||||||
return cast(typeof(return)) result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
unittest
|
||||||
|
@ -726,6 +802,7 @@ unittest
|
||||||
assert(i == 0, text(i));
|
assert(i == 0, text(i));
|
||||||
|
|
||||||
assert(join([[1, 2], [41, 42]], [5, 6]) == [1, 2, 5, 6, 41, 42]);
|
assert(join([[1, 2], [41, 42]], [5, 6]) == [1, 2, 5, 6, 41, 42]);
|
||||||
|
assert(join([[1, 2], [41, 42]]) == [1, 2, 41, 42]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -734,9 +811,8 @@ Replaces elements from $(D array) with indices ranging from $(D from)
|
||||||
or shrinks the array as needed.
|
or shrinks the array as needed.
|
||||||
*/
|
*/
|
||||||
void replace(T, Range)(ref T[] array, size_t from, size_t to, Range stuff)
|
void replace(T, Range)(ref T[] array, size_t from, size_t to, Range stuff)
|
||||||
if (is(ElementType!Range == T))
|
if (isDynamicArray!Range && is(ElementType!Range : T))
|
||||||
{
|
{
|
||||||
// container = container[0 .. from] ~ stuff ~ container[to .. $];
|
|
||||||
if (overlap(array, stuff))
|
if (overlap(array, stuff))
|
||||||
{
|
{
|
||||||
// use slower/conservative method
|
// use slower/conservative method
|
||||||
|
@ -761,7 +837,6 @@ void replace(T, Range)(ref T[] array, size_t from, size_t to, Range stuff)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void replace(T, Range)(ref T[] array, size_t from, size_t to, Range stuff)
|
void replace(T, Range)(ref T[] array, size_t from, size_t to, Range stuff)
|
||||||
if (!is(ElementType!Range == T) && is(Unqual!Range == void*))
|
if (!is(ElementType!Range == T) && is(Unqual!Range == void*))
|
||||||
{
|
{
|
||||||
|
|
|
@ -31,7 +31,7 @@ Distributed under the Boost Software License, Version 1.0.
|
||||||
*/
|
*/
|
||||||
module std.getopt;
|
module std.getopt;
|
||||||
|
|
||||||
private import std.string, std.conv, std.traits, std.bitmanip,
|
private import std.array, std.string, std.conv, std.traits, std.bitmanip,
|
||||||
std.algorithm, std.ctype, std.exception;
|
std.algorithm, std.ctype, std.exception;
|
||||||
|
|
||||||
version (unittest)
|
version (unittest)
|
||||||
|
|
53
std/range.d
53
std/range.d
|
@ -634,6 +634,34 @@ unittest
|
||||||
static assert(is(ElementType!(typeof(buf)) : void));
|
static assert(is(ElementType!(typeof(buf)) : void));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
The encoding element type of $(D R). For narrow strings ($(D char[]),
|
||||||
|
$(D wchar[]) and their qualified variants including $(D string) and
|
||||||
|
$(D wstring)), $(D ElementEncodingType) is the character type of the
|
||||||
|
string. For all other ranges, $(D ElementEncodingType) is the same as
|
||||||
|
$(D ElementType).
|
||||||
|
*/
|
||||||
|
template ElementEncodingType(R)
|
||||||
|
{
|
||||||
|
static if (isNarrowString!R)
|
||||||
|
alias typeof(R.init[0]) ElementEncodingType;
|
||||||
|
else
|
||||||
|
alias ElementType!R ElementEncodingType;
|
||||||
|
}
|
||||||
|
|
||||||
|
unittest
|
||||||
|
{
|
||||||
|
enum XYZ : string { a = "foo" };
|
||||||
|
auto x = front(XYZ.a);
|
||||||
|
static assert(is(ElementType!(XYZ) : dchar));
|
||||||
|
immutable char[3] a = "abc";
|
||||||
|
static assert(is(ElementType!(typeof(a)) : dchar));
|
||||||
|
int[] i;
|
||||||
|
static assert(is(ElementType!(typeof(i)) : int));
|
||||||
|
void[] buf;
|
||||||
|
static assert(is(ElementType!(typeof(buf)) : void));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Returns $(D true) if $(D R) is a forward range and has swappable
|
Returns $(D true) if $(D R) is a forward range and has swappable
|
||||||
elements. The following code should compile for any random-access
|
elements. The following code should compile for any random-access
|
||||||
|
@ -2122,11 +2150,6 @@ if(isInputRange!(Unqual!Range) &&
|
||||||
public:
|
public:
|
||||||
alias R Source;
|
alias R Source;
|
||||||
|
|
||||||
static if (byRef)
|
|
||||||
alias ref .ElementType!(R) ElementType;
|
|
||||||
else
|
|
||||||
alias .ElementType!(R) ElementType;
|
|
||||||
|
|
||||||
@property bool empty()
|
@property bool empty()
|
||||||
{
|
{
|
||||||
return _maxAvailable == 0 || original.empty;
|
return _maxAvailable == 0 || original.empty;
|
||||||
|
@ -2156,7 +2179,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
static if (hasAssignableElements!R)
|
static if (hasAssignableElements!R)
|
||||||
@property auto front(ElementType v)
|
@property auto front(ElementType!R v)
|
||||||
{
|
{
|
||||||
// This has to return auto instead of void because of Bug 4706.
|
// This has to return auto instead of void because of Bug 4706.
|
||||||
original.front = v;
|
original.front = v;
|
||||||
|
@ -2164,7 +2187,7 @@ public:
|
||||||
|
|
||||||
static if(hasMobileElements!R)
|
static if(hasMobileElements!R)
|
||||||
{
|
{
|
||||||
ElementType moveFront()
|
auto moveFront()
|
||||||
{
|
{
|
||||||
return .moveFront(original);
|
return .moveFront(original);
|
||||||
}
|
}
|
||||||
|
@ -2210,13 +2233,13 @@ public:
|
||||||
|
|
||||||
static if(hasAssignableElements!R)
|
static if(hasAssignableElements!R)
|
||||||
{
|
{
|
||||||
auto back(ElementType v)
|
auto back(ElementType!R v)
|
||||||
{
|
{
|
||||||
// This has to return auto instead of void because of Bug 4706.
|
// This has to return auto instead of void because of Bug 4706.
|
||||||
original[this.length - 1] = v;
|
original[this.length - 1] = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
void opIndexAssign(ElementType v, size_t index)
|
void opIndexAssign(ElementType!R v, size_t index)
|
||||||
{
|
{
|
||||||
original[index] = v;
|
original[index] = v;
|
||||||
}
|
}
|
||||||
|
@ -2224,12 +2247,12 @@ public:
|
||||||
|
|
||||||
static if(hasMobileElements!R)
|
static if(hasMobileElements!R)
|
||||||
{
|
{
|
||||||
ElementType moveBack()
|
auto moveBack()
|
||||||
{
|
{
|
||||||
return .moveAt(original, this.length - 1);
|
return .moveAt(original, this.length - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
ElementType moveAt(size_t index)
|
auto moveAt(size_t index)
|
||||||
{
|
{
|
||||||
assert(index < this.length,
|
assert(index < this.length,
|
||||||
"Attempting to index out of the bounds of a "
|
"Attempting to index out of the bounds of a "
|
||||||
|
@ -2435,9 +2458,9 @@ struct Repeat(T)
|
||||||
{
|
{
|
||||||
private T _value;
|
private T _value;
|
||||||
/// Range primitive implementations.
|
/// Range primitive implementations.
|
||||||
@property ref T front() { return _value; }
|
@property T front() { return _value; }
|
||||||
/// Ditto
|
/// Ditto
|
||||||
@property ref T back() { return _value; }
|
@property T back() { return _value; }
|
||||||
/// Ditto
|
/// Ditto
|
||||||
enum bool empty = false;
|
enum bool empty = false;
|
||||||
/// Ditto
|
/// Ditto
|
||||||
|
@ -2445,9 +2468,9 @@ struct Repeat(T)
|
||||||
/// Ditto
|
/// Ditto
|
||||||
void popBack() {}
|
void popBack() {}
|
||||||
/// Ditto
|
/// Ditto
|
||||||
@property Repeat!(T) save() { return this; }
|
@property Repeat!T save() { return this; }
|
||||||
/// Ditto
|
/// Ditto
|
||||||
ref T opIndex(size_t) { return _value; }
|
T opIndex(size_t) { return _value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ditto
|
/// Ditto
|
||||||
|
|
192
std/string.d
192
std/string.d
|
@ -389,7 +389,7 @@ unittest
|
||||||
* ditto
|
* ditto
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ptrdiff_t lastIndexOf(Char)(const(Char)[] s, dchar c,
|
sizediff_t lastIndexOf(Char)(const(Char)[] s, dchar c,
|
||||||
CaseSensitive cs = CaseSensitive.yes)
|
CaseSensitive cs = CaseSensitive.yes)
|
||||||
{
|
{
|
||||||
if (cs == CaseSensitive.yes)
|
if (cs == CaseSensitive.yes)
|
||||||
|
@ -627,7 +627,7 @@ unittest
|
||||||
* ditto
|
* ditto
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ptrdiff_t lastIndexOf(Char1, Char2)(in Char1[] s, in Char2[] sub,
|
sizediff_t lastIndexOf(Char1, Char2)(in Char1[] s, in Char2[] sub,
|
||||||
CaseSensitive cs = CaseSensitive.yes) if (isSomeChar!Char1 && isSomeChar!Char2)
|
CaseSensitive cs = CaseSensitive.yes) if (isSomeChar!Char1 && isSomeChar!Char2)
|
||||||
{
|
{
|
||||||
if (cs == CaseSensitive.yes)
|
if (cs == CaseSensitive.yes)
|
||||||
|
@ -1088,27 +1088,12 @@ unittest
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************
|
/********************************************
|
||||||
* Return a string that consists of s[] repeated n times.
|
* Repeat $(D s) for $(D n) times. This function is scheduled for
|
||||||
|
* deprecation - use $(XREF array, replicate) instead.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
S repeat(S)(S s, size_t n)
|
S repeat(S)(S s, size_t n)
|
||||||
{
|
{
|
||||||
if (n == 0)
|
return std.array.replicate(s, n);
|
||||||
return S.init;
|
|
||||||
if (n == 1)
|
|
||||||
return s;
|
|
||||||
auto r = new Unqual!(typeof(s[0]))[n * s.length];
|
|
||||||
if (s.length == 1)
|
|
||||||
r[] = s[0];
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto len = s.length;
|
|
||||||
for (size_t i = 0; i < n * len; i += len)
|
|
||||||
{
|
|
||||||
r[i .. i + len] = s[];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cast(S) r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
unittest
|
||||||
|
@ -1137,166 +1122,10 @@ unittest
|
||||||
*/
|
*/
|
||||||
alias std.array.join join;
|
alias std.array.join join;
|
||||||
|
|
||||||
/**************************************
|
/**
|
||||||
Split $(D s[]) into an array of words, using whitespace as delimiter.
|
* Alias for std.array.split
|
||||||
*/
|
*/
|
||||||
|
alias std.array.split split;
|
||||||
S[] split(S)(S s) if (isSomeString!S)
|
|
||||||
{
|
|
||||||
size_t istart;
|
|
||||||
bool inword = false;
|
|
||||||
S[] result;
|
|
||||||
|
|
||||||
foreach (i; 0 .. s.length)
|
|
||||||
{
|
|
||||||
switch (s[i])
|
|
||||||
{
|
|
||||||
case ' ':
|
|
||||||
case '\t':
|
|
||||||
case '\f':
|
|
||||||
case '\r':
|
|
||||||
case '\n':
|
|
||||||
case '\v':
|
|
||||||
if (inword)
|
|
||||||
{
|
|
||||||
result ~= s[istart .. i];
|
|
||||||
inword = false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
if (!inword)
|
|
||||||
{
|
|
||||||
istart = i;
|
|
||||||
inword = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (inword)
|
|
||||||
result ~= s[istart .. $];
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
unittest
|
|
||||||
{
|
|
||||||
foreach (S; TypeTuple!(string, wstring, dstring))
|
|
||||||
{
|
|
||||||
debug(string) printf("string.split1\n");
|
|
||||||
|
|
||||||
S s = " peter paul\tjerry ";
|
|
||||||
S[] words;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
words = split(s);
|
|
||||||
assert(words.length == 3);
|
|
||||||
i = cmp(words[0], "peter");
|
|
||||||
assert(i == 0);
|
|
||||||
i = cmp(words[1], "paul");
|
|
||||||
assert(i == 0);
|
|
||||||
i = cmp(words[2], "jerry");
|
|
||||||
assert(i == 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto splitter(String)(String s) if (isSomeString!String)
|
|
||||||
{
|
|
||||||
//return std.regex.splitter(s, regex("[ \t\n\r]+"));
|
|
||||||
return std.algorithm.splitter!isspace(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
unittest
|
|
||||||
{
|
|
||||||
auto a = " a bcd ef gh ";
|
|
||||||
//foreach (e; splitter(a)) writeln("[", e, "]");
|
|
||||||
assert(equal(splitter(a), ["", "a", "bcd", "ef", "gh"][]));
|
|
||||||
a = "";
|
|
||||||
assert(splitter(a).empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**************************************
|
|
||||||
* Split s[] into an array of words,
|
|
||||||
* using delim[] as the delimiter.
|
|
||||||
*/
|
|
||||||
|
|
||||||
Unqual!(S1)[] split(S1, S2)(S1 s, S2 delim)
|
|
||||||
if (isSomeString!S1 && isSomeString!S2)
|
|
||||||
{
|
|
||||||
Unqual!(S1) us = s;
|
|
||||||
auto app = appender!(Unqual!(S1)[])();
|
|
||||||
foreach (word; std.algorithm.splitter(us, delim))
|
|
||||||
{
|
|
||||||
app.put(word);
|
|
||||||
}
|
|
||||||
return app.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
unittest
|
|
||||||
{
|
|
||||||
debug(string) printf("string.split2\n");
|
|
||||||
foreach (S; TypeTuple!(string, wstring, dstring,
|
|
||||||
immutable(string), immutable(wstring), immutable(dstring),
|
|
||||||
char[], wchar[], dchar[],
|
|
||||||
const(char)[], const(wchar)[], const(dchar)[]))
|
|
||||||
{
|
|
||||||
S s = to!S(",peter,paul,jerry,");
|
|
||||||
int i;
|
|
||||||
|
|
||||||
auto words = split(s, ",");
|
|
||||||
assert(words.length == 5, text(words.length));
|
|
||||||
i = cmp(words[0], "");
|
|
||||||
assert(i == 0);
|
|
||||||
i = cmp(words[1], "peter");
|
|
||||||
assert(i == 0);
|
|
||||||
i = cmp(words[2], "paul");
|
|
||||||
assert(i == 0);
|
|
||||||
i = cmp(words[3], "jerry");
|
|
||||||
assert(i == 0);
|
|
||||||
i = cmp(words[4], "");
|
|
||||||
assert(i == 0);
|
|
||||||
|
|
||||||
auto s1 = s[0 .. s.length - 1]; // lop off trailing ','
|
|
||||||
words = split(s1, ",");
|
|
||||||
assert(words.length == 4);
|
|
||||||
i = cmp(words[3], "jerry");
|
|
||||||
assert(i == 0);
|
|
||||||
|
|
||||||
auto s2 = s1[1 .. s1.length]; // lop off leading ','
|
|
||||||
words = split(s2, ",");
|
|
||||||
assert(words.length == 3);
|
|
||||||
i = cmp(words[0], "peter");
|
|
||||||
assert(i == 0);
|
|
||||||
|
|
||||||
auto s3 = to!S(",,peter,,paul,,jerry,,");
|
|
||||||
|
|
||||||
words = split(s3, ",,");
|
|
||||||
//printf("words.length = %d\n", words.length);
|
|
||||||
assert(words.length == 5);
|
|
||||||
i = cmp(words[0], "");
|
|
||||||
assert(i == 0);
|
|
||||||
i = cmp(words[1], "peter");
|
|
||||||
assert(i == 0);
|
|
||||||
i = cmp(words[2], "paul");
|
|
||||||
assert(i == 0);
|
|
||||||
i = cmp(words[3], "jerry");
|
|
||||||
assert(i == 0);
|
|
||||||
i = cmp(words[4], "");
|
|
||||||
assert(i == 0);
|
|
||||||
|
|
||||||
auto s4 = s3[0 .. s3.length - 2]; // lop off trailing ',,'
|
|
||||||
words = split(s4, ",,");
|
|
||||||
assert(words.length == 4);
|
|
||||||
i = cmp(words[3], "jerry");
|
|
||||||
assert(i == 0);
|
|
||||||
|
|
||||||
auto s5 = s4[2 .. s4.length]; // lop off leading ',,'
|
|
||||||
words = split(s5, ",,");
|
|
||||||
assert(words.length == 3);
|
|
||||||
i = cmp(words[0], "peter");
|
|
||||||
assert(i == 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************
|
/**************************************
|
||||||
* Split s[] into an array of lines,
|
* Split s[] into an array of lines,
|
||||||
|
@ -1674,11 +1503,8 @@ unittest
|
||||||
/***********************************************
|
/***********************************************
|
||||||
* Returns s[] sans trailing character, if there is one.
|
* Returns s[] sans trailing character, if there is one.
|
||||||
* If last two characters are CR-LF, then both are removed.
|
* If last two characters are CR-LF, then both are removed.
|
||||||
*
|
|
||||||
* Deprecated: use s.popBack() instead.
|
|
||||||
*/
|
*/
|
||||||
|
S chop(S)(S s) if (isSomeString!S)
|
||||||
deprecated S chop(S)(S s) if (isSomeString!S)
|
|
||||||
{
|
{
|
||||||
auto len = s.length;
|
auto len = s.length;
|
||||||
if (!len) return s;
|
if (!len) return s;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue