
use mem

+ class Pool[T] {
    - data: ptr
    - size: uint
    ~ count: uint (0)

    + static fn new(start_size: uint (2)) SELF {
        if start_size < 2 {
            start_size = 2
        }
        return SELF {
            size: start_size
            data: mem:alloc(start_size * size_of(T))
        }
    }

    + fn add(item: T) {
        let count = this.count
        let size = this.size
        if count == size {
            this.increase_size(size * 2)
        }

        @ptrv(this.data, T, count) = item
        this.count = count + 1
    }

    + fn get() T !empty {
        let count = this.count
        if count == 0 : throw empty
        let new_count = count - 1
        let item = @ptrv(this.data, T, new_count)
        this.count = new_count
        return item
    }

    fn increase_size(new_size: uint) ptr {
        this.data = mem:resize(this.data, this.size * size_of(T), new_size * size_of(T))
        this.size = new_size
        return this.data
    }

    fn gc_free() {
        mem:free(this.data)
    }
}

class StructPool[T] {
    - data: ptr
    ~ count: uint (0)
    - size: uint

    static fn new(start_size: uint (2)) SELF {
        if start_size < 2 {
            start_size = 2
        }
        return SELF {
            size: start_size
            data: mem:alloc(start_size * size_of(T))
        }
    }

    fn add(item: T) {
        let count = this.count
        let size = this.size
        if count == size {
            this.increase_size(size * 2)
        }

        @ptrv(this.data, T, count) = item
        this.count = count + 1
    }

    fn get() T !empty {
        let count = this.count
        if count == 0 : throw empty
        let new_count = count - 1
        let item = @ptrv(this.data, T, new_count)
        this.count = new_count
        return item
    }

    fn increase_size(new_size: uint) ptr {
        this.data = mem:resize(this.data, this.size * size_of(T), new_size * size_of(T))
        this.size = new_size
        return this.data
    }
}
