mirror of
https://github.com/dlang/phobos.git
synced 2025-04-28 06:00:35 +03:00
254 lines
6.2 KiB
D
254 lines
6.2 KiB
D
// Written in the D programming language
|
|
|
|
module std.array;
|
|
|
|
private import std.c.stdio;
|
|
private import std.contracts;
|
|
private import std.traits;
|
|
private import std.gc;
|
|
private import std.string;
|
|
private import std.algorithm;
|
|
version(unittest) private import std.stdio;
|
|
|
|
class ArrayBoundsError : Error
|
|
{
|
|
private:
|
|
|
|
uint linnum;
|
|
string filename;
|
|
|
|
public:
|
|
this(string filename, uint linnum)
|
|
{
|
|
this.linnum = linnum;
|
|
this.filename = filename;
|
|
|
|
char[] buffer = new char[19 + filename.length + linnum.sizeof * 3 + 1];
|
|
auto len = sprintf(buffer.ptr,
|
|
"ArrayBoundsError %.*s(%u)", filename, linnum);
|
|
buffer = buffer[0..len];
|
|
super(assumeUnique(buffer)); // fine because buffer is unaliased
|
|
}
|
|
}
|
|
|
|
|
|
/********************************************
|
|
* Called by the compiler generated module assert function.
|
|
* Builds an ArrayBoundsError exception and throws it.
|
|
*/
|
|
|
|
extern (C) static void _d_array_bounds(string filename, uint line)
|
|
{
|
|
//printf("_d_assert(%s, %d)\n", (char *)filename, line);
|
|
ArrayBoundsError a = new ArrayBoundsError(filename, line);
|
|
//printf("assertion %p created\n", a);
|
|
throw a;
|
|
}
|
|
|
|
/*
|
|
Returns an array consisting of $(D elements).
|
|
|
|
Example:
|
|
|
|
----
|
|
auto a = array(1, 2, 3);
|
|
assert(is(typeof(a) == int[]));
|
|
assert(a == [ 1, 2, 3 ]);
|
|
auto b = array(1, 2.2, 3);
|
|
assert(is(typeof(b) == double[]));
|
|
assert(b == [ 1.0, 2.2, 3 ]);
|
|
----
|
|
*/
|
|
// CommonType!(Ts)[] array(Ts...)(Ts elements)
|
|
// {
|
|
// alias CommonType!(Ts) E;
|
|
// alias typeof(return) R;
|
|
// // 1. Allocate untyped memory
|
|
// auto result = cast(E*) enforce(std.gc.malloc(elements.length * R.sizeof),
|
|
// text("Out of memory while allocating an array of ",
|
|
// elements.length, " objects of type ", E.stringof));
|
|
// // 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];
|
|
// }
|
|
|
|
// unittest
|
|
// {
|
|
// auto a = array(1, 2, 3, 4, 5);
|
|
// writeln(a);
|
|
// assert(a == [ 1, 2, 3, 4, 5 ]);
|
|
|
|
// struct S { int x; string toString() { return .toString(x); } }
|
|
// auto b = array(S(1), S(2));
|
|
// writeln(b);
|
|
|
|
// class C
|
|
// {
|
|
// int x;
|
|
// this(int y) { x = y; }
|
|
// string toString() { return .toString(x); }
|
|
// }
|
|
// auto c = array(new C(1), new C(2));
|
|
// writeln(c);
|
|
|
|
// auto d = array(1, 2.2, 3);
|
|
// assert(is(typeof(d) == double[]));
|
|
// writeln(d);
|
|
// }
|
|
|
|
template IndexType(C : T[], T)
|
|
{
|
|
alias size_t IndexType;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
static assert(is(IndexType!(double[]) == size_t));
|
|
static assert(!is(IndexType!(double) == size_t));
|
|
}
|
|
|
|
/**
|
|
Inserts $(D stuff) in $(D container) at position $(D pos).
|
|
*/
|
|
void insert(T, Range)(ref T[] array, size_t pos, Range stuff)
|
|
{
|
|
static if (is(typeof(stuff[0])))
|
|
{
|
|
// presumably an array
|
|
alias stuff toInsert;
|
|
assert(!overlap(array, toInsert));
|
|
}
|
|
else
|
|
{
|
|
// presumably only one element
|
|
auto toInsert = (&stuff)[0 .. 1];
|
|
}
|
|
|
|
// @@@BUG 2130@@@
|
|
// invariant
|
|
// size_t delta = toInsert.length,
|
|
// size_t oldLength = array.length,
|
|
// size_t newLength = oldLength + delta;
|
|
invariant
|
|
delta = toInsert.length,
|
|
oldLength = array.length,
|
|
newLength = oldLength + delta;
|
|
|
|
// Reallocate the array to make space for new content
|
|
array = cast(T[]) realloc(array.ptr, newLength * array[0].sizeof);
|
|
assert(array.length == newLength);
|
|
|
|
// Move data in pos .. pos + stuff.length to the end of the array
|
|
foreach_reverse (i; pos .. oldLength)
|
|
{
|
|
// This will be guaranteed to not throw
|
|
move(array[i], array[i + delta]);
|
|
}
|
|
|
|
// Copy stuff into array
|
|
foreach (e; toInsert)
|
|
{
|
|
array[pos++] = e;
|
|
}
|
|
}
|
|
|
|
unittest
|
|
{
|
|
int[] a = ([1, 4, 5]).dup;
|
|
insert(a, 1u, [2, 3]);
|
|
assert(a == [1, 2, 3, 4, 5]);
|
|
insert(a, 1u, 99);
|
|
assert(a == [1, 99, 2, 3, 4, 5]);
|
|
}
|
|
|
|
/**
|
|
Erases elements from $(D array) with indices ranging from $(D from)
|
|
(inclusive) to $(D to) (exclusive).
|
|
*/
|
|
void erase(T)(ref T[] array, size_t from, size_t to)
|
|
{
|
|
invariant 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]);
|
|
}
|
|
|
|
/**
|
|
Replaces elements from $(D array) with indices ranging from $(D from)
|
|
(inclusive) to $(D to) (exclusive) with the range $(D stuff). Expands
|
|
or shrinks the array as needed.
|
|
*/
|
|
void replace(T, Range)(ref T[] array, size_t from, size_t to,
|
|
Range stuff)
|
|
{
|
|
// container = container[0 .. from] ~ stuff ~ container[to .. $];
|
|
if (overlap(array, stuff))
|
|
{
|
|
// use slower/conservative method
|
|
array = array[0 .. from] ~ stuff ~ array[to .. $];
|
|
}
|
|
else if (stuff.length <= to - from)
|
|
{
|
|
// replacement reduces length
|
|
// BUG 2128
|
|
//invariant stuffEnd = from + stuff.length;
|
|
auto stuffEnd = from + stuff.length;
|
|
array[from .. stuffEnd] = stuff;
|
|
erase(array, stuffEnd, to);
|
|
}
|
|
else
|
|
{
|
|
// replacement increases length
|
|
// @@@TODO@@@: optimize this
|
|
invariant replaceLen = to - from;
|
|
array[from .. to] = stuff[0 .. replaceLen];
|
|
insert(array, to, stuff[replaceLen .. $]);
|
|
}
|
|
}
|
|
|
|
unittest
|
|
{
|
|
int[] a = [1, 4, 5];
|
|
replace(a, 1u, 2u, [2, 3, 4]);
|
|
assert(a == [1, 2, 3, 4, 5]);
|
|
}
|
|
|