const std = @import("std");

pub fn filter(comptime T: type, allocator: std.mem.Allocator, arr: []const T, predicate: fn (T) bool) ![]T {
    var result = std.ArrayList(T).init(allocator);
    defer result.deinit();
    
    for (arr) |item| {
        if (predicate(item)) {
            try result.append(item);
        }
    }
    
    return result.toOwnedSlice();
}

pub fn map(comptime T: type, comptime U: type, allocator: std.mem.Allocator, arr: []const T, mapper: fn (T) U) ![]U {
    var result = try allocator.alloc(U, arr.len);
    
    for (arr, 0..) |item, i| {
        result[i] = mapper(item);
    }
    
    return result;
}

pub fn find(comptime T: type, arr: []const T, value: T) ?usize {
    for (arr, 0..) |item, i| {
        if (item == value) {
            return i;
        }
    }
    return null;
}

pub fn reverse(comptime T: type, arr: []T) void {
    var i: usize = 0;
    var j: usize = arr.len - 1;
    
    while (i < j) {
        const temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
        i += 1;
        j -= 1;
    }
}

pub fn contains(comptime T: type, arr: []const T, value: T) bool {
    return find(T, arr, value) != null;
}