summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/std/README.md3
-rw-r--r--docs/std/vec.md90
-rw-r--r--examples/gpu/cuda_info.zc33
-rw-r--r--src/parser/parser_stmt.c26
-rw-r--r--src/parser/parser_utils.c37
-rw-r--r--std/cuda.zc85
-rw-r--r--std/vec.zc109
-rw-r--r--tests/collections/test_vec_suite.zc177
-rw-r--r--tests/std/test_vec.zc168
9 files changed, 534 insertions, 194 deletions
diff --git a/docs/std/README.md b/docs/std/README.md
new file mode 100644
index 0000000..8202192
--- /dev/null
+++ b/docs/std/README.md
@@ -0,0 +1,3 @@
+# Standard Library
+
+- [Vector (Vec)](./vec.md) - A growable dynamic array.
diff --git a/docs/std/vec.md b/docs/std/vec.md
new file mode 100644
index 0000000..a0422bb
--- /dev/null
+++ b/docs/std/vec.md
@@ -0,0 +1,90 @@
+# Standard Library: Vector (`std/vec.zc`)
+
+`Vec<T>` is a contiguous, growable array type. It is the standard dynamic array used in Zen-C.
+
+## Overview
+
+- **Generic**: Works with any type `T`.
+- **Dynamic**: Automatically resizes as elements are added.
+- **Safe**: Bounds checks on access (panics on failure).
+- **RAII**: Automatically frees memory when it goes out of scope (implements `Drop`).
+
+## Usage
+
+```zc
+import "std/vec.zc"
+
+fn main() {
+ var v = Vec<int>::new();
+ v.push(10);
+ v.push(20);
+
+ // Iteration
+ for x in &v {
+ println "{(*x)}";
+ }
+} // v is freed automatically here
+```
+
+## Struct Definition
+
+```zc
+struct Vec<T> {
+ data: T*;
+ len: usize;
+ cap: usize;
+}
+```
+
+## Methods
+
+### Construction
+
+| Method | Signature | Description |
+| :--- | :--- | :--- |
+| **new** | `Vec<T>::new() -> Vec<T>` | Creates a new, empty vector. Does not allocate memory until the first push. |
+| **with_capacity** | `Vec<T>::with_capacity(cap: usize) -> Vec<T>` | Creates a new vector with an initial capacity of `cap`. Useful for optimization if you know the number of elements in advance. |
+
+### Modification
+
+| Method | Signature | Description |
+| :--- | :--- | :--- |
+| **push** | `push(self, item: T)` | Appends an element to the back. Panics if allocation fails. |
+| **pop** | `pop(self) -> T` | Removes the last element and returns it. Panics if empty. |
+| **pop_opt** | `pop_opt(self) -> Option<T>` | Removes the last element and returns `Some(val)`. Returns `None` if empty. Safe usage. |
+| **insert** | `insert(self, idx: usize, item: T)` | Inserts an element at `idx`. Shifts elements right. Panics if `idx > len`. |
+| **remove** | `remove(self, idx: usize) -> T` | Removes and returns the element at `idx`. Shifts elements left. Panics if `idx >= len`. |
+| **clear** | `clear(self)` | Removes all values. Has no effect on allocated capacity. |
+| **reverse** | `reverse(self)` | Reverses the order of elements in place. |
+
+### Access
+
+| Method | Signature | Description |
+| :--- | :--- | :--- |
+| **get** | `get(self, idx: usize) -> T` | Returns a copy of the element at `idx`. Panics if out of bounds. |
+| **set** | `set(self, idx: usize, item: T)` | Overwrites the element at `idx`. Panics if out of bounds. |
+| **first** | `first(self) -> T` | Returns a copy of the first element. Panics if empty. |
+| **last** | `last(self) -> T` | Returns a copy of the last element. Panics if empty. |
+
+### Utility
+
+| Method | Signature | Description |
+| :--- | :--- | :--- |
+| **length** | `length(self) -> usize` | Returns the number of elements. |
+| **is_empty** | `is_empty(self) -> bool` | Returns `true` if the vector contains no elements. |
+| **contains** | `contains(self, item: T) -> bool` | Returns `true` if vector contains an element equal to `item` (byte-wise). |
+| **clone** | `clone(self) -> Vec<T>` | Returns a new vector with a deep copy of the data. |
+
+### Iteration
+
+| Method | Signature | Description |
+| :--- | :--- | :--- |
+| **iterator** | `iterator(self) -> VecIter<T>` | Returns an iterator yielding copies. Used by `for x in v`. |
+| **iter_ref** | `iter_ref(self) -> VecIterRef<T>` | Returns an iterator yielding pointers. Used by `for x in &v` (sugar) or `for x in v.iter_ref()`. Allows in-place mod. |
+
+## Memory Management
+
+| Method | Signature | Description |
+| :--- | :--- | :--- |
+| **Free** | `free(self)` | Manually frees memory. Safe to call multiple times. |
+| **Trait** | `impl Drop for Vec` | Automatically calls `free()` when `Vec` goes out of scope. |
diff --git a/examples/gpu/cuda_info.zc b/examples/gpu/cuda_info.zc
new file mode 100644
index 0000000..7e832d1
--- /dev/null
+++ b/examples/gpu/cuda_info.zc
@@ -0,0 +1,33 @@
+
+import "std/cuda.zc"
+import "std/string.zc"
+
+fn main() {
+ var count = cuda_device_count();
+ "---------------------------";
+ "CUDA Device Count: {count}";
+ "---------------------------";
+
+ if (count > 0) {
+ var props = cuda_device_properties(0);
+
+ "Device Name: {props.name.vec.data}";
+ "Total Global Mem: {props.total_global_mem}";
+ "SM Count: {props.multi_processor_count}";
+ "Compute Capability: {props.major}.{props.minor}";
+ "Max Threads per Block: {props.max_threads_per_block}";
+ "Warp Size: {props.warp_size}";
+
+ props.name.free();
+
+ var driver = cuda_driver_version();
+ var runtime = cuda_runtime_version();
+
+ "Driver Version: {driver}";
+ "Runtime Version: {runtime}";
+
+ var mem = cuda_mem_info();
+ "Free Mem: {mem.free}";
+ "Total Mem: {mem.total}";
+ }
+}
diff --git a/src/parser/parser_stmt.c b/src/parser/parser_stmt.c
index 699b9fc..db47d16 100644
--- a/src/parser/parser_stmt.c
+++ b/src/parser/parser_stmt.c
@@ -1665,17 +1665,26 @@ ASTNode *parse_for(ParserContext *ctx, Lexer *l)
var_name[var.len] = 0;
ASTNode *obj_expr = start_expr;
+ char *iter_method = "iterator";
+
+ // Check for reference iteration: for x in &vec
+ if (obj_expr->type == NODE_EXPR_UNARY &&
+ obj_expr->unary.op && strcmp(obj_expr->unary.op, "&") == 0)
+ {
+ obj_expr = obj_expr->unary.operand;
+ iter_method = "iter_ref";
+ }
// var __it = obj.iterator();
ASTNode *it_decl = ast_create(NODE_VAR_DECL);
it_decl->var_decl.name = xstrdup("__it");
it_decl->var_decl.type_str = NULL; // inferred
- // obj.iterator()
+ // obj.iterator() or obj.iter_ref()
ASTNode *call_iter = ast_create(NODE_EXPR_CALL);
ASTNode *memb_iter = ast_create(NODE_EXPR_MEMBER);
memb_iter->member.target = obj_expr;
- memb_iter->member.field = xstrdup("iterator");
+ memb_iter->member.field = xstrdup(iter_method);
call_iter->call.callee = memb_iter;
call_iter->call.args = NULL;
call_iter->call.arg_count = 0;
@@ -3391,6 +3400,19 @@ ASTNode *parse_impl(ParserContext *ctx, Lexer *l)
n->impl_trait.target_type = name2;
n->impl_trait.methods = h;
add_to_impl_list(ctx, n);
+
+ // If target struct is generic, register this impl as a template
+ ASTNode *def = find_struct_def(ctx, name2);
+ if (def && ((def->type == NODE_STRUCT && def->strct.is_template) ||
+ (def->type == NODE_ENUM && def->enm.is_template)))
+ {
+ const char *gp = "T";
+ if (def->type == NODE_STRUCT && def->strct.generic_param_count > 0)
+ gp = def->strct.generic_params[0];
+ // TODO: Enum generic params support if needed
+ register_impl_template(ctx, name2, gp, n);
+ }
+
return n;
}
else
diff --git a/src/parser/parser_utils.c b/src/parser/parser_utils.c
index 1f881b7..f96ed24 100644
--- a/src/parser/parser_utils.c
+++ b/src/parser/parser_utils.c
@@ -1518,6 +1518,11 @@ ASTNode *copy_ast_replacing(ASTNode *n, const char *p, const char *c, const char
new_node->impl.struct_name = replace_type_str(n->impl.struct_name, p, c, os, ns);
new_node->impl.methods = copy_ast_replacing(n->impl.methods, p, c, os, ns);
break;
+ case NODE_IMPL_TRAIT:
+ new_node->impl_trait.trait_name = xstrdup(n->impl_trait.trait_name);
+ new_node->impl_trait.target_type = replace_type_str(n->impl_trait.target_type, p, c, os, ns);
+ new_node->impl_trait.methods = copy_ast_replacing(n->impl_trait.methods, p, c, os, ns);
+ break;
default:
break;
}
@@ -1879,8 +1884,17 @@ void instantiate_methods(ParserContext *ctx, GenericImplTemplate *it,
it->struct_name, mangled_struct_name);
it->impl_node->next = backup_next; // Restore
- new_impl->impl.struct_name = xstrdup(mangled_struct_name);
- ASTNode *meth = new_impl->impl.methods;
+
+ ASTNode *meth = NULL;
+
+ if (new_impl->type == NODE_IMPL) {
+ new_impl->impl.struct_name = xstrdup(mangled_struct_name);
+ meth = new_impl->impl.methods;
+ } else if (new_impl->type == NODE_IMPL_TRAIT) {
+ new_impl->impl_trait.target_type = xstrdup(mangled_struct_name);
+ meth = new_impl->impl_trait.methods;
+ }
+
while (meth)
{
char *suffix = meth->func.name + strlen(it->struct_name);
@@ -1995,6 +2009,16 @@ void instantiate_generic(ParserContext *ctx, const char *tpl, const char *arg,
ASTNode *i = ast_create(NODE_STRUCT);
i->strct.name = xstrdup(m);
i->strct.is_template = 0;
+
+ // Copy type attributes (e.g. has_drop)
+ i->type_info = type_new(TYPE_STRUCT);
+ i->type_info->name = xstrdup(m);
+ if (t->struct_node->type_info)
+ {
+ i->type_info->traits = t->struct_node->type_info->traits;
+ i->type_info->is_restrict = t->struct_node->type_info->is_restrict;
+ }
+
// Use first generic param for substitution (single-param backward compat)
const char *gp = (t->struct_node->strct.generic_param_count > 0)
? t->struct_node->strct.generic_params[0]
@@ -2009,6 +2033,15 @@ void instantiate_generic(ParserContext *ctx, const char *tpl, const char *arg,
ASTNode *i = ast_create(NODE_ENUM);
i->enm.name = xstrdup(m);
i->enm.is_template = 0;
+
+ // Copy type attributes (e.g. has_drop)
+ i->type_info = type_new(TYPE_ENUM);
+ i->type_info->name = xstrdup(m);
+ if (t->struct_node->type_info)
+ {
+ i->type_info->traits = t->struct_node->type_info->traits;
+ }
+
ASTNode *h = 0, *tl = 0;
ASTNode *v = t->struct_node->enm.variants;
while (v)
diff --git a/std/cuda.zc b/std/cuda.zc
index 851acb3..dbb1fe6 100644
--- a/std/cuda.zc
+++ b/std/cuda.zc
@@ -1,5 +1,7 @@
include <cuda_runtime.h>
+import "./string.zc"
+import "./mem.zc"
// Memory Management.
@@ -97,3 +99,86 @@ fn cuda_last_error() -> int {
fn cuda_ok() -> bool {
return cuda_last_error() == 0;
}
+
+
+raw {
+ void _z_cuda_get_props(int dev, char* name, size_t* total_mem, int* sm_count, int* major, int* minor, int* max_threads, int* warp_size) {
+ struct cudaDeviceProp prop;
+ if (cudaGetDeviceProperties(&prop, dev) == 0) {
+ strcpy(name, prop.name);
+ *total_mem = prop.totalGlobalMem;
+ *sm_count = prop.multiProcessorCount;
+ *major = prop.major;
+ *minor = prop.minor;
+ *max_threads = prop.maxThreadsPerBlock;
+ *warp_size = prop.warpSize;
+ }
+ }
+}
+
+extern fn _z_cuda_get_props(dev: int, name: char*, mem: usize*, sm: int*, maj: int*, min: int*, max_t: int*, warp: int*);
+
+struct CudaDeviceProp {
+ name: String;
+ total_global_mem: usize;
+ multi_processor_count: int;
+ major: int;
+ minor: int;
+ max_threads_per_block: int;
+ warp_size: int;
+}
+
+struct CudaMemInfo {
+ free: usize;
+ total: usize;
+}
+
+fn cuda_device_properties(device_id: int) -> CudaDeviceProp {
+ var mem: usize = 0;
+ var sm: int = 0;
+ var maj: int = 0;
+ var min: int = 0;
+ var max_t: int = 0;
+ var warp: int = 0;
+
+ var name_ptr = alloc_n<char>(256);
+ name_ptr[0] = 0;
+
+ _z_cuda_get_props(device_id, name_ptr, &mem, &sm, &maj, &min, &max_t, &warp);
+
+ var s = String::new(name_ptr);
+ free(name_ptr);
+
+ return CudaDeviceProp {
+ name: s,
+ total_global_mem: mem,
+ multi_processor_count: sm,
+ major: maj,
+ minor: min,
+ max_threads_per_block: max_t,
+ warp_size: warp
+ };
+}
+
+fn cuda_driver_version() -> int {
+ var d: int = 0;
+ cudaDriverGetVersion(&d);
+ return d;
+}
+
+fn cuda_runtime_version() -> int {
+ var r: int = 0;
+ cudaRuntimeGetVersion(&r);
+ return r;
+}
+
+fn cuda_mem_info() -> CudaMemInfo {
+ var f: usize = 0;
+ var t: usize = 0;
+ cudaMemGetInfo(&f, &t);
+ return CudaMemInfo { free: f, total: t };
+}
+
+fn cuda_device_reset() {
+ cudaDeviceReset();
+}
diff --git a/std/vec.zc b/std/vec.zc
index 1d9e6e1..be4dc05 100644
--- a/std/vec.zc
+++ b/std/vec.zc
@@ -14,6 +14,30 @@ struct VecIter<T> {
idx: usize;
}
+struct VecIterResult<T> {
+ ptr: T*;
+}
+
+impl VecIterResult<T> {
+ fn is_none(self) -> bool {
+ return self.ptr == 0;
+ }
+
+ fn unwrap(self) -> T* {
+ if (self.ptr == 0) {
+ !"Panic: unwrap called on null VecIterResult";
+ exit(1);
+ }
+ return self.ptr;
+ }
+}
+
+struct VecIterRef<T> {
+ data: T*;
+ count: usize;
+ idx: usize;
+}
+
impl VecIter<T> {
fn next(self) -> Option<T> {
if (self.idx < self.count) {
@@ -23,6 +47,25 @@ impl VecIter<T> {
}
return Option<T>::None();
}
+
+ fn iterator(self) -> VecIter<T> {
+ return *self;
+ }
+}
+
+impl VecIterRef<T> {
+ fn next(self) -> VecIterResult<T> {
+ if (self.idx < self.count) {
+ var item = &self.data[self.idx];
+ self.idx = self.idx + 1;
+ return VecIterResult<T> { ptr: item };
+ }
+ return VecIterResult<T> { ptr: 0 };
+ }
+
+ fn iterator(self) -> VecIterRef<T> {
+ return *self;
+ }
}
impl Vec<T> {
@@ -30,6 +73,23 @@ impl Vec<T> {
return Vec<T> { data: 0, len: 0, cap: 0 };
}
+ fn with_capacity(cap: usize) -> Vec<T> {
+ if (cap == 0) {
+ return Vec<T> { data: 0, len: 0, cap: 0 };
+ }
+ return Vec<T> {
+ data: (T*)malloc(cap * sizeof(T)),
+ len: 0,
+ cap: cap
+ };
+ }
+
+ fn grow(self) {
+ if (self.cap == 0) { self.cap = 8; }
+ else { self.cap = self.cap * 2; }
+ self.data = (T*)realloc(self.data, self.cap * sizeof(T));
+ }
+
fn iterator(self) -> VecIter<T> {
return VecIter<T> {
data: self.data,
@@ -37,16 +97,21 @@ impl Vec<T> {
idx: 0
};
}
+
+ fn iter_ref(self) -> VecIterRef<T> {
+ return VecIterRef<T> {
+ data: self.data,
+ count: self.len,
+ idx: 0
+ };
+ }
fn push(self, item: T) {
if (self.len >= self.cap) {
- if (self.cap == 0) { self.cap = 8;
- }
- else { self.cap = self.cap * 2;
- }
- self.data = realloc(self.data, self.cap * sizeof(T));
+ self.grow();
}
self.data[self.len] = item;
+ self.data[self.len] = item;
self.len = self.len + 1;
}
@@ -56,11 +121,7 @@ impl Vec<T> {
exit(1);
}
if (self.len >= self.cap) {
- if (self.cap == 0) { self.cap = 8;
- }
- else { self.cap = self.cap * 2;
- }
- self.data = realloc(self.data, self.cap * sizeof(T));
+ self.grow();
}
// Shift elements right
if (idx < self.len) {
@@ -79,6 +140,14 @@ impl Vec<T> {
return self.data[self.len];
}
+ fn pop_opt(self) -> Option<T> {
+ if (self.len == 0) {
+ return Option<T>::None();
+ }
+ self.len = self.len - 1;
+ return Option<T>::Some(self.data[self.len]);
+ }
+
fn remove(self, idx: usize) -> T {
if (idx >= self.len) {
!"Panic: Remove index out of bounds";
@@ -176,12 +245,26 @@ impl Vec<T> {
}
fn clone(self) -> Vec<T> {
- var new_vec: Vec<T> = Vec<T>::new();
+ if (self.len == 0) {
+ return Vec<T> { data: 0, len: 0, cap: 0 };
+ }
+ var new_data = (T*)malloc(self.len * sizeof(T));
var i: usize = 0;
while i < self.len {
- new_vec.push(self.data[i]);
+ new_data[i] = self.data[i];
i = i + 1;
}
- return new_vec;
+ return Vec<T> {
+ data: new_data,
+ len: self.len,
+ cap: self.len // Set capacity to exact length
+ };
+ // No local Vec variable means no Drop is called here.
+ }
+}
+
+impl Drop for Vec {
+ fn drop(self) {
+ self.free();
}
}
diff --git a/tests/collections/test_vec_suite.zc b/tests/collections/test_vec_suite.zc
deleted file mode 100644
index 9722972..0000000
--- a/tests/collections/test_vec_suite.zc
+++ /dev/null
@@ -1,177 +0,0 @@
-
-import "std.zc"
-
-@derive(Eq, Clone)
-struct Point {
- x: int;
- y: int;
-}
-
-test "test_vec_methods" {
- println "Testing Vec methods...";
-
- // Insert at beginning
- var v = Vec<int>::new();
- v.push(10);
- v.push(20);
- v.push(30);
- v.insert(0, 5);
-
- if (v.get(0) == 5 && v.get(1) == 10 && v.length() == 4) {
- println " -> insert(0, 5): Passed";
- } else {
- assert(false, "insert(0, 5) failed");
- }
-
- // Insert in middle
- v.insert(2, 15);
- if (v.get(2) == 15 && v.get(3) == 20 && v.length() == 5) {
- println " -> insert(2, 15): Passed";
- } else {
- assert(false, "insert(2, 15) failed");
- }
-
- // Insert at end
- v.insert(5, 35);
- if (v.get(5) == 35 && v.length() == 6) {
- println " -> insert(5, 35): Passed";
- } else {
- assert(false, "insert(5, 35) failed");
- }
-
- // Remove from beginning
- var removed = v.remove(0);
- if (removed == 5 && v.get(0) == 10 && v.length() == 5) {
- println " -> remove(0): Passed";
- } else {
- assert(false, "remove(0) failed");
- }
-
- // Remove from middle
- var removed2 = v.remove(1);
- if (removed2 == 15 && v.get(1) == 20 && v.length() == 4) {
- println " -> remove(1): Passed";
- } else {
- assert(false, "remove(1) failed");
- }
-
- // Remove from end
- var removed3 = v.remove(3);
- if (removed3 == 35 && v.length() == 3) {
- println " -> remove(3): Passed";
- } else {
- assert(false, "remove(3) failed");
- }
-
- // Verify final state
- if (v.get(0) == 10 && v.get(1) == 20 && v.get(2) == 30) {
- println " -> final state: Passed";
- } else {
- assert(false, "final state failed");
- }
-
- println "All Vec methods passed!";
-}
-
-test "test_vec_extensions" {
- println "Testing Vec extensions (pop, clear, etc)...";
- var v = Vec<int>::new();
- v.push(10);
- v.push(20);
- v.push(30);
-
- assert(v.length() == 3, "Length should be 3");
- assert(v.last() == 30, "Last should be 30");
-
- var popped = v.pop();
- println "Popped: {popped}";
- assert(popped == 30, "Popped value mismatch");
- assert(v.length() == 2, "Length after pop mismatch");
-
- assert(!v.is_empty(), "Vector should not be empty");
-
- v.clear();
- assert(v.is_empty(), "Vector should be empty after clear");
- assert(v.length() == 0, "Length should be 0");
-
- v.free();
-}
-
-test "test_vec_basic" {
- var v = Vec<int>::new();
- v.push(10);
- v.push(10);
- v.push(20);
- var v0 = v.get(0);
- var v1 = v.get(1);
- println "Vec: {v0}, {v1}";
-
- var s1 = String::from("Hello ");
- var s2 = String::from("World");
- var s3 = s1 + s2;
-
- println "{s3.c_str()}";
-}
-
-test "test_vec_clone" {
- var v = Vec<int>::new();
- v.push(10);
- v.push(20);
- v.push(30);
-
- println "Vec has {(int)v.len} elements";
- println "First: {v.first()}";
- println "Last: {v.last()}";
-
- v.free();
- "Done";
-}
-
-test "test_vec_contains" {
- println "Testing Vec::contains with structs...";
-
- var v = Vec<Point>::new();
- v.push(Point { x: 1, y: 2 });
- v.push(Point { x: 3, y: 4 });
-
- var p1 = Point { x: 1, y: 2 };
- if (v.contains(p1)) {
- println " -> contains((1, 2)): Passed";
- } else {
- assert(false, "contains({1, 2}) failed");
- }
-
- var p2 = Point { x: 3, y: 4 };
- if (v.contains(p2)) {
- println " -> contains((3, 4)): Passed";
- } else {
- assert(false, "contains({3, 4}) failed");
- }
-
- var p3 = Point { x: 5, y: 6 };
- if (!v.contains(p3)) {
- println " -> !contains((5, 6)): Passed";
- } else {
- assert(false, "!contains({5, 6}) failed");
- }
-
- var vi = Vec<int>::new();
- vi.push(10);
- vi.push(20);
-
- if (vi.contains(10)) {
- println " -> Vec<int>::contains(10): Passed";
- } else {
- assert(false, "Vec<int>::contains(10) failed");
- }
-
- if (!vi.contains(30)) {
- println " -> !Vec<int>::contains(30): Passed";
- } else {
- assert(false, "!Vec<int>::contains(30) failed");
- }
-
- v.free();
- vi.free();
- println "All tests passed!";
-}
diff --git a/tests/std/test_vec.zc b/tests/std/test_vec.zc
new file mode 100644
index 0000000..4787e06
--- /dev/null
+++ b/tests/std/test_vec.zc
@@ -0,0 +1,168 @@
+import "std/vec.zc"
+import "std/io.zc"
+
+// Helper for assertions
+fn assert_true(cond: bool, msg: char*) {
+ if (!cond) {
+ print "Assertion failed: {msg}\n";
+ exit(1);
+ }
+}
+
+fn assert_eq(a: int, b: int, msg: char*) {
+ if (a != b) {
+ print "Assertion failed: {msg} (Expected {a}, Got {b})\n";
+ exit(1);
+ }
+}
+
+@derive(Eq, Clone)
+struct Point {
+ x: int;
+ y: int;
+}
+
+test "Vec Basics (Construction, Push, Pop, Access)" {
+ print "Testing Vec basics...\n";
+ var v = Vec<int>::new();
+ assert_eq(v.len, 0, "Initial len");
+ assert_eq(v.cap, 0, "Initial cap");
+
+ v.push(10);
+ v.push(20);
+ v.push(30);
+
+ assert_eq(v.len, 3, "Len after push");
+ assert_eq(v.get(0), 10, "get(0)");
+ assert_eq(v.get(1), 20, "get(1)");
+ assert_eq(v.get(2), 30, "get(2)");
+ assert_eq(v.last(), 30, "last()");
+ assert_eq(v.first(), 10, "first()");
+
+ assert_eq(v.pop(), 30, "pop()");
+ assert_eq(v.len, 2, "Len after pop");
+
+ v.set(0, 99);
+ assert_eq(v.get(0), 99, "set()");
+
+ // Explicit clean up check (safe idempotent free)
+ v.free();
+ assert_eq(v.len, 0, "Len after free");
+}
+
+test "Vec Capacity and Allocation" {
+ print "Testing Vec capacity...\n";
+ // with_capacity
+ var v1 = Vec<int>::with_capacity(10);
+ assert_eq(v1.len, 0, "with_capacity len");
+ assert_eq(v1.cap, 10, "with_capacity cap");
+ v1.push(1);
+ assert_eq(v1.cap, 10, "Cap should not change yet");
+
+ // Implicit grow
+ var v2 = Vec<int>::new();
+ // Force grow logic: 0 -> 8 -> 16...
+ var i = 0;
+ while i < 9 {
+ v2.push(i);
+ i = i + 1;
+ }
+ assert_true(v2.cap >= 9, "Capacity grew to hold 9 items");
+ // Expected strategy: 0 -> 8 -> 16
+ assert_eq(v2.cap, 16, "Growth strategy check (8->16)");
+}
+
+test "Vec Modification (Insert, Remove, Clear)" {
+ print "Testing Vec modification...\n";
+ var v = Vec<int>::new();
+ v.push(1);
+ v.push(3);
+
+ v.insert(1, 2); // [1, 2, 3]
+ assert_eq(v.get(1), 2, "insert middle");
+ assert_eq(v.len, 3, "insert len");
+
+ var val = v.remove(0); // [2, 3]
+ assert_eq(val, 1, "remove return");
+ assert_eq(v.get(0), 2, "remove shift");
+ assert_eq(v.len, 2, "remove len");
+
+ v.clear();
+ assert_eq(v.len, 0, "clear len");
+ assert_true(v.is_empty(), "is_empty");
+}
+
+test "Vec Extensions (pop_opt)" {
+ print "Testing Vec extensions...\n";
+ var v = Vec<int>::new();
+ v.push(42);
+
+ var opt = v.pop_opt();
+ assert_true(!opt.is_none(), "pop_opt some");
+ assert_eq(opt.unwrap(), 42, "pop_opt val");
+
+ var empty = v.pop_opt();
+ assert_true(empty.is_none(), "pop_opt none");
+}
+
+test "Vec Iteration (Reference and Value)" {
+ print "Testing Vec iteration...\n";
+ var v = Vec<Point>::new();
+ v.push(Point { x: 10, y: 10 });
+ v.push(Point { x: 20, y: 20 });
+
+ // 1. Value Iteration
+ var sum_val = 0;
+ for p in v {
+ sum_val = sum_val + p.x;
+ }
+ assert_eq(sum_val, 30, "Value iteration sum");
+
+ // 2. Reference Iteration (Sugar &v) - In-place modification
+ for p in &v {
+ (*p).x = (*p).x + 1;
+ }
+ assert_eq(v.get(0).x, 11, "Ref iter mod 0");
+ assert_eq(v.get(1).x, 21, "Ref iter mod 1");
+
+ // 3. Explicit iter_ref()
+ for p in v.iter_ref() {
+ (*p).y = (*p).y + 2;
+ }
+ assert_eq(v.get(0).y, 12, "Explicit ref iter mod 0");
+ assert_eq(v.get(1).y, 22, "Explicit ref iter mod 1");
+}
+
+test "Vec Clone and Drop" {
+ print "Testing Vec clone and drop...\n";
+ var v = Vec<int>::new();
+ v.push(100);
+ v.push(200);
+
+ var v2 = v.clone();
+ assert_eq(v2.len, 2, "Clone len");
+ assert_eq(v2.get(0), 100, "Clone val 0");
+
+ v.set(0, 999);
+ assert_eq(v.get(0), 999, "Original mod");
+ assert_eq(v2.get(0), 100, "Clone independent");
+
+ // Drop is implicit at end of scope.
+ // We trust valgrind/previous verification for actual memory free.
+ // This test ensures no double-free crashes or logic errors.
+}
+
+test "Vec Utils (Reverse, Contains)" {
+ print "Testing Vec utils...\n";
+ var v = Vec<int>::new();
+ v.push(1);
+ v.push(2);
+ v.push(3);
+
+ v.reverse(); // [3, 2, 1]
+ assert_eq(v.get(0), 3, "Reverse 0");
+ assert_eq(v.get(2), 1, "Reverse 2");
+
+ assert_true(v.contains(2), "Contains true");
+ assert_true(!v.contains(99), "Contains false");
+}