struct memory_pool {
  char * start;
  char * cur;
  size_t size;
  char * free;
};

void ?{}(memory_pool * pool, size_t size) {
  pool->[start, cur] = malloc(size);
  pool->size = size;
  printf("initializing memory pool with size %lu at location %p\n", pool->size, pool->start);
}

void ^?{}(memory_pool * pool) {
  free(pool->start);
}

forall(dtype T | sized(T))
T * allocate(memory_pool * pool, unsigned int array_size = 1) {
  size_t size = sizeof(T) * array_size;
  printf("allocating block of size %lu...", size);
  if (pool->cur + size < pool->start + pool->size) {
    T * x = (T*)pool->cur;
    pool->cur += size;
    printf("success!\n");
    printf("next address is %p\n", pool->cur);
    return x;
  } else {
    printf("failed!\n");
    // fail to allocate
    return 0;
  }
}

struct A {
  int x, y, z;
};
void ?{}(A * a) {
  a->[x,y,z] = [123, 456, 789];
}

int main() {
  memory_pool pool = { 1024 };

  int * x = allocate(&pool);
  A * a = allocate(&pool);
  A * b = allocate(&pool, 1000);
  a{};
  printf("%p\n", x);
  printf("%p %d %d %d\n", a, a->[x,y,z]);
}
