Made Appender instantiable with string and other arrays with immutable elements. Also now Appender appends ranges to arrays wherever applicable.

This commit is contained in:
Andrei Alexandrescu 2009-04-29 21:31:33 +00:00
parent 2a1def14ff
commit e112df9d98

View file

@ -4,12 +4,8 @@ module std.array;
import std.c.stdio; import std.c.stdio;
import core.memory; import core.memory;
import std.contracts; import std.algorithm, std.contracts, std.conv, std.encoding, std.range,
import std.traits; std.string, std.traits, std.typecons;
import std.string;
import std.algorithm;
import std.encoding;
import std.typecons;
version(unittest) private import std.stdio; version(unittest) private import std.stdio;
/* /*
@ -430,7 +426,7 @@ recommended over $(D a ~= data) because it is more efficient.
Example: Example:
---- ----
auto arr = new char[0]; string arr;
auto app = appender(&arr); auto app = appender(&arr);
string b = "abcdefg"; string b = "abcdefg";
foreach (char c; b) app.put(c); foreach (char c; b) app.put(c);
@ -447,7 +443,7 @@ assert(app2.data == [ 1, 2, 3, 4, 5, 6 ]);
struct Appender(A : T[], T) struct Appender(A : T[], T)
{ {
private: private:
T[] * pArray; Unqual!(T)[] * pArray;
size_t _capacity; size_t _capacity;
public: public:
@ -459,10 +455,9 @@ will allocate and use a new array.
*/ */
this(T[] * p) this(T[] * p)
{ {
pArray = p; pArray = cast(Unqual!(T)[] *) p;
if (!pArray) pArray = (new typeof(*pArray)[1]).ptr; if (!pArray) pArray = (new typeof(*pArray)[1]).ptr;
_capacity = GC.sizeOf(pArray.ptr) / T.sizeof; _capacity = GC.sizeOf(pArray.ptr) / T.sizeof;
//_capacity = .capacity(pArray.ptr) / T.sizeof;
} }
/** /**
@ -470,7 +465,7 @@ Returns the managed array.
*/ */
T[] data() T[] data()
{ {
return pArray ? *pArray : null; return cast(typeof(return)) (pArray ? *pArray : null);
} }
/** /**
@ -478,82 +473,68 @@ Returns the capacity of the array (the maximum number of elements the
managed array can accommodate before triggering a reallocation). managed array can accommodate before triggering a reallocation).
*/ */
size_t capacity() const { return _capacity; } size_t capacity() const { return _capacity; }
static if (is(const(T) : T))
{
/**
An alias for the accepted type to be appended.
*/
alias const(T) AcceptedElementType;
}
else
{
alias T AcceptedElementType;
}
/** /**
Appends one item to the managed array. Appends one item to the managed array.
*/ */
void put(AcceptedElementType item) void put(U)(U item) if (isImplicitlyConvertible!(U, T) ||
isSomeString!(T[]) && isSomeString!(U[]))
{ {
if (!pArray) pArray = (new typeof(*pArray)[1]).ptr; static if (isSomeString!(T[]) && T.sizeof != U.sizeof)
if (pArray.length < _capacity)
{ {
// Should do in-place construction here // must do some transcoding around here
pArray.ptr[pArray.length] = item; encode!(T)(item, this);
*pArray = pArray.ptr[0 .. pArray.length + 1];
} }
else else
{ {
// Time to reallocate, do it and cache capacity if (!pArray) pArray = (new typeof(*pArray)[1]).ptr;
*pArray ~= item; if (pArray.length < _capacity)
//_capacity = .capacity(pArray.ptr) / T.sizeof; {
_capacity = GC.sizeOf(pArray.ptr) / T.sizeof; // Should do in-place construction here
pArray.ptr[pArray.length] = item;
*pArray = pArray.ptr[0 .. pArray.length + 1];
}
else
{
// Time to reallocate, do it and cache capacity
*pArray ~= item;
_capacity = GC.sizeOf(pArray.ptr) / T.sizeof;
}
} }
} }
/** /**
Appends another array to the managed array. Appends an entire range to the managed array.
*/ */
void put(AcceptedElementType[] items) void put(Range)(Range items) if (isForwardRange!Range
&& is(typeof(Appender.init.put(ElementType!(Range).init))))
{ {
for (; !items.empty(); items.popFront()) { // @@@ UNCOMMENT WHEN BUG 2912 IS FIXED @@@
put(items.front()); // static if (is(typeof(*cast(T[]*) pArray ~= items)))
} // {
} // if (!pArray) pArray = (new typeof(*pArray)[1]).ptr;
// *pArray ~= items;
// }
// else
// {
// // Generic input range
// for (; !items.empty; items.popFront)
// {
// put(items.front());
// }
// }
static if (is(Unqual!(T) == wchar) || is(Unqual!(T) == dchar)) // @@@ Doctored version taking BUG 2912 into account @@@
{ static if (is(typeof(*cast(T[]*) pArray ~= items)) &&
/** T.sizeof == ElementType!Range.sizeof)
In case the managed array has type $(D char[]), $(D wchar[]), or $(D
dchar[]), all other character widths and arrays thereof are also
accepted.
*/
void put(in char c) { encode!(T)((&c)[0 .. 1], this); }
/// Ditto
void put(in char[] cs)
{ {
encode!(T)(cs, this); if (!pArray) pArray = (new typeof(*pArray)[1]).ptr;
*pArray ~= items;
} }
} else
static if (is(Unqual!(T) == char) || is(Unqual!(T) == dchar))
{
/// Ditto
void put(in wchar dc) { assert(false); }
/// Ditto
void put(in wchar[] dcs)
{ {
encode!(T)(dcs, this); // Generic input range
} foreach (e; items) put(e);
}
static if (is(Unqual!(T) == char) || is(Unqual!(T) == wchar))
{
/// Ditto
void put(in dchar dc) { std.utf.encode(*pArray, dc); }
/// Ditto
void put(in dchar[] wcs)
{
encode!(T)(wcs, this);
} }
} }
@ -589,7 +570,7 @@ unittest
int[] a = [ 1, 2 ]; int[] a = [ 1, 2 ];
auto app2 = appender(&a); auto app2 = appender(&a);
app2.put(3); app2.put(3);
app2.put([ 4, 5, 6 ]); app2.put([ 4, 5, 6 ][]);
assert(app2.data == [ 1, 2, 3, 4, 5, 6 ]); assert(app2.data == [ 1, 2, 3, 4, 5, 6 ]);
} }