mirror of
https://github.com/dlang/phobos.git
synced 2025-05-12 15:17:12 +03:00
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:
parent
2a1def14ff
commit
e112df9d98
1 changed files with 50 additions and 69 deletions
119
std/array.d
119
std/array.d
|
@ -4,12 +4,8 @@ module std.array;
|
|||
|
||||
import std.c.stdio;
|
||||
import core.memory;
|
||||
import std.contracts;
|
||||
import std.traits;
|
||||
import std.string;
|
||||
import std.algorithm;
|
||||
import std.encoding;
|
||||
import std.typecons;
|
||||
import std.algorithm, std.contracts, std.conv, std.encoding, std.range,
|
||||
std.string, std.traits, std.typecons;
|
||||
version(unittest) private import std.stdio;
|
||||
|
||||
/*
|
||||
|
@ -430,7 +426,7 @@ recommended over $(D a ~= data) because it is more efficient.
|
|||
|
||||
Example:
|
||||
----
|
||||
auto arr = new char[0];
|
||||
string arr;
|
||||
auto app = appender(&arr);
|
||||
string b = "abcdefg";
|
||||
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)
|
||||
{
|
||||
private:
|
||||
T[] * pArray;
|
||||
Unqual!(T)[] * pArray;
|
||||
size_t _capacity;
|
||||
|
||||
public:
|
||||
|
@ -459,10 +455,9 @@ will allocate and use a new array.
|
|||
*/
|
||||
this(T[] * p)
|
||||
{
|
||||
pArray = p;
|
||||
pArray = cast(Unqual!(T)[] *) p;
|
||||
if (!pArray) pArray = (new typeof(*pArray)[1]).ptr;
|
||||
_capacity = GC.sizeOf(pArray.ptr) / T.sizeof;
|
||||
//_capacity = .capacity(pArray.ptr) / T.sizeof;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -470,7 +465,7 @@ Returns the managed array.
|
|||
*/
|
||||
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).
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
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;
|
||||
if (pArray.length < _capacity)
|
||||
static if (isSomeString!(T[]) && T.sizeof != U.sizeof)
|
||||
{
|
||||
// Should do in-place construction here
|
||||
pArray.ptr[pArray.length] = item;
|
||||
*pArray = pArray.ptr[0 .. pArray.length + 1];
|
||||
// must do some transcoding around here
|
||||
encode!(T)(item, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Time to reallocate, do it and cache capacity
|
||||
*pArray ~= item;
|
||||
//_capacity = .capacity(pArray.ptr) / T.sizeof;
|
||||
_capacity = GC.sizeOf(pArray.ptr) / T.sizeof;
|
||||
if (!pArray) pArray = (new typeof(*pArray)[1]).ptr;
|
||||
if (pArray.length < _capacity)
|
||||
{
|
||||
// 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()) {
|
||||
put(items.front());
|
||||
}
|
||||
}
|
||||
// @@@ UNCOMMENT WHEN BUG 2912 IS FIXED @@@
|
||||
// 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))
|
||||
{
|
||||
/**
|
||||
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)
|
||||
// @@@ Doctored version taking BUG 2912 into account @@@
|
||||
static if (is(typeof(*cast(T[]*) pArray ~= items)) &&
|
||||
T.sizeof == ElementType!Range.sizeof)
|
||||
{
|
||||
encode!(T)(cs, this);
|
||||
if (!pArray) pArray = (new typeof(*pArray)[1]).ptr;
|
||||
*pArray ~= items;
|
||||
}
|
||||
}
|
||||
static if (is(Unqual!(T) == char) || is(Unqual!(T) == dchar))
|
||||
{
|
||||
/// Ditto
|
||||
void put(in wchar dc) { assert(false); }
|
||||
/// Ditto
|
||||
void put(in wchar[] dcs)
|
||||
else
|
||||
{
|
||||
encode!(T)(dcs, this);
|
||||
}
|
||||
}
|
||||
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);
|
||||
// Generic input range
|
||||
foreach (e; items) put(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -589,7 +570,7 @@ unittest
|
|||
int[] a = [ 1, 2 ];
|
||||
auto app2 = appender(&a);
|
||||
app2.put(3);
|
||||
app2.put([ 4, 5, 6 ]);
|
||||
app2.put([ 4, 5, 6 ][]);
|
||||
assert(app2.data == [ 1, 2, 3, 4, 5, 6 ]);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue