/* slide_hash.c -- slide hash table C implementation
 *
 * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler
 * For conditions of distribution and use, see copyright notice in zlib.h
 */

#include "zbuild.h"
#include "arch_functions.h"

#ifdef SLIDE_HASH_FALLBACK

#include "deflate.h"

/* ===========================================================================
 * Slide the hash table when sliding the window down (could be avoided with 32
 * bit values at the expense of memory usage). We slide even when level == 0 to
 * keep the hash table consistent if we switch back to level > 0 later.
 */
static inline void slide_hash_c_chain(Pos *table, uint32_t entries, uint16_t wsize) {
#ifdef NOT_TWEAK_COMPILER
    table += entries;
    do {
        unsigned m;
        m = *--table;
        *table = (Pos)(m >= wsize ? m-wsize : 0);
        /* If entries is not on any hash chain, prev[entries] is garbage but
         * its value will never be used.
         */
    } while (--entries);
#else
    {
    /* As of I make this change, gcc (4.8.*) isn't able to vectorize
     * this hot loop using saturated-subtraction on x86-64 architecture.
     * To avoid this defect, we can change the loop such that
     *    o. the pointer advance forward, and
     *    o. demote the variable 'm' to be local to the loop, and
     *       choose type "Pos" (instead of 'unsigned int') for the
     *       variable to avoid unnecessary zero-extension.
     */
        unsigned int i;
        Pos *q = table;
        for (i = 0; i < entries; i++) {
            Pos m = *q;
            Pos t = (Pos)wsize;
            *q++ = (Pos)(m >= t ? m-t: 0);
        }
    }
#endif /* NOT_TWEAK_COMPILER */
}

Z_INTERNAL void slide_hash_c(deflate_state *s) {
    uint16_t wsize = (uint16_t)s->w_size;

    slide_hash_c_chain(s->head, HASH_SIZE, wsize);
    slide_hash_c_chain(s->prev, wsize, wsize);
}

#endif /* SLIDE_HASH_FALLBACK */
