#ifndef _FORWARDING_PTR_H_
#define _FORWARDING_PTR_H_

#include <stdbool.h>
#ifndef LISP_FEATURE_GENCGC
inline static bool
in_gc_p(void) {
    return current_dynamic_space == from_space;
}
#endif

#define FORWARDING_HEADER 1

inline static bool
forwarding_pointer_p(lispobj *pointer) {
#if defined LISP_FEATURE_64_BIT && defined LISP_FEATURE_LITTLE_ENDIAN
    /* Read exactly 1 byte. The upper bytes can store the original object size.
     * With other architectures we will need to pick a byte distinct from any widetag
     * and any pointer in the low N-LOWTAG-BITS */
    return *(char*)pointer == 1;
#else
    return (*pointer == FORWARDING_HEADER);
#endif
}

static inline lispobj
forwarding_pointer_value(lispobj *pointer) {
#ifdef LISP_FEATURE_GENCGC
    return pointer[1];
#else
    return pointer[0];
#endif
}
static inline void set_forwarding_pointer(lispobj *addr, lispobj newspace_copy) {
  // The object at 'addr' might already have been forwarded,
  // but that's ok. Such occurs primarily when dealing with
  // code components, because code can be forwarded by scavenging any
  // pointer to a function that resides within the code.
  // Testing whether the object had been forwarded would just slow
  // things down, so we blindly stomp on whatever was there.
  // Unfortunately this also implies we can't assert
  // that we're operating on a not-yet-forwarded object here.
#ifdef LISP_FEATURE_GENCGC
  //gc_dcheck(from_space_p(addr)); // inclusion order problem, too bad
    addr[0] = FORWARDING_HEADER;
    addr[1] = newspace_copy;
#else
    addr[0] = newspace_copy;
#endif
}
static inline void set_forwarding_pointer_resized(lispobj *addr, lispobj newspace_copy,
                                                  __attribute__((unused)) int old_nwords)
{
#if defined LISP_FEATURE_64_BIT && defined LISP_FEATURE_LITTLE_ENDIAN
    addr[0] = FORWARDING_HEADER | (old_nwords<<N_WIDETAG_BITS);
    addr[1] = newspace_copy;
#else
    set_forwarding_pointer(addr, newspace_copy);
#endif
}

/// Chase the pointer in 'word' if it points to a forwarded object.
static inline lispobj follow_maybe_fp(lispobj word)
{
    return (is_lisp_pointer(word) && forwarding_pointer_p(native_pointer(word)))
        ? forwarding_pointer_value(native_pointer(word)) : word;
}
/// As above, but 'ptr' MUST be a pointer.
static inline lispobj follow_fp(lispobj ptr)
{
  return forwarding_pointer_p(native_pointer(ptr))
      ? forwarding_pointer_value(native_pointer(ptr)) : ptr;
}

#endif
