mirror of
https://github.com/dlang/phobos.git
synced 2025-05-04 17:11:26 +03:00
Improvements to replicate(); documented splitter() for strings; renamed replace() in place to replaceInPlace(); removed replace() that takes void* in the last position; moved replace() from string to array and generalized it; attached constraint to functional.not; more cleanup of std.string; improved std.algorithm.util and count to accept ranges; improved constraint in std.algorithm.remove
This commit is contained in:
parent
6c89581e2f
commit
272ceaa9a6
5 changed files with 173 additions and 161 deletions
|
@ -805,10 +805,9 @@ assert(r1 == [ 2.5 ]);
|
||||||
*/
|
*/
|
||||||
template filter(alias pred)
|
template filter(alias pred)
|
||||||
{
|
{
|
||||||
Filter!(unaryFun!(pred), Range)
|
auto filter(Range)(Range rs)
|
||||||
filter(Range)(Range rs)
|
|
||||||
{
|
{
|
||||||
return typeof(return)(rs);
|
return Filter!(unaryFun!(pred), Range)(rs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1790,7 +1789,7 @@ if(!is(isTerminator))
|
||||||
_input.popFront();
|
_input.popFront();
|
||||||
}
|
}
|
||||||
assert(!_input.empty && !_isTerminator(_input.front));
|
assert(!_input.empty && !_isTerminator(_input.front));
|
||||||
// Prime _end
|
// Prepare _end
|
||||||
_end = 1;
|
_end = 1;
|
||||||
while (_end < _input.length && !_isTerminator(_input[_end]))
|
while (_end < _input.length && !_isTerminator(_input[_end]))
|
||||||
{
|
{
|
||||||
|
@ -1967,7 +1966,6 @@ if (isForwardRange!RoR && isInputRange!(ElementType!RoR)
|
||||||
if (!_current.empty) return;
|
if (!_current.empty) return;
|
||||||
useSeparator();
|
useSeparator();
|
||||||
}
|
}
|
||||||
// We need to re-prime the range
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static if (isForwardRange!RoR && isForwardRange!(ElementType!RoR))
|
static if (isForwardRange!RoR && isForwardRange!(ElementType!RoR))
|
||||||
|
@ -2009,7 +2007,7 @@ if (isInputRange!RoR && isInputRange!(ElementType!RoR))
|
||||||
private:
|
private:
|
||||||
RoR _items;
|
RoR _items;
|
||||||
ElementType!RoR _current;
|
ElementType!RoR _current;
|
||||||
void prime()
|
void prepare()
|
||||||
{
|
{
|
||||||
for (;; _items.popFront())
|
for (;; _items.popFront())
|
||||||
{
|
{
|
||||||
|
@ -2023,7 +2021,7 @@ if (isInputRange!RoR && isInputRange!(ElementType!RoR))
|
||||||
this(RoR r)
|
this(RoR r)
|
||||||
{
|
{
|
||||||
_items = r;
|
_items = r;
|
||||||
prime();
|
prepare();
|
||||||
}
|
}
|
||||||
static if (isInfinite!(ElementType!RoR))
|
static if (isInfinite!(ElementType!RoR))
|
||||||
{
|
{
|
||||||
|
@ -2045,7 +2043,7 @@ if (isInputRange!RoR && isInputRange!(ElementType!RoR))
|
||||||
{
|
{
|
||||||
assert(!_current.empty);
|
assert(!_current.empty);
|
||||||
_current.popFront();
|
_current.popFront();
|
||||||
if (_current.empty) prime();
|
if (_current.empty) prepare();
|
||||||
}
|
}
|
||||||
static if (isForwardRange!RoR && isForwardRange!(ElementType!RoR))
|
static if (isForwardRange!RoR && isForwardRange!(ElementType!RoR))
|
||||||
{
|
{
|
||||||
|
@ -2565,7 +2563,7 @@ if (isRandomAccessRange!R1 && isForwardRange!R2 && !isBidirectionalRange!R2
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Prime the search with needle's first element
|
// Prepare the search with needle's first element
|
||||||
if (needle.empty) return haystack;
|
if (needle.empty) return haystack;
|
||||||
haystack = .find!pred(haystack, needle.front);
|
haystack = .find!pred(haystack, needle.front);
|
||||||
if (haystack.empty) return haystack;
|
if (haystack.empty) return haystack;
|
||||||
|
@ -3200,7 +3198,7 @@ struct Until(alias pred, Range, Sentinel) if (isInputRange!Range)
|
||||||
static if (is(Sentinel == void))
|
static if (is(Sentinel == void))
|
||||||
return unaryFun!pred(_input.front);
|
return unaryFun!pred(_input.front);
|
||||||
else
|
else
|
||||||
return binaryFun!pred(_input.front, _sentinel);
|
return startsWith!pred(_input, _sentinel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void popFront()
|
void popFront()
|
||||||
|
@ -3274,6 +3272,7 @@ unittest
|
||||||
static assert(isForwardRange!(typeof(until!"a == 2"(a, OpenRight.no))));
|
static assert(isForwardRange!(typeof(until!"a == 2"(a, OpenRight.no))));
|
||||||
|
|
||||||
assert(equal(a.until(7), [1, 2, 4][]));
|
assert(equal(a.until(7), [1, 2, 4][]));
|
||||||
|
assert(equal(a.until([7, 2]), [1, 2, 4, 7][]));
|
||||||
assert(equal(a.until(7, OpenRight.no), [1, 2, 4, 7][]));
|
assert(equal(a.until(7, OpenRight.no), [1, 2, 4, 7][]));
|
||||||
assert(equal(until!"a == 2"(a, OpenRight.no), [1, 2][]));
|
assert(equal(until!"a == 2"(a, OpenRight.no), [1, 2][]));
|
||||||
}
|
}
|
||||||
|
@ -3736,18 +3735,33 @@ unittest
|
||||||
|
|
||||||
// count
|
// count
|
||||||
/**
|
/**
|
||||||
Counts the number of elements $(D x) in $(D r) for which $(D pred(x,
|
The first version counts the number of elements $(D x) in $(D r) for
|
||||||
value)) is $(D true). $(D pred) defaults to equality. Performs $(BIGOH
|
which $(D pred(x, value)) is $(D true). $(D pred) defaults to
|
||||||
r.length) evaluations of $(D pred).
|
equality. Performs $(BIGOH r.length) evaluations of $(D pred).
|
||||||
|
|
||||||
|
The second version returns the number of times $(D needle) occurs in
|
||||||
|
$(D haystack). Throws an exception if $(D needle.empty), as the _count
|
||||||
|
of the empty range in any range would be infinite. Overlapped counts
|
||||||
|
are not considered, for example $(D count("aaa", "aa")) is $(D 1), not
|
||||||
|
$(D 2).
|
||||||
|
|
||||||
|
The third version counts the elements for which $(D pred(x)) is $(D
|
||||||
|
true). Performs $(BIGOH r.length) evaluations of $(D pred).
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
----
|
----
|
||||||
|
// count elements in range
|
||||||
int[] a = [ 1, 2, 4, 3, 2, 5, 3, 2, 4 ];
|
int[] a = [ 1, 2, 4, 3, 2, 5, 3, 2, 4 ];
|
||||||
assert(count(a, 2) == 3);
|
assert(count(a, 2) == 3);
|
||||||
assert(count!("a > b")(a, 2) == 5);
|
assert(count!("a > b")(a, 2) == 5);
|
||||||
|
// count range in range
|
||||||
|
assert(count("abcadfabf", "ab") == 2);
|
||||||
|
assert(count("ababab", "abab") == 1);
|
||||||
|
assert(count("ababab", "abx") == 0);
|
||||||
|
// count predicate in range
|
||||||
|
assert(count!("a > 1")(a) == 8);
|
||||||
----
|
----
|
||||||
*/
|
*/
|
||||||
|
|
||||||
size_t count(alias pred = "a == b", Range, E)(Range r, E value)
|
size_t count(alias pred = "a == b", Range, E)(Range r, E value)
|
||||||
if (isInputRange!Range && is(typeof(binaryFun!pred(r.front, value)) == bool))
|
if (isInputRange!Range && is(typeof(binaryFun!pred(r.front, value)) == bool))
|
||||||
{
|
{
|
||||||
|
@ -3773,20 +3787,15 @@ unittest
|
||||||
assert(count!("a == '語'")("日本語"d) == 1);
|
assert(count!("a == '語'")("日本語"d) == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
unittest
|
||||||
* Returns the number of times $(D needle) occurs in $(D
|
{
|
||||||
* haystack). Throws an exception if $(D needle.empty), as the _count
|
debug(std_algorithm) printf("algorithm.count.unittest\n");
|
||||||
* of the empty range in any range would be infinite. Overlapped
|
string s = "This is a fofofof list";
|
||||||
* counts are not considered, for example $(D count("aaa", "aa")) is
|
string sub = "fof";
|
||||||
* $(D 1), not $(D 2).
|
assert(count(s, sub) == 2);
|
||||||
*
|
}
|
||||||
* Example:
|
|
||||||
----
|
/// Ditto
|
||||||
assert(count("abcadfabf", "ab") == 2);
|
|
||||||
assert(count("ababab", "abab") == 1);
|
|
||||||
assert(count("ababab", "abx") == 0);
|
|
||||||
----
|
|
||||||
*/
|
|
||||||
size_t count(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle)
|
size_t count(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle)
|
||||||
if (isInputRange!R1 && isForwardRange!R2 && is(typeof(binaryFun!pred(haystack, needle)) == bool))
|
if (isInputRange!R1 && isForwardRange!R2 && is(typeof(binaryFun!pred(haystack, needle)) == bool))
|
||||||
{
|
{
|
||||||
|
@ -3805,16 +3814,7 @@ unittest
|
||||||
assert(count("ababab", "abx") == 0);
|
assert(count("ababab", "abx") == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/// Ditto
|
||||||
Counts the number of elements $(D x) in $(D r) for which $(D pred(x))
|
|
||||||
is $(D true). Performs $(BIGOH r.length) evaluations of $(D pred).
|
|
||||||
|
|
||||||
Example:
|
|
||||||
----
|
|
||||||
int[] a = [ 1, 2, 4, 3, 2, 5, 3, 2, 4 ];
|
|
||||||
assert(count!("a > 1")(a) == 8);
|
|
||||||
----
|
|
||||||
*/
|
|
||||||
size_t count(alias pred = "true", Range)(Range r) if (isInputRange!(Range))
|
size_t count(alias pred = "true", Range)(Range r) if (isInputRange!(Range))
|
||||||
{
|
{
|
||||||
size_t result;
|
size_t result;
|
||||||
|
@ -5045,7 +5045,8 @@ cases.))
|
||||||
Range remove
|
Range remove
|
||||||
(SwapStrategy s = SwapStrategy.stable, Range, Offset...)
|
(SwapStrategy s = SwapStrategy.stable, Range, Offset...)
|
||||||
(Range range, Offset offset)
|
(Range range, Offset offset)
|
||||||
if (isBidirectionalRange!Range && hasLength!Range && s != SwapStrategy.stable)
|
if (isBidirectionalRange!Range && hasLength!Range && s != SwapStrategy.stable
|
||||||
|
&& Offset.length >= 1)
|
||||||
{
|
{
|
||||||
enum bool tupleLeft = is(typeof(offset[0][0]))
|
enum bool tupleLeft = is(typeof(offset[0][0]))
|
||||||
&& is(typeof(offset[0][1]));
|
&& is(typeof(offset[0][1]));
|
||||||
|
@ -5150,8 +5151,9 @@ if (isBidirectionalRange!Range && hasLength!Range && s != SwapStrategy.stable)
|
||||||
Range remove
|
Range remove
|
||||||
(SwapStrategy s = SwapStrategy.stable, Range, Offset...)
|
(SwapStrategy s = SwapStrategy.stable, Range, Offset...)
|
||||||
(Range range, Offset offset)
|
(Range range, Offset offset)
|
||||||
if (isForwardRange!Range && !isBidirectionalRange!Range
|
if ((isForwardRange!Range && !isBidirectionalRange!Range
|
||||||
|| !hasLength!Range || s == SwapStrategy.stable)
|
|| !hasLength!Range || s == SwapStrategy.stable)
|
||||||
|
&& Offset.length >= 1)
|
||||||
{
|
{
|
||||||
auto result = range;
|
auto result = range;
|
||||||
auto src = range, tgt = range;
|
auto src = range, tgt = range;
|
||||||
|
|
147
std/array.d
147
std/array.d
|
@ -5,6 +5,8 @@ Copyright: Copyright Andrei Alexandrescu 2008-.
|
||||||
License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
|
License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
|
||||||
|
|
||||||
Authors: $(WEB erdani.org, Andrei Alexandrescu)
|
Authors: $(WEB erdani.org, Andrei Alexandrescu)
|
||||||
|
|
||||||
|
Functions and types that manipulate built-in arrays.
|
||||||
*/
|
*/
|
||||||
module std.array;
|
module std.array;
|
||||||
|
|
||||||
|
@ -190,12 +192,14 @@ assert(b is a);
|
||||||
Implements the range interface primitive $(D popFront) for built-in
|
Implements the range interface primitive $(D popFront) for built-in
|
||||||
arrays. Due to the fact that nonmember functions can be called with
|
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)). For $(GLOSSARY narrow strings),
|
||||||
|
$(D popFront) automaticaly advances to the next $(GLOSSARY code
|
||||||
|
point).
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
----
|
----
|
||||||
int[] a = [ 1, 2, 3 ];
|
int[] a = [ 1, 2, 3 ];
|
||||||
a.popFront;
|
a.popFront();
|
||||||
assert(a == [ 2, 3 ]);
|
assert(a == [ 2, 3 ]);
|
||||||
----
|
----
|
||||||
*/
|
*/
|
||||||
|
@ -217,6 +221,7 @@ unittest
|
||||||
static assert(!__traits(compiles, popFront!(void[])));
|
static assert(!__traits(compiles, popFront!(void[])));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Specialization for narrow strings
|
||||||
void popFront(A)(ref A a)
|
void popFront(A)(ref A a)
|
||||||
if (isNarrowString!A && isMutable!A)
|
if (isNarrowString!A && isMutable!A)
|
||||||
{
|
{
|
||||||
|
@ -243,7 +248,8 @@ unittest
|
||||||
Implements the range interface primitive $(D popBack) for built-in
|
Implements the range interface primitive $(D popBack) for built-in
|
||||||
arrays. Due to the fact that nonmember functions can be called with
|
arrays. Due to the fact that nonmember functions can be called with
|
||||||
the first argument using the dot notation, $(D array.popBack) is
|
the first argument using the dot notation, $(D array.popBack) is
|
||||||
equivalent to $(D popBack(array)).
|
equivalent to $(D popBack(array)). For $(GLOSSARY narrow strings), $(D
|
||||||
|
popFront) automaticaly eliminates the last $(GLOSSARY code point).
|
||||||
|
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
@ -270,6 +276,7 @@ unittest
|
||||||
static assert(!__traits(compiles, popBack!(void[])));
|
static assert(!__traits(compiles, popBack!(void[])));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Specialization for arrays of char
|
||||||
@trusted 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)
|
||||||
{
|
{
|
||||||
|
@ -311,6 +318,7 @@ unittest
|
||||||
static assert(!__traits(compiles, popBack!(immutable char[])));
|
static assert(!__traits(compiles, popBack!(immutable char[])));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Specialization for arrays of wchar
|
||||||
@trusted 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)
|
||||||
{
|
{
|
||||||
|
@ -338,7 +346,9 @@ unittest
|
||||||
Implements the range interface primitive $(D front) for built-in
|
Implements the range interface primitive $(D front) for built-in
|
||||||
arrays. Due to the fact that nonmember functions can be called with
|
arrays. Due to the fact that nonmember functions can be called with
|
||||||
the first argument using the dot notation, $(D array.front) is
|
the first argument using the dot notation, $(D array.front) is
|
||||||
equivalent to $(D front(array)).
|
equivalent to $(D front(array)). For $(GLOSSARY narrow strings), $(D
|
||||||
|
front) automaticaly returns the first $(GLOSSARY code point) as a $(D
|
||||||
|
dchar).
|
||||||
|
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
@ -373,7 +383,9 @@ unittest
|
||||||
Implements the range interface primitive $(D back) for built-in
|
Implements the range interface primitive $(D back) for built-in
|
||||||
arrays. Due to the fact that nonmember functions can be called with
|
arrays. Due to the fact that nonmember functions can be called with
|
||||||
the first argument using the dot notation, $(D array.back) is
|
the first argument using the dot notation, $(D array.back) is
|
||||||
equivalent to $(D back(array)).
|
equivalent to $(D back(array)). For $(GLOSSARY narrow strings), $(D
|
||||||
|
back) automaticaly returns the last $(GLOSSARY code point) as a $(D
|
||||||
|
dchar).
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
----
|
----
|
||||||
|
@ -381,9 +393,7 @@ int[] a = [ 1, 2, 3 ];
|
||||||
assert(a.back == 3);
|
assert(a.back == 3);
|
||||||
----
|
----
|
||||||
*/
|
*/
|
||||||
ref typeof(A.init[0]) back(A)(A a)
|
ref T back(T)(T[] a) if (!isNarrowString!(T[]))
|
||||||
if (isDynamicArray!A && !isNarrowString!A
|
|
||||||
&& !is(typeof(A.init[0]) : const(void)))
|
|
||||||
{
|
{
|
||||||
assert(a.length, "Attempting to fetch the back of an empty array");
|
assert(a.length, "Attempting to fetch the back of an empty array");
|
||||||
return a[$ - 1];
|
return a[$ - 1];
|
||||||
|
@ -397,36 +407,35 @@ unittest
|
||||||
assert(a.back == 7);
|
assert(a.back == 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Specialization for strings
|
||||||
dchar back(A)(A a)
|
dchar back(A)(A a)
|
||||||
if (isDynamicArray!A && isNarrowString!A)
|
if (isDynamicArray!A && isNarrowString!A)
|
||||||
{
|
{
|
||||||
assert(a.length, "Attempting to fetch the back of an empty array");
|
|
||||||
auto n = a.length;
|
auto n = a.length;
|
||||||
const p = a.ptr + n;
|
const p = a.ptr + n;
|
||||||
if (n >= 1 && (p[-1] & 0b1100_0000) != 0b1000_0000)
|
if (n >= 1 && (p[-1] & 0b1100_0000) != 0b1000_0000)
|
||||||
{
|
{
|
||||||
--n;
|
--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)
|
||||||
{
|
{
|
||||||
n -= 2;
|
n -= 2;
|
||||||
return decode(a, n);
|
|
||||||
}
|
}
|
||||||
else if (n >= 3 && (p[-3] & 0b1100_0000) != 0b1000_0000)
|
else if (n >= 3 && (p[-3] & 0b1100_0000) != 0b1000_0000)
|
||||||
{
|
{
|
||||||
n -= 3;
|
n -= 3;
|
||||||
return decode(a, n);
|
|
||||||
}
|
}
|
||||||
else if (n >= 4 && (p[-4] & 0b1100_0000) != 0b1000_0000)
|
else if (n >= 4 && (p[-4] & 0b1100_0000) != 0b1000_0000)
|
||||||
{
|
{
|
||||||
n -= 4;
|
n -= 4;
|
||||||
return decode(a, n);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new UtfException("Invalid UTF character at end of string");
|
throw new UtfException(a.length
|
||||||
|
? "Invalid UTF character at end of string"
|
||||||
|
: "Attempting to fetch the back of an empty array");
|
||||||
}
|
}
|
||||||
|
return decode(a, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
// overlap
|
// overlap
|
||||||
|
@ -448,8 +457,8 @@ assert(overlap(a, b).empty);
|
||||||
*/
|
*/
|
||||||
T[] overlap(T)(T[] r1, T[] r2) @trusted pure nothrow
|
T[] overlap(T)(T[] r1, T[] r2) @trusted pure nothrow
|
||||||
{
|
{
|
||||||
T* max(T* a, T* b) nothrow { return a > b ? a : b; }
|
static T* max(T* a, T* b) nothrow { return a > b ? a : b; }
|
||||||
T* min(T* a, T* b) nothrow { return a < b ? a : b; }
|
static T* min(T* a, T* b) nothrow { return a < b ? a : b; }
|
||||||
auto b = max(r1.ptr, r2.ptr);
|
auto b = max(r1.ptr, r2.ptr);
|
||||||
auto e = min(r1.ptr + r1.length, r2.ptr + r2.length);
|
auto e = min(r1.ptr + r1.length, r2.ptr + r2.length);
|
||||||
return b < e ? b[0 .. e - b] : null;
|
return b < e ? b[0 .. e - b] : null;
|
||||||
|
@ -471,18 +480,14 @@ unittest
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Inserts $(D stuff) in $(D container) at position $(D pos).
|
Inserts $(D stuff) (which must be an input range or a single item) in
|
||||||
|
$(D array) 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(ElementEncodingType!Range : T))
|
if (isInputRange!Range && is(ElementEncodingType!Range : T))
|
||||||
{
|
{
|
||||||
static if (hasLength!Range)
|
static if (hasLength!Range)
|
||||||
{
|
{
|
||||||
// @@@BUG 2130@@@
|
|
||||||
// immutable
|
|
||||||
// size_t delta = toInsert.length,
|
|
||||||
// size_t oldLength = array.length,
|
|
||||||
// size_t newLength = oldLength + delta;
|
|
||||||
immutable
|
immutable
|
||||||
delta = stuff.length,
|
delta = stuff.length,
|
||||||
oldLength = array.length,
|
oldLength = array.length,
|
||||||
|
@ -535,10 +540,12 @@ pure bool sameHead(T)(in T[] lhs, in T[] rhs)
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************
|
/********************************************
|
||||||
* Return an array that consists of $(D s) (which must be an input
|
Returns an array that consists of $(D s) (which must be an input
|
||||||
* range) repeated $(D n) times.
|
range) repeated $(D n) times. This function allocates, fills, and
|
||||||
|
returns a new array. For a lazy version, refer to $(XREF
|
||||||
|
range,repeat).
|
||||||
*/
|
*/
|
||||||
S replicate(S)(S s, size_t n) if (isSomeString!S)
|
S replicate(S)(S s, size_t n) if (isDynamicArray!S)
|
||||||
{
|
{
|
||||||
// Optimization for return join(std.range.repeat(s, n));
|
// Optimization for return join(std.range.repeat(s, n));
|
||||||
if (n == 0)
|
if (n == 0)
|
||||||
|
@ -550,8 +557,8 @@ S replicate(S)(S s, size_t n) if (isSomeString!S)
|
||||||
r[] = s[0];
|
r[] = s[0];
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto len = s.length;
|
immutable len = s.length, nlen = n * len;
|
||||||
for (size_t i = 0; i < n * len; i += len)
|
for (size_t i = 0; i < nlen; i += len)
|
||||||
{
|
{
|
||||||
r[i .. i + len] = s[];
|
r[i .. i + len] = s[];
|
||||||
}
|
}
|
||||||
|
@ -560,7 +567,7 @@ S replicate(S)(S s, size_t n) if (isSomeString!S)
|
||||||
}
|
}
|
||||||
|
|
||||||
ElementType!S[] replicate(S)(S s, size_t n)
|
ElementType!S[] replicate(S)(S s, size_t n)
|
||||||
if (isInputRange!S && !isSomeString!S)
|
if (isInputRange!S && !isDynamicArray!S)
|
||||||
{
|
{
|
||||||
return join(std.range.repeat(s, n));
|
return join(std.range.repeat(s, n));
|
||||||
}
|
}
|
||||||
|
@ -590,7 +597,9 @@ unittest
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************************************
|
/**************************************
|
||||||
Split $(D s[]) into an array of words, using whitespace as delimiter.
|
Split the string $(D s) into an array of words, using whitespace as
|
||||||
|
delimiter. Runs of whitespace are merged together (no empty words are
|
||||||
|
produced).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
S[] split(S)(S s) if (isSomeString!S)
|
S[] split(S)(S s) if (isSomeString!S)
|
||||||
|
@ -629,22 +638,21 @@ unittest
|
||||||
foreach (S; TypeTuple!(string, wstring, dstring))
|
foreach (S; TypeTuple!(string, wstring, dstring))
|
||||||
{
|
{
|
||||||
debug(string) printf("string.split1\n");
|
debug(string) printf("string.split1\n");
|
||||||
|
S s = " \t\npeter paul\tjerry \n";
|
||||||
S s = " peter paul\tjerry ";
|
assert(equal(split(s), [ to!S("peter"), to!S("paul"), to!S("jerry") ]));
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Splits a string by whitespace.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
----
|
||||||
|
auto a = " a bcd ef gh ";
|
||||||
|
assert(equal(splitter(a), ["", "a", "bcd", "ef", "gh"][]));
|
||||||
|
----
|
||||||
|
*/
|
||||||
auto splitter(String)(String s) if (isSomeString!String)
|
auto splitter(String)(String s) if (isSomeString!String)
|
||||||
{
|
{
|
||||||
return std.algorithm.splitter!isspace(s);
|
return std.algorithm.splitter!isspace(s);
|
||||||
|
@ -659,7 +667,7 @@ unittest
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************************************
|
/**************************************
|
||||||
* Split $(D r) into an array, using $(D delim) as the delimiter.
|
* Splits $(D s) into an array, using $(D delim) as the delimiter.
|
||||||
*/
|
*/
|
||||||
Unqual!(S1)[] split(S1, S2)(S1 s, S2 delim)
|
Unqual!(S1)[] split(S1, S2)(S1 s, S2 delim)
|
||||||
if (isForwardRange!(Unqual!S1) && isForwardRange!S2)
|
if (isForwardRange!(Unqual!S1) && isForwardRange!S2)
|
||||||
|
@ -810,7 +818,7 @@ Replaces elements from $(D array) with indices ranging from $(D from)
|
||||||
(inclusive) to $(D to) (exclusive) with the range $(D stuff). Expands
|
(inclusive) to $(D to) (exclusive) with the range $(D stuff). Expands
|
||||||
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 replaceInPlace(T, Range)(ref T[] array, size_t from, size_t to, Range stuff)
|
||||||
if (isDynamicArray!Range && is(ElementType!Range : T))
|
if (isDynamicArray!Range && is(ElementType!Range : T))
|
||||||
{
|
{
|
||||||
if (overlap(array, stuff))
|
if (overlap(array, stuff))
|
||||||
|
@ -837,52 +845,45 @@ if (isDynamicArray!Range && is(ElementType!Range : T))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void replace(T, Range)(ref T[] array, size_t from, size_t to, Range stuff)
|
|
||||||
if (!is(ElementType!Range == T) && is(Unqual!Range == void*))
|
|
||||||
{
|
|
||||||
replace(array, from, to, cast(T[])[]);
|
|
||||||
}
|
|
||||||
|
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
int[] a = [1, 4, 5];
|
int[] a = [1, 4, 5];
|
||||||
replace(a, 1u, 2u, [2, 3, 4]);
|
replaceInPlace(a, 1u, 2u, [2, 3, 4]);
|
||||||
assert(a == [1, 2, 3, 4, 5]);
|
assert(a == [1, 2, 3, 4, 5]);
|
||||||
replace(a, 1u, 2u, cast(int[])[]);
|
replaceInPlace(a, 1u, 2u, cast(int[])[]);
|
||||||
assert(a == [1, 3, 4, 5]);
|
assert(a == [1, 3, 4, 5]);
|
||||||
replace(a, 1u, 2u, null);
|
|
||||||
assert(a == [1, 4, 5]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************
|
/********************************************
|
||||||
* Replace occurrences of from[] with to[] in s[].
|
* Replace occurrences of $(D from) with $(D to) in $(D a). Returns a
|
||||||
|
* new array.
|
||||||
*/
|
*/
|
||||||
C1[] replace(C1, C2, C3)(C1[] s, C2[] from, C3[] to)
|
R1 replace(R1, R2, R3)(R1 subject, R2 from, R3 to)
|
||||||
//if (is(typeof(s[0] == from[0])) && is(typeof(to[0]) : C1))
|
if (isDynamicArray!R1 && isForwardRange!R2 && isForwardRange!R3)
|
||||||
{
|
{
|
||||||
if (from.length == 0) return s;
|
if (from.empty) return subject;
|
||||||
typeof(s.dup) p;
|
auto app = appender!R1();
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
auto s1 = std.algorithm.find(s, from);
|
auto balance = std.algorithm.find(subject, from.save);
|
||||||
if (!s1.length)
|
if (balance.empty)
|
||||||
{
|
{
|
||||||
if (p is null) return s;
|
if (app.data.empty) return subject;
|
||||||
p ~= s;
|
app.put(subject);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
p ~= s[0 .. s.length - s1.length];
|
app.put(subject[0 .. subject.length - balance.length]);
|
||||||
p ~= to;
|
app.put(to.save);
|
||||||
s = s1[from.length .. $];
|
subject = balance[from.length .. $];
|
||||||
}
|
}
|
||||||
|
|
||||||
return cast(C1[]) p;
|
return app.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
unittest
|
||||||
{
|
{
|
||||||
debug(string) printf("string.replace.unittest\n");
|
debug(string) printf("array.replace.unittest\n");
|
||||||
|
|
||||||
alias TypeTuple!(string, wstring, dstring, char[], wchar[], dchar[])
|
alias TypeTuple!(string, wstring, dstring, char[], wchar[], dchar[])
|
||||||
TestTypes;
|
TestTypes;
|
||||||
|
@ -908,8 +909,8 @@ unittest
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************
|
/*****************************
|
||||||
* Return an array that is $(D s[]) with $(D slice[]) replaced by $(D
|
Return an array that is $(D s) with $(D slice) replaced by $(D
|
||||||
* replacement[]).
|
replacement[]).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
T[] replaceSlice(T)(T[] s, in T[] slice, in T[] replacement)
|
T[] replaceSlice(T)(T[] s, in T[] slice, in T[] replacement)
|
||||||
|
@ -1020,7 +1021,8 @@ done.
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// didn't work, must reallocate
|
// didn't work, must reallocate
|
||||||
auto bi = GC.qalloc(newCapacity * T.sizeof, (typeid(T[]).next.flags & 1) ? 0 : GC.BlkAttr.NO_SCAN);
|
auto bi = GC.qalloc(newCapacity * T.sizeof,
|
||||||
|
(typeid(T[]).next.flags & 1) ? 0 : GC.BlkAttr.NO_SCAN);
|
||||||
_data.capacity = bi.size / T.sizeof;
|
_data.capacity = bi.size / T.sizeof;
|
||||||
if(len)
|
if(len)
|
||||||
memcpy(bi.base, _data.arr.ptr, len * T.sizeof);
|
memcpy(bi.base, _data.arr.ptr, len * T.sizeof);
|
||||||
|
@ -1071,7 +1073,8 @@ Returns the managed array.
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// didn't work, must reallocate
|
// didn't work, must reallocate
|
||||||
auto bi = GC.qalloc(newlen * T.sizeof, (typeid(T[]).next.flags & 1) ? 0 : GC.BlkAttr.NO_SCAN);
|
auto bi = GC.qalloc(newlen * T.sizeof,
|
||||||
|
(typeid(T[]).next.flags & 1) ? 0 : GC.BlkAttr.NO_SCAN);
|
||||||
_data.capacity = bi.size / T.sizeof;
|
_data.capacity = bi.size / T.sizeof;
|
||||||
if(len)
|
if(len)
|
||||||
memcpy(bi.base, _data.arr.ptr, len * T.sizeof);
|
memcpy(bi.base, _data.arr.ptr, len * T.sizeof);
|
||||||
|
|
|
@ -278,9 +278,9 @@ string a = " Hello, world!";
|
||||||
assert(find!(not!isspace)(a) == "Hello, world!");
|
assert(find!(not!isspace)(a) == "Hello, world!");
|
||||||
----
|
----
|
||||||
*/
|
*/
|
||||||
template not(alias pred)
|
template not(alias pred) if (is(typeof(!unaryFun!pred(args))))
|
||||||
{
|
{
|
||||||
bool not(T...)(T args) { return !pred(args); }
|
auto not(T...)(T args) { return !binaryFun!pred(args); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -80,7 +80,7 @@ version(Posix)
|
||||||
|
|
||||||
version (Windows) alias std.string.icmp fcmp;
|
version (Windows) alias std.string.icmp fcmp;
|
||||||
|
|
||||||
version (Posix) alias std.string.cmp fcmp;
|
version (Posix) alias std.algorithm.cmp fcmp;
|
||||||
|
|
||||||
/**************************
|
/**************************
|
||||||
* Extracts the extension from a filename or path.
|
* Extracts the extension from a filename or path.
|
||||||
|
|
85
std/string.d
85
std/string.d
|
@ -8,31 +8,62 @@
|
||||||
are preferable because they don't exhibit undesired aliasing, thus
|
are preferable because they don't exhibit undesired aliasing, thus
|
||||||
making code more robust.
|
making code more robust.
|
||||||
|
|
||||||
Macros:
|
Macros: WIKI = Phobos/StdString
|
||||||
WIKI = Phobos/StdString
|
|
||||||
|
Copyright: Copyright Digital Mars 2007-.
|
||||||
|
|
||||||
|
License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
|
||||||
|
|
||||||
|
Authors: $(WEB digitalmars.com, Walter Bright), $(WEB erdani.org,
|
||||||
|
Andrei Alexandrescu)
|
||||||
|
|
||||||
|
$(B $(RED IMPORTANT NOTE:)) Beginning with version 2.052, the
|
||||||
|
following symbols have been generalized beyond strings and moved to
|
||||||
|
different modules. This action was prompted by the fact that
|
||||||
|
generalized routines belong better in other places, although they
|
||||||
|
still work for strings as expected. In order to use moved symbols, you
|
||||||
|
will need to import the respective modules as follows:
|
||||||
|
|
||||||
|
$(BOOKTABLE ,
|
||||||
|
|
||||||
|
$(TR $(TH Symbol) $(TH Comment))
|
||||||
|
|
||||||
|
$(TR $(TD $(D cmp)) $(TD Moved to $(XREF algorithm, cmp) and
|
||||||
|
generalized to work for all input ranges and accept a custom
|
||||||
|
predicate.))
|
||||||
|
|
||||||
|
$(TR $(TD $(D count)) $(TD Moved to $(XREF algorithm, count) and
|
||||||
|
generalized to accept a custom predicate.))
|
||||||
|
|
||||||
|
$(TR $(TD $(D replace)) $(TD Moved to $(XREF array, replace).))
|
||||||
|
|
||||||
|
$(TR $(TD $(D ByCodeUnit)) $(TD Removed.))
|
||||||
|
|
||||||
|
$(TR $(TD $(D insert)) $(TD Use $(XREF array, insert) instead.))
|
||||||
|
|
||||||
|
$(TR $(TD $(D join)) $(TD Use $(XREF array, join) instead.))
|
||||||
|
|
||||||
|
$(TR $(TD $(D repeat)) $(TD Use $(XREF array, replicate) instead.))
|
||||||
|
|
||||||
|
$(TR $(TD $(D replace)) $(TD Use $(XREF array, replace) instead.))
|
||||||
|
|
||||||
|
$(TR $(TD $(D replaceSlice)) $(TD Use $(XREF array, replace) instead.))
|
||||||
|
|
||||||
|
$(TR $(TD $(D split)) $(TD Use $(XREF array, split) instead.))
|
||||||
|
)
|
||||||
|
|
||||||
Copyright: Copyright Digital Mars 2007 - 2009.
|
|
||||||
License: <a href="http: //www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>.
|
|
||||||
Authors: $(WEB digitalmars.com, Walter Bright),
|
|
||||||
$(WEB erdani.org, Andrei Alexandrescu)
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
Copyright Digital Mars 2007 - 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.string;
|
module std.string;
|
||||||
|
|
||||||
//debug=string; // uncomment to turn on debugging printf's
|
//debug=string; // uncomment to turn on debugging printf's
|
||||||
|
|
||||||
private import core.exception : onRangeError;
|
import core.exception : onRangeError;
|
||||||
import core.vararg, core.stdc.stdio, core.stdc.stdlib,
|
import core.vararg, core.stdc.stdio, core.stdc.stdlib,
|
||||||
core.stdc.string, std.algorithm,
|
core.stdc.string/*, std.algorithm*/,
|
||||||
std.conv, std.ctype, std.encoding, std.exception, std.format,
|
std.conv, std.ctype, std.encoding, std.exception, std.format,
|
||||||
std.functional, std.metastrings, std.range, std.regex, std.stdio,
|
std.functional, std.metastrings, std.range, std.regex, std.stdio,
|
||||||
std.traits, std.typetuple, std.uni, std.utf;
|
std.traits, std.typetuple, std.uni, std.utf;
|
||||||
public import std.algorithm : startsWith, endsWith;
|
public import std.algorithm : startsWith, endsWith, cmp, count;
|
||||||
public import std.array : join, split;
|
public import std.array : join, split;
|
||||||
|
|
||||||
version(Windows) extern (C)
|
version(Windows) extern (C)
|
||||||
|
@ -95,12 +126,6 @@ $(TR $(TD $(D > 0)) $(TD $(D s1 > s2)))
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
alias std.algorithm.cmp cmp;
|
|
||||||
|
|
||||||
/*********************************
|
|
||||||
* ditto
|
|
||||||
*/
|
|
||||||
|
|
||||||
int icmp(alias pred = "a < b", S1, S2)(S1 s1, S2 s2)
|
int icmp(alias pred = "a < b", S1, S2)(S1 s1, S2 s2)
|
||||||
if (is(Unqual!(ElementType!S1) == dchar) && is(Unqual!(ElementType!S2) == dchar))
|
if (is(Unqual!(ElementType!S1) == dchar) && is(Unqual!(ElementType!S2) == dchar))
|
||||||
{
|
{
|
||||||
|
@ -1557,24 +1582,6 @@ unittest
|
||||||
assert(i == 0);
|
assert(i == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************
|
|
||||||
* Count up all instances of sub[] in s[].
|
|
||||||
*/
|
|
||||||
|
|
||||||
alias std.algorithm.count count;
|
|
||||||
|
|
||||||
unittest
|
|
||||||
{
|
|
||||||
debug(string) printf("string.count.unittest\n");
|
|
||||||
|
|
||||||
string s = "This is a fofofof list";
|
|
||||||
string sub = "fof";
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
i = count(s, sub);
|
|
||||||
assert(i == 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/************************************************
|
/************************************************
|
||||||
* Replace tabs with the appropriate number of spaces.
|
* Replace tabs with the appropriate number of spaces.
|
||||||
* tabsize is the distance between tab stops.
|
* tabsize is the distance between tab stops.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue