import { assert } from "../../assert.js";

/**
 * Note: produces valid hash values for `null` and `undefined`.
 * @param {string|null|undefined} string
 * @param {number} [start=0]
 * @param {number} [length] how many characters to hash, defaults to the rest of the string from `start`
 * @returns {number}
 */
export function computeStringHash(string, start, length) {
    if (string === null) {
        return 0;
    }

    if (string === undefined) {
        return 1;
    }

    assert.isString(string, 'string');

    let _start = start ?? 0;
    let _length = length ?? string.length - _start;

    let hash = _length;

    const end = _start + _length;

    for (let i = _start; i < end; i++) {
        const code_point = string.charCodeAt(i);

        /*
         * Avoiding potentially expensive multiplication operation by using 2 cheaper operation instead
         * (h<<5) - h ===  h*31
         */
        hash = ((hash << 5) - hash) + code_point;

    }

    // force uint32
    return hash >>> 0;
}
