Affix

 view release on metacpan or  search on metacpan

infix/src/core/arena.c  view on Meta::CPAN

        if (next_cap < size + alignment)
            next_cap = size + alignment;

        block->next_block = infix_arena_create(next_cap);
        if (!block->next_block) {
            block->error = true;
            return nullptr;
        }

        block = block->next_block;
    }
}
/**
 * @internal
 * @brief Allocates and zero-initializes a block of memory from an arena.
 *
 * This function is a convenience wrapper around `infix_arena_alloc` that also
 * ensures the allocated memory is set to zero, mimicking the behavior of `calloc`.
 * It includes a check for integer overflow on the `num * size` calculation and
 * will set a detailed error on failure.
 *
 * @param arena The arena to allocate from.
 * @param num The number of elements to allocate.
 * @param size The size of each element.
 * @param alignment The required alignment for the allocation. Must be a power of two.
 * @return A pointer to the zero-initialized memory, or `nullptr` on failure.
 */
INFIX_API c23_nodiscard void * infix_arena_calloc(infix_arena_t * arena, size_t num, size_t size, size_t alignment) {
    // Security: Check for multiplication overflow.
    if (size > 0 && num > SIZE_MAX / size) {
        if (arena)
            arena->error = true;
        _infix_set_error(INFIX_CATEGORY_GENERAL, INFIX_CODE_INTEGER_OVERFLOW, 0);
        return nullptr;
    }
    size_t total_size = num * size;
    void * ptr = infix_arena_alloc(arena, total_size, alignment);
    if (ptr != nullptr)
        memset(ptr, 0, total_size);
    return ptr;
}

/**
 * @brief Captures the current allocation state of an arena chain.
 */
INFIX_API c23_nodiscard infix_arena_mark_t infix_arena_get_mark(infix_arena_t * arena) {
    infix_arena_mark_t mark = {nullptr, 0};
    if (arena == nullptr)
        return mark;

    infix_arena_t * current = arena;
    while (current->next_block != nullptr && current->next_block->current_offset > 0)
        current = current->next_block;
    mark.block = current;
    mark.offset = current->current_offset;
    return mark;
}

/**
 * @brief Rewinds an arena chain back to a previously captured mark,
 * resetting all secondary blocks for immediate reuse.
 */
INFIX_API void infix_arena_rewind(infix_arena_t * arena, infix_arena_mark_t mark) {
    if (arena == nullptr || mark.block == nullptr)
        return;

    // Reset offset in the marked block
    mark.block->current_offset = mark.offset;
    mark.block->error = false;

    // Reset offsets in all subsequent blocks so they can be reused
    infix_arena_t * current = mark.block->next_block;
    while (current != nullptr) {
        current->current_offset = 0;
        current->error = false;
        current = current->next_block;
    }
}



( run in 0.627 second using v1.01-cache-2.11-cpan-d01c6094234 )