#include "game_types.h"

/* Mem_Swap @ 0x08015E70 (real 110B) -- coroutine list surgery with indirect calls. Mirrors src/matched/Mem_Swap.c. */
/* Decrements p[7], returning early unless it hits 0. Then replaces the
   +24 link pointing at p (or the head q[0] itself) with p[6], calling
   Mem_CopyBytes when the chain misses or is empty. Follows with an indirect
   call through p[4] (SqrtFixed shape) unless it is null, skips the FillBytes
   of p[8] on a hash hit, and always fills p. The head q comes from an
   indirect call through the incoming r3 slot (trampoline convention). */
extern void Mem_CopyBytes(void);
extern int Collision_HasResult(int *p);
extern void Mem_FillBytes(int *p);

void Mem_Swap(int *p, int unused, int *(*getq)(void))
{
    int *q = getq();
    int *at;
    (void)unused;
    if (--p[7] != 0)
        return;
    if (q[0] == (int)p) {
        if (((unsigned char *)p)[20] == 0)
            return;
        at = q; /* head slot itself */
    } else if (q[0] == 0) {
        Mem_CopyBytes();
        at = q;
    } else {
        /* chase the +24 chain for p; a miss still stores after CopyBytes */
        int *node = (int *)q[0];
        at = q;
        for (;;) {
            int *next = *(int **)((char *)node + 24);
            at = (int *)((char *)node + 24);
            if (next == 0) {
                Mem_CopyBytes();
                break;
            }
            if (next == p)
                break;
            node = next;
        }
    }
    *at = p[6];
    if (p[4] != 0)
        ((void (*)(int, int))p[4])(p[2], 2);
    if (Collision_HasResult(p) == 0)
        Mem_FillBytes((int *)p[8]);
    Mem_FillBytes(p);
}
