mirror of
https://github.com/dlang/phobos.git
synced 2025-04-29 22:50:38 +03:00
Moved join from std.string to std.array, plus a few cosmetic changes
This commit is contained in:
parent
a0ecf2a10e
commit
cf33c1999a
4 changed files with 175 additions and 191 deletions
|
@ -1853,10 +1853,18 @@ unittest
|
|||
|
||||
// joiner
|
||||
/**
|
||||
Lazily joins a range of ranges with a separator. The range of ranges
|
||||
Lazily joins a range of ranges with a separator. The separator itself
|
||||
is a range.
|
||||
|
||||
Example:
|
||||
----
|
||||
assert(equal(joiner([""], "xyz"), ""));
|
||||
assert(equal(joiner(["", ""], "xyz"), "xyz"));
|
||||
assert(equal(joiner(["", "abc"], "xyz"), "xyzabc"));
|
||||
assert(equal(joiner(["abc", ""], "xyz"), "abcxyz"));
|
||||
assert(equal(joiner(["abc", "def"], "xyz"), "abcxyzdef"));
|
||||
assert(equal(joiner(["Mary", "has", "a", "little", "lamb"], "..."),
|
||||
"Mary...has...a...little...lamb"));
|
||||
----
|
||||
*/
|
||||
auto joiner(Range, Separator)(Range r, Separator sep)
|
||||
|
|
216
std/array.d
216
std/array.d
|
@ -19,7 +19,7 @@ import std.algorithm, std.conv, std.encoding, std.exception, std.range,
|
|||
std.string, std.traits, std.typecons, std.utf;
|
||||
private import std.c.string : memcpy;
|
||||
private import std.intrinsic : bsr;
|
||||
version(unittest) private import std.stdio;
|
||||
version(unittest) private import std.stdio, std.typetuple;
|
||||
|
||||
/**
|
||||
Returns a newly-allocated dynamic array consisting of a copy of the input
|
||||
|
@ -77,39 +77,6 @@ if (isIterable!Range && !isNarrowString!Range)
|
|||
}
|
||||
return a.data;
|
||||
}
|
||||
// // 2. Initialize the memory
|
||||
// size_t constructedElements = 0;
|
||||
// scope(failure)
|
||||
// {
|
||||
// // Deconstruct only what was constructed
|
||||
// foreach_reverse (i; 0 .. constructedElements)
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// //result[i].~E();
|
||||
// }
|
||||
// catch (Exception e)
|
||||
// {
|
||||
// }
|
||||
// }
|
||||
// // free the entire array
|
||||
// std.gc.realloc(result, 0);
|
||||
// }
|
||||
// foreach (src; elements)
|
||||
// {
|
||||
// static if (is(typeof(new(result + constructedElements) E(src))))
|
||||
// {
|
||||
// new(result + constructedElements) E(src);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// result[constructedElements] = src;
|
||||
// }
|
||||
// ++constructedElements;
|
||||
// }
|
||||
// // 3. Success constructing all elements, type the array and return it
|
||||
// setTypeInfo(typeid(E), result);
|
||||
// return result[0 .. constructedElements];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -195,17 +162,6 @@ unittest
|
|||
assert(array("ABC".dup) == "ABC"d.dup);
|
||||
}
|
||||
|
||||
template IndexType(C : T[], T)
|
||||
{
|
||||
alias size_t IndexType;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
static assert(is(IndexType!(double[]) == size_t));
|
||||
static assert(!is(IndexType!(double) == size_t));
|
||||
}
|
||||
|
||||
/**
|
||||
Implements the range interface primitive $(D empty) for built-in
|
||||
arrays. Due to the fact that nonmember functions can be called with
|
||||
|
@ -628,41 +584,149 @@ bool sameHead(T)(in T[] lhs, in T[] rhs)
|
|||
return lhs.ptr == rhs.ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
Erases elements from $(D array) with indices ranging from $(D from)
|
||||
(inclusive) to $(D to) (exclusive).
|
||||
/********************************************
|
||||
* Return an array that consists of $(D s) (which must be an input
|
||||
* range) repeated $(D n) times.
|
||||
*/
|
||||
// void erase(T)(ref T[] array, size_t from, size_t to)
|
||||
// {
|
||||
// immutable newLength = array.length - (to - from);
|
||||
// foreach (i; to .. array.length)
|
||||
// {
|
||||
// move(array[i], array[from++]);
|
||||
// }
|
||||
// array.length = newLength;
|
||||
// }
|
||||
|
||||
// unittest
|
||||
// {
|
||||
// int[] a = [1, 2, 3, 4, 5];
|
||||
// erase(a, 1u, 3u);
|
||||
// assert(a == [1, 4, 5]);
|
||||
// }
|
||||
S multiply(S)(S s, size_t n) if (isSomeString!S)
|
||||
{
|
||||
if (n == 0)
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
Erases element from $(D array) at index $(D from).
|
||||
ElementType!S[] multiply(S)(S s, size_t n)
|
||||
if (isInputRange!S && !isSomeString!S)
|
||||
{
|
||||
if (n == 0)
|
||||
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
|
||||
{
|
||||
debug(string) printf("array.repeat.unittest\n");
|
||||
|
||||
foreach (S; TypeTuple!(string, wstring, dstring, char[], wchar[], dchar[]))
|
||||
{
|
||||
S s;
|
||||
|
||||
s = multiply(to!S("1234"), 0);
|
||||
assert(s is null);
|
||||
s = multiply(to!S("1234"), 1);
|
||||
assert(cmp(s, "1234") == 0);
|
||||
s = multiply(to!S("1234"), 2);
|
||||
assert(cmp(s, "12341234") == 0);
|
||||
s = multiply(to!S("1"), 4);
|
||||
assert(cmp(s, "1111") == 0);
|
||||
s = multiply(cast(S) null, 4);
|
||||
assert(s is null);
|
||||
}
|
||||
|
||||
int[] a = [ 1, 2, 3 ];
|
||||
assert(multiply(a, 3) == [1, 2, 3, 1, 2, 3, 1, 2, 3]);
|
||||
}
|
||||
|
||||
/********************************************
|
||||
* Concatenate all the ranges in $(D ror) together into one array;
|
||||
* use $(D sep) as the separator.
|
||||
*/
|
||||
// void erase(T)(ref T[] array, size_t from)
|
||||
// {
|
||||
// erase(array, from, from + 1);
|
||||
// }
|
||||
|
||||
// unittest
|
||||
// {
|
||||
// int[] a = [1, 2, 3, 4, 5];
|
||||
// erase(a, 2u);
|
||||
// assert(a == [1, 2, 4, 5]);
|
||||
// }
|
||||
ElementType!RoR join(RoR, R)(RoR ror, R sep)
|
||||
if (isInputRange!RoR && isInputRange!(typeof(ror.front))
|
||||
&& !(isSomeString!(typeof(ror.front)) && isSomeString!R))
|
||||
{
|
||||
return copy(joiner(ror, sep), appender!(ElementType!RoR)()).data;
|
||||
}
|
||||
|
||||
// Specialization for strings
|
||||
typeof(RoR.init[0]) join(RoR, R)(RoR words, R sep)
|
||||
if (isSomeString!(typeof(words[0])) && isSomeString!R)
|
||||
{
|
||||
if (!words.length) return null;
|
||||
auto sep2 = to!(typeof(return))(sep);
|
||||
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)
|
||||
{
|
||||
result[j .. j + seplen] = sep2;
|
||||
j += seplen;
|
||||
}
|
||||
immutable wlen = words[i].length;
|
||||
result[j .. j + wlen] = words[i];
|
||||
j += wlen;
|
||||
}
|
||||
assert(j == len);
|
||||
return cast(typeof(return)) result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(std_array) printf("array.join.unittest\n");
|
||||
|
||||
string word1 = "peter";
|
||||
string word2 = "paul";
|
||||
string word3 = "jerry";
|
||||
string[3] words;
|
||||
string r;
|
||||
int i;
|
||||
|
||||
words[0] = word1;
|
||||
words[1] = word2;
|
||||
words[2] = word3;
|
||||
r = join(words[], ",");
|
||||
i = cmp(r, "peter,paul,jerry");
|
||||
assert(i == 0, text(i));
|
||||
|
||||
assert(join([[1, 2], [41, 42]], [5, 6]) == [1, 2, 5, 6, 41, 42]);
|
||||
}
|
||||
|
||||
/**
|
||||
Replaces elements from $(D array) with indices ranging from $(D from)
|
||||
|
@ -704,8 +768,6 @@ void replace(T, Range)(ref T[] array, size_t from, size_t to, Range stuff)
|
|||
replace(array, from, to, cast(T[])[]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
unittest
|
||||
{
|
||||
int[] a = [1, 4, 5];
|
||||
|
|
27
std/range.d
27
std/range.d
|
@ -2460,17 +2460,23 @@ unittest
|
|||
}
|
||||
|
||||
/**
|
||||
Replicates $(D value) exactly $(D n) times. Equivalent to $(D
|
||||
Repeats $(D value) exactly $(D n) times. Equivalent to $(D
|
||||
take(repeat(value), n)).
|
||||
*/
|
||||
Take!(Repeat!(T)) replicate(T)(T value, size_t n)
|
||||
Take!(Repeat!T) repeat(T)(T value, size_t n)
|
||||
{
|
||||
return take(repeat(value), n);
|
||||
}
|
||||
|
||||
/// Equivalent to $(D repeat(value, n)). Scheduled for deprecation.
|
||||
Take!(Repeat!T) replicate(T)(T value, size_t n)
|
||||
{
|
||||
return repeat(value, n);
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
enforce(equal(replicate(5, 4), [ 5, 5, 5, 5 ][]));
|
||||
enforce(equal(repeat(5, 4), [ 5, 5, 5, 5 ][]));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2559,24 +2565,23 @@ if (isForwardRange!(Unqual!Range) && !isInfinite!(Unqual!Range))
|
|||
if (_current.empty) _current = _original;
|
||||
}
|
||||
|
||||
@property Cycle!(R) save() {
|
||||
Cycle!(R) ret;
|
||||
@property Cycle!R save() {
|
||||
Cycle!R ret;
|
||||
ret._original = this._original.save;
|
||||
ret._current = this._current.save;
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// Ditto
|
||||
template Cycle(R) if(isInfinite!(R))
|
||||
template Cycle(R) if (isInfinite!R)
|
||||
{
|
||||
alias R Cycle;
|
||||
}
|
||||
|
||||
/// Ditto
|
||||
struct Cycle(R) if (isStaticArray!(R))
|
||||
struct Cycle(R) if (isStaticArray!R)
|
||||
{
|
||||
private alias typeof(R[0]) ElementType;
|
||||
private ElementType* _ptr;
|
||||
|
@ -2607,17 +2612,17 @@ struct Cycle(R) if (isStaticArray!(R))
|
|||
}
|
||||
|
||||
/// Ditto
|
||||
Cycle!(R) cycle(R)(R input)
|
||||
Cycle!R cycle(R)(R input)
|
||||
if (isForwardRange!(Unqual!R) && !isInfinite!(Unqual!R))
|
||||
{
|
||||
return Cycle!(R)(input);
|
||||
}
|
||||
|
||||
/// Ditto
|
||||
Cycle!(R) cycle(R)(R input, size_t index)
|
||||
Cycle!R cycle(R)(R input, size_t index)
|
||||
if (isRandomAccessRange!(Unqual!R) && !isInfinite!(Unqual!R))
|
||||
{
|
||||
return Cycle!(R)(input, index);
|
||||
return Cycle!R(input, index);
|
||||
}
|
||||
|
||||
/// Ditto
|
||||
|
|
109
std/string.d
109
std/string.d
|
@ -172,7 +172,8 @@ unittest
|
|||
|
||||
/*********************************
|
||||
* Convert array of chars $(D s[]) to a C-style 0-terminated string.
|
||||
* $(D s[]) must not contain embedded 0's.
|
||||
* $(D s[]) must not contain embedded 0's. If $(D s) is $(D null) or
|
||||
* empty, a string containing only $(D '\0') is returned.
|
||||
*/
|
||||
|
||||
immutable(char)* toStringz(const(char)[] s)
|
||||
|
@ -194,8 +195,6 @@ out (result)
|
|||
}
|
||||
body
|
||||
{
|
||||
char[] copy;
|
||||
|
||||
/+ Unfortunately, this isn't reliable.
|
||||
We could make this work if string literals are put
|
||||
in read-only memory and we test if s[] is pointing into
|
||||
|
@ -212,7 +211,7 @@ body
|
|||
+/
|
||||
|
||||
// Need to make a copy
|
||||
copy = new char[s.length + 1];
|
||||
auto copy = new char[s.length + 1];
|
||||
copy[0..s.length] = s;
|
||||
copy[s.length] = 0;
|
||||
|
||||
|
@ -222,7 +221,7 @@ body
|
|||
/// Ditto
|
||||
immutable(char)* toStringz(string s)
|
||||
{
|
||||
if (!s) return null;
|
||||
if (s.empty) return "".ptr;
|
||||
/* Peek past end of s[], if it's 0, no conversion necessary.
|
||||
* Note that the compiler will put a 0 past the end of static
|
||||
* strings, and the storage allocator will put a 0 past the end
|
||||
|
@ -359,12 +358,10 @@ unittest
|
|||
{
|
||||
debug(string) printf("string.indexOf.unittest\n");
|
||||
|
||||
sizediff_t i;
|
||||
|
||||
foreach (S; TypeTuple!(string, wstring, dstring))
|
||||
{
|
||||
S s = null;
|
||||
i = indexOf(s, cast(dchar)'a', CaseSensitive.no);
|
||||
auto i = indexOf(s, cast(dchar)'a', CaseSensitive.no);
|
||||
assert(i == -1);
|
||||
i = indexOf("def", cast(dchar)'a', CaseSensitive.no);
|
||||
assert(i == -1);
|
||||
|
@ -765,46 +762,6 @@ S tolower(S)(S s) if (isSomeString!S)
|
|||
return cast(S) result;
|
||||
}
|
||||
return s;
|
||||
/*
|
||||
foreach (i; 0 .. s.length)
|
||||
{
|
||||
auto c = s[i];
|
||||
if ('A' <= c && c <= 'Z')
|
||||
{
|
||||
if (!changed)
|
||||
{
|
||||
r = s.dup;
|
||||
changed = 1;
|
||||
}
|
||||
r[i] = cast(Unqual!Char) (c + ('a' - 'A'));
|
||||
}
|
||||
else if (c > 0x7F)
|
||||
{
|
||||
foreach (size_t j, dchar dc; s[i .. $])
|
||||
{
|
||||
if (std.uni.isUniUpper(dc))
|
||||
{
|
||||
dc = std.uni.toUniLower(dc);
|
||||
if (!changed)
|
||||
{
|
||||
r = s[0 .. i + j].dup;
|
||||
changed = 2;
|
||||
}
|
||||
}
|
||||
if (changed)
|
||||
{
|
||||
if (changed == 1)
|
||||
{ r = r[0 .. i + j];
|
||||
changed = 2;
|
||||
}
|
||||
std.utf.encode(r, dc);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return changed ? cast(S) r : s;
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1137,7 +1094,7 @@ unittest
|
|||
S repeat(S)(S s, size_t n)
|
||||
{
|
||||
if (n == 0)
|
||||
return null;
|
||||
return S.init;
|
||||
if (n == 1)
|
||||
return s;
|
||||
auto r = new Unqual!(typeof(s[0]))[n * s.length];
|
||||
|
@ -1175,58 +1132,10 @@ unittest
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/********************************************
|
||||
* Concatenate all the strings in words[] together into one
|
||||
* string; use sep[] as the separator.
|
||||
/**
|
||||
* Alias for std.array.join
|
||||
*/
|
||||
|
||||
S join(S, S2)(in S[] words, S2 sep) if (isSomeString!S && isSomeString!S2)
|
||||
{
|
||||
if (!words.length) return null;
|
||||
immutable seplen = sep.length;
|
||||
size_t len = (words.length - 1) * seplen;
|
||||
|
||||
foreach (i; 0 .. words.length)
|
||||
len += words[i].length;
|
||||
|
||||
auto result = new Unqual!(typeof(words[0][0]))[len];
|
||||
|
||||
size_t j;
|
||||
foreach (i; 0 .. words.length)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
result[j .. j + seplen] = sep;
|
||||
j += seplen;
|
||||
}
|
||||
immutable wlen = words[i].length;
|
||||
result[j .. j + wlen] = words[i];
|
||||
j += wlen;
|
||||
}
|
||||
assert(j == len);
|
||||
return cast(S) result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(string) printf("string.join.unittest\n");
|
||||
|
||||
string word1 = "peter";
|
||||
string word2 = "paul";
|
||||
string word3 = "jerry";
|
||||
string[3] words;
|
||||
string r;
|
||||
int i;
|
||||
|
||||
words[0] = word1;
|
||||
words[1] = word2;
|
||||
words[2] = word3;
|
||||
r = join(words, ",");
|
||||
i = cmp(r, "peter,paul,jerry");
|
||||
assert(i == 0, text(i));
|
||||
}
|
||||
|
||||
alias std.array.join join;
|
||||
|
||||
/**************************************
|
||||
Split $(D s[]) into an array of words, using whitespace as delimiter.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue