Moved join from std.string to std.array, plus a few cosmetic changes

This commit is contained in:
Andrei Alexandrescu 2011-01-17 20:43:54 +00:00
parent a0ecf2a10e
commit cf33c1999a
4 changed files with 175 additions and 191 deletions

View file

@ -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)

View file

@ -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];

View file

@ -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

View file

@ -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.