
import paged.*;
import vectors.generic.*;


//
// Vector[T]
//

record Vector[T] (
    size:SizeT,
    capacity:SizeT,
    data:PagedPointer[T],
);



//
// predicates
//

[T] overload RegularRecord?(static Vector[T]) = false;

[T] overload ContiguousSequence?(static Vector[T]) = true; 



//
// constructors
//

[T]
overload Vector[T]() = Vector[T](SizeT(0), SizeT(0), nullPaged(T));

[T,A | Sequence?(A) and (T == SequenceElementType(A))]
overload Vector[T](a:A) {
    var v = Vector[T]();
    for (x in a)
        push(v, x);
    return move(v);
}

[T,A | SizedSequence?(A) and (T == SequenceElementType(A))]
overload Vector[T](a:A) {
    var v = Vector[T]();
    reserve(v, size(a));
    for (x in a)
        push(v, x);
    return move(v);
}

[A | Sequence?(A)]
overload Vector(a:A) {
    alias T = SequenceElementType(A);
    return Vector[T](a);
}



//
// varargs constructor
//

[T, ..A | (countValues(..A) > 0) and equalValues?(T, ..A)]
alias overload Vector[T](..args:A) {
    var v = Vector[T]();
    reserve(v, countValues(..A));
    pushAll(v, ..args);
    return move(v);
}

private pushAll(a, forward x, forward ..rest) { push(a, x); pushAll(a, ..rest); }
overload pushAll(a) {}



//
// moveUnsafe, resetUnsafe, assign, destroy
//

[T]
overload BitwiseMovedType?(static Vector[T]) = true;

[T]
overload resetUnsafe(a:Vector[T]) {
    a <-- Vector[T]();
}


[T]
overload assign(ref dest:Vector[T], ref src:Vector[T]) {
    resize(dest, size(src));
    for (x, y in zipped(dest, src))
        assign(x, y);
}

[T]
overload destroy(a:Vector[T]) {
    for (x in a)
        destroy(x);
    freePaged(a.data);
}



//
// generic vector requirements
//

[T]
overload Vector?(static Vector[T]) = true;

[T]
overload vectorData(a:Vector[T]) = &(a.data^);

[T]
overload vectorSize(a:Vector[T]) = a.size;

[T]
overload vectorSetSize(a:Vector[T], n:SizeT) {
    a.size = n;
}

[T]
overload vectorCapacity(a:Vector[T]) = a.capacity;

[T]
overload vectorRequestCapacity(a:Vector[T], capacity:SizeT) {
    assert(capacity >= a.size);
    if (capacity < a.capacity)
        return;
    var n = max(capacity, SizeT(16));
    n = max(n, 2*a.capacity);
    reallocVector(a, n);
}

[T]
private reallocVector(a:Vector[T], capacity:SizeT) {
    var data = allocatePaged(T, capacity);
    var ptr = data;
    for (x in a) {
        ptr^ <-- moveUnsafe(x);
        inc(ptr);
    }
    freePaged(a.data);
    a.data = data;
    a.capacity = capacity;
}
