#ifndef JEMALLOC_INTERNAL_TYPES_H
#define JEMALLOC_INTERNAL_TYPES_H

#include "jemalloc/internal/quantum.h"

/* Processor / core id type. */
typedef int malloc_cpuid_t;

/* When realloc(non-null-ptr, 0) is called, what happens? */
enum zero_realloc_action_e {
	/* Realloc(ptr, 0) is free(ptr); return malloc(0); */
	zero_realloc_action_alloc = 0,
	/* Realloc(ptr, 0) is free(ptr); */
	zero_realloc_action_free = 1,
	/* Realloc(ptr, 0) aborts. */
	zero_realloc_action_abort = 2
};
typedef enum zero_realloc_action_e zero_realloc_action_t;

/* Signature of write callback. */
typedef void(write_cb_t)(void *, const char *);

enum malloc_init_e {
	malloc_init_uninitialized = 3,
	malloc_init_a0_initialized = 2,
	malloc_init_recursible = 1,
	malloc_init_initialized = 0 /* Common case --> jnz. */
};
typedef enum malloc_init_e malloc_init_t;

/*
 * Flags bits:
 *
 * a: arena
 * t: tcache
 * 0: unused
 * z: zero
 * n: alignment
 *
 * aaaaaaaa aaaatttt tttttttt 0znnnnnn
 */
#define MALLOCX_ARENA_BITS 12
#define MALLOCX_TCACHE_BITS 12
#define MALLOCX_LG_ALIGN_BITS 6
#define MALLOCX_ARENA_SHIFT 20
#define MALLOCX_TCACHE_SHIFT 8
#define MALLOCX_ARENA_MASK                                                     \
	((unsigned)(((1U << MALLOCX_ARENA_BITS) - 1) << MALLOCX_ARENA_SHIFT))
/* NB: Arena index bias decreases the maximum number of arenas by 1. */
#define MALLOCX_ARENA_LIMIT ((unsigned)((1U << MALLOCX_ARENA_BITS) - 1))
#define MALLOCX_TCACHE_MASK                                                    \
	((unsigned)(((1U << MALLOCX_TCACHE_BITS) - 1) << MALLOCX_TCACHE_SHIFT))
#define MALLOCX_TCACHE_MAX ((unsigned)((1U << MALLOCX_TCACHE_BITS) - 3))
#define MALLOCX_LG_ALIGN_MASK ((1 << MALLOCX_LG_ALIGN_BITS) - 1)
/* Use MALLOCX_ALIGN_GET() if alignment may not be specified in flags. */
#define MALLOCX_ALIGN_GET_SPECIFIED(flags)                                     \
	(ZU(1) << (flags & MALLOCX_LG_ALIGN_MASK))
#define MALLOCX_ALIGN_GET(flags)                                               \
	(MALLOCX_ALIGN_GET_SPECIFIED(flags) & (SIZE_T_MAX - 1))
#define MALLOCX_ZERO_GET(flags) ((bool)(flags & MALLOCX_ZERO))

#define MALLOCX_TCACHE_GET(flags)                                              \
	(((unsigned)((flags & MALLOCX_TCACHE_MASK) >> MALLOCX_TCACHE_SHIFT))   \
	    - 2)
#define MALLOCX_ARENA_GET(flags)                                               \
	(((unsigned)(((unsigned)flags) >> MALLOCX_ARENA_SHIFT)) - 1)

/* Smallest size class to support. */
#define TINY_MIN (1U << LG_TINY_MIN)

#define LONG ((size_t)(1U << LG_SIZEOF_LONG))
#define LONG_MASK (LONG - 1)

/* Return the smallest long multiple that is >= a. */
#define LONG_CEILING(a) (((a) + LONG_MASK) & ~LONG_MASK)

#define SIZEOF_PTR (1U << LG_SIZEOF_PTR)
#define PTR_MASK (SIZEOF_PTR - 1)

/* Return the smallest (void *) multiple that is >= a. */
#define PTR_CEILING(a) (((a) + PTR_MASK) & ~PTR_MASK)

/*
 * Maximum size of L1 cache line.  This is used to avoid cache line aliasing.
 * In addition, this controls the spacing of cacheline-spaced size classes.
 *
 * CACHELINE cannot be based on LG_CACHELINE because __declspec(align()) can
 * only handle raw constants.
 */
#define LG_CACHELINE 6
#define CACHELINE 64
#define CACHELINE_MASK (CACHELINE - 1)

/* Return the smallest cacheline multiple that is >= s. */
#define CACHELINE_CEILING(s) (((s) + CACHELINE_MASK) & ~CACHELINE_MASK)

/* Return the nearest aligned address at or below a. */
#define ALIGNMENT_ADDR2BASE(a, alignment)                                      \
	((void *)(((byte_t *)(a))                                              \
	    - (((uintptr_t)(a)) - ((uintptr_t)(a) & ((~(alignment)) + 1)))))

/* Return the offset between a and the nearest aligned address at or below a. */
#define ALIGNMENT_ADDR2OFFSET(a, alignment)                                    \
	((size_t)((uintptr_t)(a) & (alignment - 1)))

/* Return the smallest alignment multiple that is >= s. */
#define ALIGNMENT_CEILING(s, alignment)                                        \
	(((s) + (alignment - 1)) & ((~(alignment)) + 1))

/*
 * Return the nearest aligned address at or above a.
 *
 * While at first glance this would appear to be merely a more complicated
 * way to perform the same computation as `ALIGNMENT_CEILING`,
 * this has the important additional property of not concealing pointer
 * provenance from the compiler. See the block-comment on the
 * definition of `byte_t` for more details.
 */
#define ALIGNMENT_ADDR2CEILING(a, alignment)                                   \
	((void *)(((byte_t *)(a))                                              \
	    + (((((uintptr_t)(a)) + (alignment - 1)) & ((~(alignment)) + 1))   \
	        - ((uintptr_t)(a)))))

/* Declare a variable-length array. */
#if __STDC_VERSION__ < 199901L || defined(__STDC_NO_VLA__)
#	ifdef _MSC_VER
#		include <malloc.h>
#		define alloca _alloca
#	else
#		ifdef JEMALLOC_HAS_ALLOCA_H
#			include <alloca.h>
#		else
#			include <stdlib.h>
#		endif
#	endif
#	define VARIABLE_ARRAY_UNSAFE(type, name, count)                       \
		type *name = alloca(sizeof(type) * (count))
#else
#	define VARIABLE_ARRAY_UNSAFE(type, name, count) type name[(count)]
#endif
#define VARIABLE_ARRAY_SIZE_MAX 2048
#define VARIABLE_ARRAY(type, name, count)                                      \
	assert(sizeof(type) * (count) <= VARIABLE_ARRAY_SIZE_MAX);             \
	VARIABLE_ARRAY_UNSAFE(type, name, count)

#define CALLOC_MADVISE_THRESHOLD_DEFAULT (((size_t)1) << 23) /* 8 MB */

#endif /* JEMALLOC_INTERNAL_TYPES_H */
