# Advanced Memory Handling

The allocation scheme used in libmpdec allows for mixing statically and dynamically allocated decimals. If a decimal with a static coefficient needs to grow beyond the fixed array size, the coefficient automatically switches to dynamic memory. This is very fast in practice and eliminates the need for `alloca`.

It is not necessary to read this section if only dynamically allocated decimals are used.

## Static and Dynamic Decimals

Static and dynamic decimals may be mixed freely. In particular, they may be used in the position of the result operand or passed as an argument to `mpd_del`.

The coefficient of a static decimal must have the size `MPD_MINALLOC_MAX` (see below).

> `MPD_STATIC` | if set, the `mpd_t` struct is static
> `MPD_STATIC_DATA` | if set, the coefficient is static

## Shared and Constant Decimals

The coefficient of a decimal can be marked shared or constant. Decimals with such coefficients must not be result operands or passed to `mpd_del`. Since these flags are intended for internal use, the memory reallocation functions only check for their presence using `assert`.

> `MPD_SHARED_DATA` | if set, the coefficient is shared
> `MPD_CONST_DATA` | if set, the coefficient is constant

## MPD_MINALLOC

In order to avoid frequent resizing operations, the global variable `MPD_MINALLOC` guarantees a minimum amount of allocated words for the coefficient of each `mpd_t`. The variable can be set once at program start and all memory functions respect it. The minimum value for `MPD_MINALLOC` is `MPD_MINALLOC_MIN=2`, the maximum value is `MPD_MINALLOC_MAX=64`.

    void mpd_setminalloc(mpd_ssize_t n);

At program start, set `MPD_MINALLOC` to n. If n is outside the limits, the function prints an error and exits. If an attempt is made to set `MPD_MINALLOC` a second time, the function does nothing but print a warning.

## Resizing Decimals

When writing functions that operate directly on the data of a decimal, it is necessary to resize the coefficient. All the above functions may be called on static decimals, since they are smart enough to allocate dynamic storage if the static array is too small. The functions must not be called on constant or shared decimals.

    int mpd_qresize(mpd_t *result, mpd_ssize_t size, uint32_t *status);
    int mpd_resize(mpd_t *result, mpd_ssize_t size, mpd_context_t *ctx);

    int mpd_qresize_zero(mpd_t *result, mpd_ssize_t size, uint32_t *status);
    int mpd_resize_zero(mpd_t *result, mpd_ssize_t size, mpd_context_t *ctx);

`mpd_qresize` tries to resize result to size words. If the size is increased, the existing coefficient data is left untouched. On success, 1 is returned. On failure, 0 is returned and `MPD_Malloc_error` is added to the status parameter.

`mpd_qresize_zero` is the same, but initializes the complete coefficient - including the old memory area - to zero.

    void mpd_minalloc(mpd_t *result);

Reduce the size of the coefficient to `MPD_MINALLOC` words. This function cannot fail.

## Custom Allocation Functions

    extern void *(* mpd_mallocfunc)(size_t size);
    extern void *(* mpd_callocfunc)(size_t nmemb, size_t size);
    extern void *(* mpd_reallocfunc)(void *ptr, size_t size);
    extern void (* mpd_free)(void *ptr);

At program start, these variables can be set to custom memory allocation functions. By default, they are set to the standard C functions.

    void *mpd_alloc(mpd_size_t nmemb, mpd_size_t size);
    void *mpd_calloc(mpd_size_t nmemb, mpd_size_t size);

Memory allocation with overflow checking, using the custom allocation functions. If the allocation fails, `NULL` is returned.

In the overflow case, the functions print an error and exit. Note that overflow can only happen due to a serious programming error, like using a context with invalid values.

    void *mpd_realloc(void *ptr, mpd_size_t nmemb, mpd_size_t size,
                      uint8_t *err);

If successful, return the pointer to the new memory area. Otherwise, return ptr and set err to 1.

Overflow handling as above.

    /* struct hack alloc */
    void *mpd_sh_alloc(mpd_size_t struct_size, mpd_size_t nmemb,
                       mpd_size_t size);

Like `mpd_alloc`, with an additional parameter for struct hack allocations.