
import vectors.generic.*;


//
// Vector[T]
//

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



//
// predicates
//

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

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

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



//
// constructors
//

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

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

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

[A | MultiValuedSequence?(A)]
overload Vector(forward a:A) = Vector(mapped(Tuple, a));



//
// varargs constructor
//

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

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

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

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

[T]
overload assign(ref dest:Vector[T], ref src:Vector[T]) {
    resizeUnsafe(dest, size(src));
    assignNonoverlappingMemory(begin(dest), begin(src), end(src));
}

[T]
overload destroy(a:Vector[T]) {
    destroyMemory(begin(a), end(a));
    freeRawMemory(a.data);
}



//
// generic vector requirements
//

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

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

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

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

[T]
inline 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 = allocateRawMemory(T, capacity);
    moveNonoverlappingMemoryUnsafe(data, a.data, a.data + a.size);
    freeRawMemory(a.data);
    a.data = data;
    a.capacity = capacity;
}

[T | BitwiseMovedType?(T) and CallDefined?(reallocateRawMemory, Pointer[T], SizeT)]
overload reallocVector(a:Vector[T], capacity:SizeT) {
    a.data = reallocateRawMemory(a.data, capacity);
    a.capacity = capacity;
}
