#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)

#endif /* JEMALLOC_INTERNAL_TYPES_H */
