Skip to content

Commit

Permalink
Merge pull request #1108 from AndrejMitrovic/Fix4287
Browse files Browse the repository at this point in the history
Issue 4287 - Implement concat-assign operator for Appender.
  • Loading branch information
alexrp committed Feb 7, 2013
2 parents bb25033 + 92b7d19 commit 2a88fea
Showing 1 changed file with 149 additions and 32 deletions.
181 changes: 149 additions & 32 deletions std/array.d
Original file line number Diff line number Diff line change
Expand Up @@ -830,7 +830,7 @@ unittest

private void copyBackwards(T)(T[] src, T[] dest)
{
import core.stdc.string;
import core.stdc.string;
assert(src.length == dest.length);
if (!__ctfe)
memmove(dest.ptr, src.ptr, src.length * T.sizeof);
Expand Down Expand Up @@ -861,7 +861,7 @@ assert(a == [ 1, 2, 1, 10, 11, 2, 3, 4]);
), $(ARGS), $(ARGS), $(ARGS import std.array;))
+/
void insertInPlace(T, U...)(ref T[] array, size_t pos, U stuff)
if(!isSomeString!(T[])
if(!isSomeString!(T[])
&& allSatisfy!(isInputRangeOrConvertible!T, U) && U.length > 0)
{
static if(allSatisfy!(isInputRangeWithLengthOrConvertible!T, U))
Expand Down Expand Up @@ -894,11 +894,11 @@ void insertInPlace(T, U...)(ref T[] array, size_t pos, U stuff)
else
{
// stuff has some InputRanges in it that don't have length
// assume that stuff to be inserted is typically shorter
// then the array that can be arbitrary big
// assume that stuff to be inserted is typically shorter
// then the array that can be arbitrary big
// TODO: needs a better implementation as there is no need to build an _array_
// a singly-linked list of memory blocks (rope, etc.) will do
auto app = appender!(T[])();
auto app = appender!(T[])();
foreach (i, E; U)
app.put(stuff[i]);
insertInPlace(array, pos, app.data);
Expand Down Expand Up @@ -995,7 +995,7 @@ private template isInputRangeWithLengthOrConvertible(E)
//ditto
private template isCharOrStringOrDcharRange(T)
{
enum isCharOrStringOrDcharRange = isSomeString!T || isSomeChar!T ||
enum isCharOrStringOrDcharRange = isSomeString!T || isSomeChar!T ||
(isInputRange!T && is(ElementType!T : dchar));
}

Expand Down Expand Up @@ -1077,7 +1077,7 @@ unittest
testStr!(T[], U[])();
}

}
}

// variadic version
bool testVar(T, U...)(T orig, size_t pos, U args)
Expand Down Expand Up @@ -1115,8 +1115,8 @@ unittest
{
int* payload;
this(int k)
{
payload = new int;
{
payload = new int;
*payload = k;
}
this(this)
Expand All @@ -1129,15 +1129,15 @@ unittest
{
*payload = 0; //'destroy' it
}
@property int getPayload(){ return *payload; }
@property int getPayload(){ return *payload; }
alias getPayload this;
}

Int[] arr;// = [Int(1), Int(4), Int(5)]; //@@BUG 8740
arr ~= [Int(1), Int(4), Int(5)];
assert(arr[0] == 1);
insertInPlace(arr, 1, Int(2), Int(3));
assert(equal(arr, [1, 2, 3, 4, 5])); //check it works with postblit
assert(equal(arr, [1, 2, 3, 4, 5])); //check it works with postblit
}

unittest
Expand Down Expand Up @@ -2219,11 +2219,28 @@ Returns the managed array.
return newext > newlength ? newext : newlength;
}

private template canPutItem(U)
{
enum bool canPutItem = isImplicitlyConvertible!(U, T) ||
isSomeChar!T && isSomeChar!U;
}

private template canPutConstRange(Range)
{
enum bool canPutConstRange = isInputRange!(Unqual!Range) &&
!isInputRange!Range;
}

private template canPutRange(Range)
{
enum bool canPutRange = isInputRange!Range &&
is(typeof(Appender.init.put(Range.init.front)));
}

