mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-05-25 06:18:37 +00:00
Rename the shared library visibility macro from GHOSTTY_EXPORT to GHOSTTY_API across all public C headers. This applies to both the libghostty-vt headers under include/ghostty/vt/ and the main include/ghostty.h header. This is a bit more idiomatic compared to other C libs and addresses the fact that we're not always exporting...
256 lines
10 KiB
C
256 lines
10 KiB
C
/**
|
|
* @file allocator.h
|
|
*
|
|
* Memory management interface for libghostty-vt.
|
|
*/
|
|
|
|
#ifndef GHOSTTY_VT_ALLOCATOR_H
|
|
#define GHOSTTY_VT_ALLOCATOR_H
|
|
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <ghostty/vt/types.h>
|
|
|
|
/** @defgroup allocator Memory Management
|
|
*
|
|
* libghostty-vt does require memory allocation for various operations,
|
|
* but is resilient to allocation failures and will gracefully handle
|
|
* out-of-memory situations by returning error codes.
|
|
*
|
|
* The exact memory management semantics are documented in the relevant
|
|
* functions and data structures.
|
|
*
|
|
* libghostty-vt uses explicit memory allocation via an allocator
|
|
* interface provided by GhosttyAllocator. The interface is based on the
|
|
* [Zig](https://ziglang.org) allocator interface, since this has been
|
|
* shown to be a flexible and powerful interface in practice and enables
|
|
* a wide variety of allocation strategies.
|
|
*
|
|
* **For the common case, you can pass NULL as the allocator for any
|
|
* function that accepts one,** and libghostty will use a default allocator.
|
|
* The default allocator will be libc malloc/free if libc is linked.
|
|
* Otherwise, a custom allocator is used (currently Zig's SMP allocator)
|
|
* that doesn't require any external dependencies.
|
|
*
|
|
* ## Basic Usage
|
|
*
|
|
* For simple use cases, you can ignore this interface entirely by passing NULL
|
|
* as the allocator parameter to functions that accept one. This will use the
|
|
* default allocator (typically libc malloc/free, if libc is linked, but
|
|
* we provide our own default allocator if libc isn't linked).
|
|
*
|
|
* To use a custom allocator:
|
|
* 1. Implement the GhosttyAllocatorVtable function pointers
|
|
* 2. Create a GhosttyAllocator struct with your vtable and context
|
|
* 3. Pass the allocator to functions that accept one
|
|
*
|
|
* ## Alloc/Free Helpers
|
|
*
|
|
* ghostty_alloc() and ghostty_free() provide a simple malloc/free-style
|
|
* interface for allocating and freeing byte buffers through the library's
|
|
* allocator. These are useful when:
|
|
*
|
|
* - You need to allocate a buffer to pass into a libghostty-vt function
|
|
* (e.g. preparing input data for ghostty_terminal_vt_write()).
|
|
* - You need to free a buffer returned by a libghostty-vt function
|
|
* (e.g. the output of ghostty_formatter_format_alloc()).
|
|
* - You are on a platform where the library's internal allocator differs
|
|
* from the consumer's C runtime (e.g. Windows, where Zig's libc and
|
|
* MSVC's CRT maintain separate heaps), so calling the standard C
|
|
* free() on library-allocated memory would be undefined behavior.
|
|
*
|
|
* Always use the same allocator (or NULL) for both the allocation and
|
|
* the corresponding free.
|
|
*
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* Function table for custom memory allocator operations.
|
|
*
|
|
* This vtable defines the interface for a custom memory allocator. All
|
|
* function pointers must be valid and non-NULL.
|
|
*
|
|
* @ingroup allocator
|
|
*
|
|
* If you're not going to use a custom allocator, you can ignore all of
|
|
* this. All functions that take an allocator pointer allow NULL to use a
|
|
* default allocator.
|
|
*
|
|
* The interface is based on the Zig allocator interface. I'll say up front
|
|
* that it is easy to look at this interface and think "wow, this is really
|
|
* overcomplicated". The reason for this complexity is well thought out by
|
|
* the Zig folks, and it enables a diverse set of allocation strategies
|
|
* as shown by the Zig ecosystem. As a consolation, please note that many
|
|
* of the arguments are only needed for advanced use cases and can be
|
|
* safely ignored in simple implementations. For example, if you look at
|
|
* the Zig implementation of the libc allocator in `lib/std/heap.zig`
|
|
* (search for CAllocator), you'll see it is very simple.
|
|
*
|
|
* We chose to align with the Zig allocator interface because:
|
|
*
|
|
* 1. It is a proven interface that serves a wide variety of use cases
|
|
* in the real world via the Zig ecosystem. It's shown to work.
|
|
*
|
|
* 2. Our core implementation itself is Zig, and this lets us very
|
|
* cheaply and easily convert between C and Zig allocators.
|
|
*
|
|
* NOTE(mitchellh): In the future, we can have default implementations of
|
|
* resize/remap and allow those to be null.
|
|
*/
|
|
typedef struct {
|
|
/**
|
|
* Return a pointer to `len` bytes with specified `alignment`, or return
|
|
* `NULL` indicating the allocation failed.
|
|
*
|
|
* @param ctx The allocator context
|
|
* @param len Number of bytes to allocate
|
|
* @param alignment Required alignment for the allocation. Guaranteed to
|
|
* be a power of two between 1 and 16 inclusive.
|
|
* @param ret_addr First return address of the allocation call stack (0 if not provided)
|
|
* @return Pointer to allocated memory, or NULL if allocation failed
|
|
*/
|
|
void* (*alloc)(void *ctx, size_t len, uint8_t alignment, uintptr_t ret_addr);
|
|
|
|
/**
|
|
* Attempt to expand or shrink memory in place.
|
|
*
|
|
* `memory_len` must equal the length requested from the most recent
|
|
* successful call to `alloc`, `resize`, or `remap`. `alignment` must
|
|
* equal the same value that was passed as the `alignment` parameter to
|
|
* the original `alloc` call.
|
|
*
|
|
* `new_len` must be greater than zero.
|
|
*
|
|
* @param ctx The allocator context
|
|
* @param memory Pointer to the memory block to resize
|
|
* @param memory_len Current size of the memory block
|
|
* @param alignment Alignment (must match original allocation)
|
|
* @param new_len New requested size
|
|
* @param ret_addr First return address of the allocation call stack (0 if not provided)
|
|
* @return true if resize was successful in-place, false if relocation would be required
|
|
*/
|
|
bool (*resize)(void *ctx, void *memory, size_t memory_len, uint8_t alignment, size_t new_len, uintptr_t ret_addr);
|
|
|
|
/**
|
|
* Attempt to expand or shrink memory, allowing relocation.
|
|
*
|
|
* `memory_len` must equal the length requested from the most recent
|
|
* successful call to `alloc`, `resize`, or `remap`. `alignment` must
|
|
* equal the same value that was passed as the `alignment` parameter to
|
|
* the original `alloc` call.
|
|
*
|
|
* A non-`NULL` return value indicates the resize was successful. The
|
|
* allocation may have same address, or may have been relocated. In either
|
|
* case, the allocation now has size of `new_len`. A `NULL` return value
|
|
* indicates that the resize would be equivalent to allocating new memory,
|
|
* copying the bytes from the old memory, and then freeing the old memory.
|
|
* In such case, it is more efficient for the caller to perform the copy.
|
|
*
|
|
* `new_len` must be greater than zero.
|
|
*
|
|
* @param ctx The allocator context
|
|
* @param memory Pointer to the memory block to remap
|
|
* @param memory_len Current size of the memory block
|
|
* @param alignment Alignment (must match original allocation)
|
|
* @param new_len New requested size
|
|
* @param ret_addr First return address of the allocation call stack (0 if not provided)
|
|
* @return Pointer to resized memory (may be relocated), or NULL if manual copy is needed
|
|
*/
|
|
void* (*remap)(void *ctx, void *memory, size_t memory_len, uint8_t alignment, size_t new_len, uintptr_t ret_addr);
|
|
|
|
/**
|
|
* Free and invalidate a region of memory.
|
|
*
|
|
* `memory_len` must equal the length requested from the most recent
|
|
* successful call to `alloc`, `resize`, or `remap`. `alignment` must
|
|
* equal the same value that was passed as the `alignment` parameter to
|
|
* the original `alloc` call.
|
|
*
|
|
* @param ctx The allocator context
|
|
* @param memory Pointer to the memory block to free
|
|
* @param memory_len Size of the memory block
|
|
* @param alignment Alignment (must match original allocation)
|
|
* @param ret_addr First return address of the allocation call stack (0 if not provided)
|
|
*/
|
|
void (*free)(void *ctx, void *memory, size_t memory_len, uint8_t alignment, uintptr_t ret_addr);
|
|
} GhosttyAllocatorVtable;
|
|
|
|
/**
|
|
* Custom memory allocator.
|
|
*
|
|
* For functions that take an allocator pointer, a NULL pointer indicates
|
|
* that the default allocator should be used. The default allocator will
|
|
* be libc malloc/free if we're linking to libc. If libc isn't linked,
|
|
* a custom allocator is used (currently Zig's SMP allocator).
|
|
*
|
|
* @ingroup allocator
|
|
*
|
|
* Usage example:
|
|
* @code
|
|
* GhosttyAllocator allocator = {
|
|
* .vtable = &my_allocator_vtable,
|
|
* .ctx = my_allocator_state
|
|
* };
|
|
* @endcode
|
|
*/
|
|
typedef struct GhosttyAllocator {
|
|
/**
|
|
* Opaque context pointer passed to all vtable functions.
|
|
* This allows the allocator implementation to maintain state
|
|
* or reference external resources needed for memory management.
|
|
*/
|
|
void *ctx;
|
|
|
|
/**
|
|
* Pointer to the allocator's vtable containing function pointers
|
|
* for memory operations (alloc, resize, remap, free).
|
|
*/
|
|
const GhosttyAllocatorVtable *vtable;
|
|
} GhosttyAllocator;
|
|
|
|
/**
|
|
* Allocate a buffer of `len` bytes.
|
|
*
|
|
* Uses the provided allocator, or the default allocator if NULL is passed.
|
|
* The returned buffer must be freed with ghostty_free() using the same
|
|
* allocator.
|
|
*
|
|
* @param allocator Pointer to the allocator to use, or NULL for the default
|
|
* @param len Number of bytes to allocate
|
|
* @return Pointer to the allocated buffer, or NULL if allocation failed
|
|
*
|
|
* @ingroup allocator
|
|
*/
|
|
GHOSTTY_API uint8_t* ghostty_alloc(const GhosttyAllocator* allocator, size_t len);
|
|
|
|
/**
|
|
* Free memory that was allocated by a libghostty-vt function.
|
|
*
|
|
* Use this to free buffers returned by functions such as
|
|
* ghostty_formatter_format_alloc(). Pass the same allocator that was
|
|
* used for the allocation, or NULL if the default allocator was used.
|
|
*
|
|
* On platforms where the library's internal allocator differs from the
|
|
* consumer's C runtime (e.g. Windows, where Zig's libc and MSVC's CRT
|
|
* maintain separate heaps), calling the standard C free() on memory
|
|
* allocated by the library causes undefined behavior. This function
|
|
* guarantees the correct allocator is used regardless of platform.
|
|
*
|
|
* It is safe to pass a NULL pointer; the call is a no-op in that case.
|
|
*
|
|
* @param allocator Pointer to the allocator that was used to allocate the
|
|
* memory, or NULL if the default allocator was used
|
|
* @param ptr Pointer to the memory to free (may be NULL)
|
|
* @param len Length of the allocation in bytes (must match the original
|
|
* allocation size)
|
|
*
|
|
* @ingroup allocator
|
|
*/
|
|
GHOSTTY_API void ghostty_free(const GhosttyAllocator* allocator, uint8_t* ptr, size_t len);
|
|
|
|
/** @} */
|
|
|
|
#endif /* GHOSTTY_VT_ALLOCATOR_H */
|