Advanced Example¶
This example demonstrates advanced ZigX features including arrays, structs, and memory management.
Working with Arrays¶
src/lib.zig¶
const std = @import("std");
/// Sum all elements in an array
pub export fn sum_array(data: [*]const f64, len: usize) f64 {
var sum: f64 = 0;
for (0..len) |i| {
sum += data[i];
}
return sum;
}
/// Calculate mean of an array
pub export fn mean_array(data: [*]const f64, len: usize) f64 {
if (len == 0) return 0;
return sum_array(data, len) / @as(f64, @floatFromInt(len));
}
/// Calculate standard deviation
pub export fn std_dev(data: [*]const f64, len: usize) f64 {
if (len == 0) return 0;
const avg = mean_array(data, len);
var sum_sq: f64 = 0;
for (0..len) |i| {
const diff = data[i] - avg;
sum_sq += diff * diff;
}
return @sqrt(sum_sq / @as(f64, @floatFromInt(len)));
}
/// Scale all elements in-place
pub export fn scale_array(data: [*]f64, len: usize, factor: f64) void {
for (0..len) |i| {
data[i] *= factor;
}
}
/// Dot product of two arrays
pub export fn dot_product(a: [*]const f64, b: [*]const f64, len: usize) f64 {
var result: f64 = 0;
for (0..len) |i| {
result += a[i] * b[i];
}
return result;
}
/// Matrix multiplication (row-major order)
/// C[m×n] = A[m×k] × B[k×n]
pub export fn matrix_multiply(
a: [*]const f64,
b: [*]const f64,
c: [*]f64,
m: usize,
k: usize,
n: usize,
) void {
for (0..m) |i| {
for (0..n) |j| {
var sum: f64 = 0;
for (0..k) |l| {
sum += a[i * k + l] * b[l * n + j];
}
c[i * n + j] = sum;
}
}
}
/// Sort array in-place (quicksort)
pub export fn sort_array(data: [*]f64, len: usize) void {
if (len <= 1) return;
quicksort(data[0..len]);
}
fn quicksort(arr: []f64) void {
if (arr.len <= 1) return;
const pivot = arr[arr.len / 2];
var left: usize = 0;
var right: usize = arr.len - 1;
while (left <= right) {
while (arr[left] < pivot) left += 1;
while (arr[right] > pivot) right -= 1;
if (left <= right) {
const temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
left += 1;
if (right > 0) right -= 1;
}
}
if (right > 0) quicksort(arr[0..right + 1]);
if (left < arr.len) quicksort(arr[left..]);
}
Python Usage¶
import ctypes
import advanced_example
# Create arrays using ctypes
data = (ctypes.c_double * 10)(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)
# Statistical functions
print(f"Sum: {advanced_example.sum_array(data, 10)}")
print(f"Mean: {advanced_example.mean_array(data, 10)}")
print(f"Std Dev: {advanced_example.std_dev(data, 10):.4f}")
# In-place modification
advanced_example.scale_array(data, 10, 2.0)
print(f"Scaled: {list(data)}")
# Dot product
a = (ctypes.c_double * 3)(1.0, 2.0, 3.0)
b = (ctypes.c_double * 3)(4.0, 5.0, 6.0)
print(f"Dot product: {advanced_example.dot_product(a, b, 3)}")
# Matrix multiplication (2x3 × 3x2 = 2x2)
A = (ctypes.c_double * 6)(1, 2, 3, 4, 5, 6) # 2×3
B = (ctypes.c_double * 6)(7, 8, 9, 10, 11, 12) # 3×2
C = (ctypes.c_double * 4)() # 2×2 result
advanced_example.matrix_multiply(A, B, C, 2, 3, 2)
print(f"Matrix result: {list(C)}")
# Sorting
unsorted = (ctypes.c_double * 8)(3.14, 1.0, 4.15, 9.26, 5.35, 8.97, 2.0, 6.0)
advanced_example.sort_array(unsorted, 8)
print(f"Sorted: {list(unsorted)}")
Working with Strings¶
/// Count occurrences of a character
pub export fn count_char(s: [*:0]const u8, c: u8) usize {
var count: usize = 0;
var i: usize = 0;
while (s[i] != 0) : (i += 1) {
if (s[i] == c) count += 1;
}
return count;
}
/// Get string length
pub export fn string_length(s: [*:0]const u8) usize {
var len: usize = 0;
while (s[len] != 0) : (len += 1) {}
return len;
}
/// Convert string to uppercase in-place
pub export fn to_uppercase(s: [*:0]u8) void {
var i: usize = 0;
while (s[i] != 0) : (i += 1) {
if (s[i] >= 'a' and s[i] <= 'z') {
s[i] -= 32;
}
}
}
# String operations
text = b"Hello, World!"
print(f"Length: {advanced_example.string_length(text)}")
print(f"Count 'l': {advanced_example.count_char(text, ord('l'))}")
# In-place modification requires mutable buffer
buf = ctypes.create_string_buffer(b"hello world")
advanced_example.to_uppercase(buf)
print(f"Uppercase: {buf.value.decode()}")
Memory Management¶
const std = @import("std");
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
/// Allocate a buffer
pub export fn alloc_buffer(size: usize) ?[*]u8 {
const allocator = gpa.allocator();
const buf = allocator.alloc(u8, size) catch return null;
return buf.ptr;
}
/// Free a buffer
pub export fn free_buffer(ptr: [*]u8, size: usize) void {
const allocator = gpa.allocator();
allocator.free(ptr[0..size]);
}
/// Create and return a dynamically sized array
pub export fn create_range(start: i32, end: i32) ?[*]i32 {
if (end <= start) return null;
const allocator = gpa.allocator();
const size = @as(usize, @intCast(end - start));
const arr = allocator.alloc(i32, size) catch return null;
for (0..size) |i| {
arr[i] = start + @as(i32, @intCast(i));
}
return arr.ptr;
}
/// Get range size (for freeing)
pub export fn range_size(start: i32, end: i32) usize {
if (end <= start) return 0;
return @as(usize, @intCast(end - start));
}
/// Free a range array
pub export fn free_range(ptr: [*]i32, size: usize) void {
const allocator = gpa.allocator();
const slice = @as([*]u8, @ptrCast(ptr))[0 .. size * @sizeOf(i32)];
allocator.free(@as([]align(1) u8, @alignCast(slice)));
}
# Manual memory management
buf_ptr = advanced_example.alloc_buffer(1024)
if buf_ptr:
# Use the buffer...
advanced_example.free_buffer(buf_ptr, 1024)
# Dynamic arrays
start, end = 0, 10
ptr = advanced_example.create_range(start, end)
if ptr:
size = advanced_example.range_size(start, end)
# Access as array
arr = ctypes.cast(ptr, ctypes.POINTER(ctypes.c_int32 * size)).contents
print(f"Range: {list(arr)}")
# Free when done
advanced_example.free_range(ptr, size)
Warning
Always free allocated memory to prevent leaks!