glfwInitAllocator support
Some checks failed
CI / x86_64-linux (push) Failing after 5s
M1 / aarch64-macos (push) Has been cancelled
CI / x86_64-windows (push) Has been cancelled
CI / x86_64-macos (push) Has been cancelled

This commit is contained in:
FalsePattern 2025-02-14 01:17:31 +01:00
parent 06e281f918
commit 85f5287f22
Signed by: falsepattern
GPG key ID: E930CDEC50C50E23
2 changed files with 130 additions and 139 deletions

View file

@ -1,143 +1,121 @@
// TODO: implement custom allocator support const std = @import("std");
const c = @import("c.zig").c;
// /*! @brief const alignment = @alignOf(std.c.max_align_t);
// * const prefix_size = blk: {
// * @sa @ref init_allocator var n = alignment;
// * @sa @ref glfwInitAllocator while (n < @sizeOf(usize)) {
// * n += alignment;
// * @since Added in version 3.4. }
// * break :blk n;
// * @ingroup init };
// */
// typedef struct GLFWallocator
// {
// GLFWallocatefun allocate;
// GLFWreallocatefun reallocate;
// GLFWdeallocatefun deallocate;
// void* user;
// } GLFWallocator;
// /*! @brief The function pointer type for memory allocation callbacks.
// *
// * This is the function pointer type for memory allocation callbacks. A memory
// * allocation callback function has the following signature:
// * @code
// * void* function_name(size_t size, void* user)
// * @endcode
// *
// * This function must return either a memory block at least `size` bytes long,
// * or `NULL` if allocation failed. Note that not all parts of GLFW handle allocation
// * failures gracefully yet.
// *
// * This function may be called during @ref glfwInit but before the library is
// * flagged as initialized, as well as during @ref glfwTerminate after the
// * library is no longer flagged as initialized.
// *
// * Any memory allocated by this function will be deallocated during library
// * termination or earlier.
// *
// * The size will always be greater than zero. Allocations of size zero are filtered out
// * before reaching the custom allocator.
// *
// * @param[in] size The minimum size, in bytes, of the memory block.
// * @param[in] user The user-defined pointer from the allocator.
// * @return The address of the newly allocated memory block, or `NULL` if an
// * error occurred.
// *
// * @pointer_lifetime The returned memory block must be valid at least until it
// * is deallocated.
// *
// * @reentrancy This function should not call any GLFW function.
// *
// * @thread_safety This function may be called from any thread that calls GLFW functions.
// *
// * @sa @ref init_allocator
// * @sa @ref GLFWallocator
// *
// * @since Added in version 3.4.
// *
// * @ingroup init
// */
// typedef void* (* GLFWallocatefun)(size_t size, void* user);
// /*! @brief The function pointer type for memory reallocation callbacks. fn rawFromZig(buf: []align(alignment)u8, size: usize) [*]u8 {
// * const pfx = @as(*usize, @ptrCast(@alignCast(buf)));
// * This is the function pointer type for memory reallocation callbacks. pfx.* = size;
// * A memory reallocation callback function has the following signature: return @ptrCast(buf[prefix_size..]);
// * @code }
// * void* function_name(void* block, size_t size, void* user)
// * @endcode
// *
// * This function must return a memory block at least `size` bytes long, or
// * `NULL` if allocation failed. Note that not all parts of GLFW handle allocation
// * failures gracefully yet.
// *
// * This function may be called during @ref glfwInit but before the library is
// * flagged as initialized, as well as during @ref glfwTerminate after the
// * library is no longer flagged as initialized.
// *
// * Any memory allocated by this function will be deallocated during library
// * termination or earlier.
// *
// * The block address will never be `NULL` and the size will always be greater than zero.
// * Reallocations of a block to size zero are converted into deallocations. Reallocations
// * of `NULL` to a non-zero size are converted into regular allocations.
// *
// * @param[in] block The address of the memory block to reallocate.
// * @param[in] size The new minimum size, in bytes, of the memory block.
// * @param[in] user The user-defined pointer from the allocator.
// * @return The address of the newly allocated or resized memory block, or
// * `NULL` if an error occurred.
// *
// * @pointer_lifetime The returned memory block must be valid at least until it
// * is deallocated.
// *
// * @reentrancy This function should not call any GLFW function.
// *
// * @thread_safety This function may be called from any thread that calls GLFW functions.
// *
// * @sa @ref init_allocator
// * @sa @ref GLFWallocator
// *
// * @since Added in version 3.4.
// *
// * @ingroup init
// */
// typedef void* (* GLFWreallocatefun)(void* block, size_t size, void* user);
// /*! @brief The function pointer type for memory deallocation callbacks. fn zigFromRaw(memory: [*]u8) []align(alignment)u8 {
// * const ptr: [*]align(alignment)u8 = @alignCast(memory - prefix_size);
// * This is the function pointer type for memory deallocation callbacks. const pfx = @as(*usize, @ptrCast(ptr));
// * A memory deallocation callback function has the following signature: const content_size: usize = pfx.*;
// * @code const full_size: usize = content_size + prefix_size;
// * void function_name(void* block, void* user) return ptr[0..full_size];
// * @endcode }
// *
// * This function may deallocate the specified memory block. This memory block fn alloc(
// * will have been allocated with the same allocator. size: usize,
// * user: ?*anyopaque,
// * This function may be called during @ref glfwInit but before the library is ) callconv(.c) ?*anyopaque {
// * flagged as initialized, as well as during @ref glfwTerminate after the if (user == null)
// * library is no longer flagged as initialized. unreachable;
// * const allocator = @as(*const std.mem.Allocator, @ptrCast(@alignCast(user.?))).*;
// * The block address will never be `NULL`. Deallocations of `NULL` are filtered out return @ptrCast(doAlloc(allocator, size));
// * before reaching the custom allocator. }
// *
// * @param[in] block The address of the memory block to deallocate. fn doAlloc(
// * @param[in] user The user-defined pointer from the allocator. allocator: std.mem.Allocator,
// * size: usize,
// * @pointer_lifetime The specified memory block will not be accessed by GLFW ) ?[*]u8 {
// * after this function is called. const buf = allocator.allocAdvancedWithRetAddr(u8, alignment, size + prefix_size, @returnAddress()) catch return null;
// * return rawFromZig(buf, size);
// * @reentrancy This function should not call any GLFW function. }
// *
// * @thread_safety This function may be called from any thread that calls GLFW functions. fn realloc(
// * p_block: ?*anyopaque,
// * @sa @ref init_allocator size: usize,
// * @sa @ref GLFWallocator user: ?*anyopaque,
// * ) callconv(.c) ?*anyopaque {
// * @since Added in version 3.4. if (user == null)
// * unreachable;
// * @ingroup init const allocator = @as(*const std.mem.Allocator, @ptrCast(@alignCast(user.?))).*;
// */ if (p_block) |block| {
// typedef void (* GLFWdeallocatefun)(void* block, void* user); return @ptrCast(doRealloc(
allocator,
@ptrCast(block),
size,
));
} else {
return @ptrCast(doAlloc(
allocator,
size,
));
}
}
fn doRealloc(
allocator: std.mem.Allocator,
block: [*]u8,
size: usize,
) ?[*]u8 {
const old_buf = zigFromRaw(block);
const new_buf = allocator.reallocAdvanced(old_buf, size + prefix_size, @returnAddress()) catch return null;
return rawFromZig(new_buf, size);
}
fn free(
p_block: ?*anyopaque,
user: ?*anyopaque,
) callconv(.c) void {
if (user == null)
unreachable;
const allocator = @as(*const std.mem.Allocator, @ptrCast(@alignCast(user.?))).*;
if (p_block) |block| {
doFree(allocator, @ptrCast(block));
}
}
fn doFree(
allocator: std.mem.Allocator,
block: [*]u8,
) void {
const buf = zigFromRaw(block);
allocator.free(buf);
}
/// Sets the allocator to the desired value.
/// To use the default allocator, call this function with a `null` argument.
///
/// @param zig_allocator The allocator to use at the next initialization, or
/// `null` to use the default one.
///
/// Possible errors include glfw.ErrorCode.InvalidValue.
///
/// The provided allocator pointer must stay valid until glfw is deinitialized,
/// or initAllocator is called with a new pointer while glfw is not initialized.
///
/// @thread_safety This function must only be called from the main thread.
pub inline fn initAllocator(allocator: ?*const std.mem.Allocator) void {
if (allocator) |zig_allocator| {
c.glfwInitAllocator(&.{
.allocate = alloc,
.reallocate = realloc,
.deallocate = free,
.user = @ptrCast(@constCast(zig_allocator)),
});
} else {
c.glfwInitAllocator(null);
}
}

View file

@ -9,6 +9,8 @@ const errors = @import("errors.zig");
/// Possible value for various window hints, etc. /// Possible value for various window hints, etc.
pub const dont_care = c.GLFW_DONT_CARE; pub const dont_care = c.GLFW_DONT_CARE;
pub const initAllocator = @import("allocator.zig").initAllocator;
pub const getError = errors.getError; pub const getError = errors.getError;
pub const mustGetError = errors.mustGetError; pub const mustGetError = errors.mustGetError;
pub const getErrorCode = errors.getErrorCode; pub const getErrorCode = errors.getErrorCode;
@ -591,3 +593,14 @@ test "rawMouseMotionSupported" {
test "basic" { test "basic" {
try basicTest(); try basicTest();
} }
test "initAllocator" {
defer clearError();
const alloc = std.testing.allocator;
initAllocator(&alloc);
if (!init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{getErrorString()});
std.process.exit(1);
}
defer terminate();
}