/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright 2010-2015 Danny Robson <danny@nerdcruft.net>
 */

#ifndef __UTIL_HASH_WANG_HPP
#define __UTIL_HASH_WANG_HPP

#include <cstdint>

namespace cruft::hash {
    // Thomas Wang's integer mixing functions, ca 2007
    //-------------------------------------------------------------------------
    constexpr uint32_t
    wang (uint32_t key)
    {
        // a prime or an odd constant
        constexpr uint32_t c2 = 0x27d4eb2d;

        key = (key ^ 61) ^ (key >> 16);
        key =  key       + (key <<  3);
        key =  key       ^ (key >>  4);
        key =  key       * c2;
        key =  key       ^ (key >> 15);

        return key;
    }


    //-------------------------------------------------------------------------
    constexpr uint64_t
    wang (uint64_t key)
    {
        key = ~key + (key << 21); // key = (key << 21) - key - 1;
        key =  key ^ (key >> 24);
        key = (key + (key <<  3)) + (key << 8); // key * 265
        key =  key ^ (key >> 14);
        key = (key + (key <<  2)) + (key << 4); // key * 21
        key =  key ^ (key >> 28);
        key =  key + (key << 31);

        return key;
    }
}

#endif