/**
Appends one item to the managed array.
*/
void put(U)(U item) if (isImplicitlyConvertible!(U, T) ||
isSomeChar!T && isSomeChar!U)
void put(U)(U item) if (canPutItem!U)
{
static if (isSomeChar!T && isSomeChar!U && T.sizeof < U.sizeof)
{
Expand All @@ -2242,17 +2259,16 @@ Appends one item to the managed array.
}

// Const fixing hack.
void put(Range)(Range items)
if(isInputRange!(Unqual!Range) && !isInputRange!Range) {
void put(Range)(Range items) if (canPutConstRange!Range)
{
alias put!(Unqual!Range) p;
p(items);
}

/**
Appends an entire range to the managed array.
*/
void put(Range)(Range items) if (isInputRange!Range
&& is(typeof(Appender.init.put(items.front))))
void put(Range)(Range items) if (canPutRange!Range)
{
// note, we disable this branch for appending one type of char to
// another because we can't trust the length portion.
Expand Down Expand Up @@ -2300,6 +2316,28 @@ Appends an entire range to the managed array.
}
}

/**
Appends one item to the managed array.
*/
void opOpAssign(string op : "~", U)(U item) if (canPutItem!U)
{
put(item);
}

// Const fixing hack.
void opOpAssign(string op : "~", Range)(Range items) if (canPutConstRange!Range)
{
put(items);
}

/**
Appends an entire range to the managed array.
*/
void opOpAssign(string op : "~", Range)(Range items) if (canPutRange!Range)
{
put(items);
}

// only allow overwriting data on non-immutable and non-const data
static if(!is(T == immutable) && !is(T == const))
{
Expand Down Expand Up @@ -2371,6 +2409,33 @@ those appends.
mixin("return impl." ~ fn ~ "(args);");
}

private alias Appender!(A, T) AppenderType;

/**
Appends one item to the managed array.
*/
void opOpAssign(string op : "~", U)(U item) if (AppenderType.canPutItem!U)
{
scope(exit) *this.arr = impl.data;
impl.put(item);
}

// Const fixing hack.
void opOpAssign(string op : "~", Range)(Range items) if (AppenderType.canPutConstRange!Range)
{
scope(exit) *this.arr = impl.data;
impl.put(items);
}

/**
Appends an entire range to the managed array.
*/
void opOpAssign(string op : "~", Range)(Range items) if (AppenderType.canPutRange!Range)
{
scope(exit) *this.arr = impl.data;
impl.put(items);
}

/**
Returns the capacity of the array (the maximum number of elements the
managed array can accommodate before triggering a reallocation). If any
Expand Down Expand Up @@ -2401,18 +2466,36 @@ Appender!(E[]) appender(A : E[], E)(A array = null)

unittest
{
auto app = appender!(char[])();
string b = "abcdefg";
foreach (char c; b) app.put(c);
assert(app.data == "abcdefg");
{
auto app = appender!(char[])();
string b = "abcdefg";
foreach (char c; b) app.put(c);
assert(app.data == "abcdefg");
}
{
auto app = appender!(char[])();
string b = "abcdefg";
foreach (char c; b) app ~= c;
assert(app.data == "abcdefg");
}
{
int[] a = [ 1, 2 ];
auto app2 = appender(a);
assert(app2.data == [ 1, 2 ]);
app2.put(3);
app2.put([ 4, 5, 6 ][]);
assert(app2.data == [ 1, 2, 3, 4, 5, 6 ]);
app2.put([ 7 ]);
assert(app2.data == [ 1, 2, 3, 4, 5, 6, 7 ]);
}

int[] a = [ 1, 2 ];
auto app2 = appender(a);
assert(app2.data == [ 1, 2 ]);
app2.put(3);
app2.put([ 4, 5, 6 ][]);
app2 ~= 3;
app2 ~= [ 4, 5, 6 ][];
assert(app2.data == [ 1, 2, 3, 4, 5, 6 ]);
app2.put([ 7 ]);
app2 ~= [ 7 ];
assert(app2.data == [ 1, 2, 3, 4, 5, 6, 7 ]);

app2.reserve(5);
Expand Down Expand Up @@ -2443,6 +2526,20 @@ unittest
assertNotThrown(app5663m.put(cast(char[])"\xE3"));
assert(app5663m.data == "\xE3");
}
// ditto for ~=
{
Appender!(char[]) app5663i;
assertNotThrown(app5663i ~= "\xE3");
assert(app5663i.data == "\xE3");

Appender!(char[]) app5663c;
assertNotThrown(app5663c ~= cast(const(char)[])"\xE3");
assert(app5663c.data == "\xE3");

Appender!(char[]) app5663m;
assertNotThrown(app5663m ~= cast(char[])"\xE3");
assert(app5663m.data == "\xE3");
}
}

/++
Expand All @@ -2457,19 +2554,39 @@ RefAppender!(E[]) appender(A : E[]*, E)(A array)

unittest
{
auto arr = new char[0];
auto app = appender(&arr);
string b = "abcdefg";
foreach (char c; b) app.put(c);
assert(app.data == "abcdefg");
assert(arr == "abcdefg");
{
auto arr = new char[0];
auto app = appender(&arr);
string b = "abcdefg";
foreach (char c; b) app.put(c);
assert(app.data == "abcdefg");
assert(arr == "abcdefg");
}
{
auto arr = new char[0];
auto app = appender(&arr);
string b = "abcdefg";
foreach (char c; b) app ~= c;
assert(app.data == "abcdefg");
assert(arr == "abcdefg");
}
{
int[] a = [ 1, 2 ];
auto app2 = appender(&a);
assert(app2.data == [ 1, 2 ]);
assert(a == [ 1, 2 ]);
app2.put(3);
app2.put([ 4, 5, 6 ][]);
assert(app2.data == [ 1, 2, 3, 4, 5, 6 ]);
assert(a == [ 1, 2, 3, 4, 5, 6 ]);
}

int[] a = [ 1, 2 ];
auto app2 = appender(&a);
assert(app2.data == [ 1, 2 ]);
assert(a == [ 1, 2 ]);
app2.put(3);
app2.put([ 4, 5, 6 ][]);
app2 ~= 3;
app2 ~= [ 4, 5, 6 ][];
assert(app2.data == [ 1, 2, 3, 4, 5, 6 ]);
assert(a == [ 1, 2, 3, 4, 5, 6 ]);

Expand Down

0 comments on commit 2a88fea

Please sign in to comment.