#ifndef MEMTAG_H
#define MEMTAG_H

#include "util.h"

#ifdef HAS_ARM_MTE
#include "arm_mte.h"
#define MEMTAG 1
// Note that bionic libc always reserves tag 0 via PR_MTE_TAG_MASK prctl
#define RESERVED_TAG 0
#define TAG_WIDTH 4
#endif

static inline void *untag_pointer(void *ptr) {
#ifdef HAS_ARM_MTE
    const uintptr_t mask = UINTPTR_MAX >> 8;
    return (void *) ((uintptr_t) ptr & mask);
#else
    return ptr;
#endif
}

static inline const void *untag_const_pointer(const void *ptr) {
#ifdef HAS_ARM_MTE
    const uintptr_t mask = UINTPTR_MAX >> 8;
    return (const void *) ((uintptr_t) ptr & mask);
#else
    return ptr;
#endif
}

static inline void *set_pointer_tag(void *ptr, u8 tag) {
#ifdef HAS_ARM_MTE
    return (void *) (((uintptr_t) tag << 56) | (uintptr_t) untag_pointer(ptr));
#else
    (void) tag;
    return ptr;
#endif
}

static inline u8 get_pointer_tag(void *ptr) {
#ifdef HAS_ARM_MTE
    return (((uintptr_t) ptr) >> 56) & 0xf;
#else
    (void) ptr;
    return 0;
#endif
}

#endif