#pragma once
#ifndef MIMALLOC_TYPES_H
#define MIMALLOC_TYPES_H
#include <stdlib.h>
#include <stddef.h>
#include <stdint.h>
#if !defined(MI_SECURE)
#define MI_SECURE 0
#endif
#if !defined(MI_DEBUG)
#if !defined(NDEBUG) || defined(_DEBUG)
#define MI_DEBUG 1
#else
#define MI_DEBUG 0
#endif
#endif
#if INTPTR_MAX == 9223372036854775807LL
# define MI_INTPTR_SHIFT (3)
#elif INTPTR_MAX == 2147483647LL
# define MI_INTPTR_SHIFT (2)
#else
#error platform must be 32 or 64 bits
#endif
#define MI_INTPTR_SIZE (1<<MI_INTPTR_SHIFT)
#define MI_SMALL_PAGE_SHIFT (13 + MI_INTPTR_SHIFT)
#define MI_LARGE_PAGE_SHIFT ( 6 + MI_SMALL_PAGE_SHIFT)
#define MI_SEGMENT_SHIFT ( MI_LARGE_PAGE_SHIFT)
#define MI_SEGMENT_SIZE (1<<MI_SEGMENT_SHIFT)
#define MI_SEGMENT_MASK ((uintptr_t)MI_SEGMENT_SIZE - 1)
#define MI_SMALL_PAGE_SIZE (1<<MI_SMALL_PAGE_SHIFT)
#define MI_LARGE_PAGE_SIZE (1<<MI_LARGE_PAGE_SHIFT)
#define MI_SMALL_PAGES_PER_SEGMENT (MI_SEGMENT_SIZE/MI_SMALL_PAGE_SIZE)
#define MI_LARGE_PAGES_PER_SEGMENT (MI_SEGMENT_SIZE/MI_LARGE_PAGE_SIZE)
#define MI_LARGE_SIZE_MAX (MI_LARGE_PAGE_SIZE/8)
#define MI_LARGE_WSIZE_MAX (MI_LARGE_SIZE_MAX>>MI_INTPTR_SHIFT)
#define MI_BIN_HUGE (64U)
#define MI_MAX_ALIGN_SIZE 16
#if (MI_LARGE_WSIZE_MAX > 131072)
#error "define more bins"
#endif
typedef uintptr_t mi_encoded_t;
typedef struct mi_block_s {
mi_encoded_t next;
} mi_block_t;
typedef enum mi_delayed_e {
MI_NO_DELAYED_FREE = 0,
MI_USE_DELAYED_FREE,
MI_DELAYED_FREEING
} mi_delayed_t;
typedef union mi_page_flags_u {
uint16_t value;
struct {
bool has_aligned;
bool in_full;
};
} mi_page_flags_t;
typedef union mi_thread_free_u {
uintptr_t value;
struct {
mi_delayed_t delayed:2;
#if MI_INTPTR_SIZE==8
uintptr_t head:62; #elif MI_INTPTR_SIZE==4
uintptr_t head:30;
#endif
};
} mi_thread_free_t;
#define MI_TF_PTR_SHIFT (2)
typedef struct mi_page_s {
uint8_t segment_idx; bool segment_in_use:1; bool is_reset:1;
mi_page_flags_t flags;
uint16_t capacity; uint16_t reserved;
mi_block_t* free; uintptr_t cookie; size_t used;
mi_block_t* local_free; volatile uintptr_t thread_freed; volatile mi_thread_free_t thread_free;
size_t block_size; mi_heap_t* heap; struct mi_page_s* next; struct mi_page_s* prev;
#if MI_INTPTR_SIZE==8
#elif MI_INTPTR_SIZE==4
void* padding[1]; #endif
} mi_page_t;
typedef enum mi_page_kind_e {
MI_PAGE_SMALL, MI_PAGE_LARGE, MI_PAGE_HUGE } mi_page_kind_t;
typedef struct mi_segment_s {
struct mi_segment_s* next;
struct mi_segment_s* prev;
struct mi_segment_s* abandoned_next;
size_t abandoned; size_t used; size_t capacity; size_t segment_size; size_t segment_info_size; uintptr_t cookie;
size_t page_shift; uintptr_t thread_id; mi_page_kind_t page_kind; mi_page_t pages[1]; } mi_segment_t;
typedef struct mi_tld_s mi_tld_t;
typedef struct mi_page_queue_s {
mi_page_t* first;
mi_page_t* last;
size_t block_size;
} mi_page_queue_t;
#define MI_BIN_FULL (MI_BIN_HUGE+1)
struct mi_heap_s {
mi_tld_t* tld;
mi_page_t* pages_free_direct[MI_SMALL_WSIZE_MAX + 2]; mi_page_queue_t pages[MI_BIN_FULL + 1]; volatile mi_block_t* thread_delayed_free;
uintptr_t thread_id; uintptr_t cookie;
uintptr_t random; size_t page_count; bool no_reclaim; };
#define MI_DEBUG_UNINIT (0xD0)
#define MI_DEBUG_FREED (0xDF)
#if (MI_DEBUG)
void _mi_assert_fail(const char* assertion, const char* fname, unsigned int line, const char* func );
#define mi_assert(expr) ((expr) ? (void)0 : _mi_assert_fail(#expr,__FILE__,__LINE__,__func__))
#else
#define mi_assert(x)
#endif
#if (MI_DEBUG>1)
#define mi_assert_internal mi_assert
#else
#define mi_assert_internal(x)
#endif
#if (MI_DEBUG>2)
#define mi_assert_expensive mi_assert
#else
#define mi_assert_expensive(x)
#endif
#ifndef MI_STAT
#if (MI_DEBUG>0)
#define MI_STAT 2
#else
#define MI_STAT 0
#endif
#endif
typedef struct mi_stat_count_s {
int64_t allocated;
int64_t freed;
int64_t peak;
int64_t current;
} mi_stat_count_t;
typedef struct mi_stat_counter_s {
int64_t total;
int64_t count;
} mi_stat_counter_t;
typedef struct mi_stats_s {
mi_stat_count_t segments;
mi_stat_count_t pages;
mi_stat_count_t reserved;
mi_stat_count_t committed;
mi_stat_count_t reset;
mi_stat_count_t segments_abandoned;
mi_stat_count_t pages_abandoned;
mi_stat_count_t pages_extended;
mi_stat_count_t mmap_calls;
mi_stat_count_t mmap_right_align;
mi_stat_count_t mmap_ensure_aligned;
mi_stat_count_t threads;
mi_stat_count_t huge;
mi_stat_count_t malloc;
mi_stat_counter_t searches;
#if MI_STAT>1
mi_stat_count_t normal[MI_BIN_HUGE+1];
#endif
} mi_stats_t;
void _mi_stat_increase(mi_stat_count_t* stat, size_t amount);
void _mi_stat_decrease(mi_stat_count_t* stat, size_t amount);
void _mi_stat_counter_increase(mi_stat_counter_t* stat, size_t amount);
#if (MI_STAT)
#define mi_stat_increase(stat,amount) _mi_stat_increase( &(stat), amount)
#define mi_stat_decrease(stat,amount) _mi_stat_decrease( &(stat), amount)
#define mi_stat_counter_increase(stat,amount) _mi_stat_counter_increase( &(stat), amount)
#else
#define mi_stat_increase(stat,amount) (void)0
#define mi_stat_decrease(stat,amount) (void)0
#define mi_stat_counter_increase(stat,amount) (void)0
#endif
#define mi_heap_stat_increase(heap,stat,amount) mi_stat_increase( (heap)->tld->stats.stat, amount)
#define mi_heap_stat_decrease(heap,stat,amount) mi_stat_decrease( (heap)->tld->stats.stat, amount)
typedef struct mi_segment_queue_s {
mi_segment_t* first;
mi_segment_t* last;
} mi_segment_queue_t;
typedef struct mi_segments_tld_s {
mi_segment_queue_t small_free; size_t current_size; size_t peak_size; size_t cache_count; size_t cache_size; mi_segment_queue_t cache; mi_stats_t* stats; } mi_segments_tld_t;
typedef struct mi_os_tld_s {
uintptr_t mmap_next_probable; void* mmap_previous; uint8_t* pool; size_t pool_available; mi_stats_t* stats; } mi_os_tld_t;
struct mi_tld_s {
unsigned long long heartbeat; mi_heap_t* heap_backing; mi_segments_tld_t segments; mi_os_tld_t os; mi_stats_t stats; };
#endif