Struct tidy_sys::_TidyAllocatorVtbl
source · #[repr(C)]pub struct _TidyAllocatorVtbl {
pub alloc: Option<unsafe extern "C" fn(self_: *mut TidyAllocator, nBytes: usize) -> *mut c_void>,
pub realloc: Option<unsafe extern "C" fn(self_: *mut TidyAllocator, block: *mut c_void, nBytes: usize) -> *mut c_void>,
pub free: Option<unsafe extern "C" fn(self_: *mut TidyAllocator, block: *mut c_void)>,
pub panic: Option<unsafe extern "C" fn(self_: *mut TidyAllocator, msg: ctmbstr)>,
}
Expand description
//** @defgroup Memory Memory Allocation
Tidy can use a user-provided allocator for all memory allocations. If this
allocator is not provided, then a default allocator is used which simply
wraps standard C malloc()/free() calls. These wrappers call the panic()
function upon any failure. The default panic function prints an out of
memory message to stderr, and calls exit(2)
.
For applications in which it is unacceptable to abort in the case of memory
allocation, then the panic function can be replaced with one which
longjmps()
out of the LibTidy code. For this to clean up completely, you
should be careful not to use any Tidy methods that open files as these will
not be closed before panic()
is called.
Calling the xxxWithAllocator()
family (tidyCreateWithAllocator
,
tidyBufInitWithAllocator
, tidyBufAllocWithAllocator
) allow setting
custom allocators.
All parts of the document use the same allocator. Calls that require a user-provided buffer can optionally use a different allocator.
For reference in designing a plug-in allocator, most allocations made by LibTidy are less than 100 bytes, corresponding to attribute names and values, etc.
There is also an additional class of much larger allocations which are where most of the data from the lexer is stored. It is not currently possible to use a separate allocator for the lexer; this would be a useful extension.
In general, approximately 1/3rd of the memory used by LibTidy is freed during the parse, so if memory usage is an issue then an allocator that can reuse this memory is a good idea.
To create your own allocator, do something like the following: @code{.c} typedef struct _MyAllocator { TidyAllocator base; // …other custom allocator state… } MyAllocator;
void* MyAllocator_alloc(TidyAllocator *base, void *block, size_t nBytes) { MyAllocator self = (MyAllocator)base; // … } // etc.
static const TidyAllocatorVtbl MyAllocatorVtbl = { MyAllocator_alloc, MyAllocator_realloc, MyAllocator_free, MyAllocator_panic };
myAllocator allocator; TidyDoc doc;
allocator.base.vtbl = &MyAllocatorVtbl; //…initialise allocator specific state… doc = tidyCreateWithAllocator(&allocator); @endcode
Although this looks slightly long-winded, the advantage is that to create a custom allocator you simply need to set the vtbl pointer correctly. The vtbl itself can reside in static/global data, and hence does not need to be initialised each time an allocator is created, and furthermore the memory is shared amongst all created allocators.
@{
Fields§
§alloc: Option<unsafe extern "C" fn(self_: *mut TidyAllocator, nBytes: usize) -> *mut c_void>
§realloc: Option<unsafe extern "C" fn(self_: *mut TidyAllocator, block: *mut c_void, nBytes: usize) -> *mut c_void>
§free: Option<unsafe extern "C" fn(self_: *mut TidyAllocator, block: *mut c_void)>
§panic: Option<unsafe extern "C" fn(self_: *mut TidyAllocator, msg: ctmbstr)>
Trait Implementations§
source§impl Clone for _TidyAllocatorVtbl
impl Clone for _TidyAllocatorVtbl
source§fn clone(&self) -> _TidyAllocatorVtbl
fn clone(&self) -> _TidyAllocatorVtbl
1.0.0 · source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read more