xref: /netbsd-src/external/gpl3/gcc.old/dist/libstdc++-v3/libsupc++/hash_bytes.cc (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
11debfc3dSmrg // Definition of _Hash_bytes. -*- C++ -*-
21debfc3dSmrg 
3*8feb0f0bSmrg // Copyright (C) 2010-2020 Free Software Foundation, Inc.
41debfc3dSmrg //
51debfc3dSmrg // This file is part of the GNU ISO C++ Library.  This library is free
61debfc3dSmrg // software; you can redistribute it and/or modify it under the
71debfc3dSmrg // terms of the GNU General Public License as published by the
81debfc3dSmrg // Free Software Foundation; either version 3, or (at your option)
91debfc3dSmrg // any later version.
101debfc3dSmrg 
111debfc3dSmrg // This library is distributed in the hope that it will be useful,
121debfc3dSmrg // but WITHOUT ANY WARRANTY; without even the implied warranty of
131debfc3dSmrg // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
141debfc3dSmrg // GNU General Public License for more details.
151debfc3dSmrg 
161debfc3dSmrg // Under Section 7 of GPL version 3, you are granted additional
171debfc3dSmrg // permissions described in the GCC Runtime Library Exception, version
181debfc3dSmrg // 3.1, as published by the Free Software Foundation.
191debfc3dSmrg 
201debfc3dSmrg // You should have received a copy of the GNU General Public License and
211debfc3dSmrg // a copy of the GCC Runtime Library Exception along with this program;
221debfc3dSmrg // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
231debfc3dSmrg // <http://www.gnu.org/licenses/>.
241debfc3dSmrg 
251debfc3dSmrg // This file defines Hash_bytes, a primitive used for defining hash
261debfc3dSmrg // functions. Based on public domain MurmurHashUnaligned2, by Austin
271debfc3dSmrg // Appleby.  http://murmurhash.googlepages.com/
281debfc3dSmrg 
291debfc3dSmrg // This file also defines _Fnv_hash_bytes, another primitive with
301debfc3dSmrg // exactly the same interface but using a different hash algorithm,
311debfc3dSmrg // Fowler / Noll / Vo (FNV) Hash (type FNV-1a). The Murmur hash
321debfc3dSmrg // function apears to be better in both speed and hash quality, and
331debfc3dSmrg // FNV is provided primarily for backward compatibility.
341debfc3dSmrg 
351debfc3dSmrg #include <bits/hash_bytes.h>
361debfc3dSmrg 
371debfc3dSmrg namespace
381debfc3dSmrg {
391debfc3dSmrg   inline std::size_t
unaligned_load(const char * p)401debfc3dSmrg   unaligned_load(const char* p)
411debfc3dSmrg   {
421debfc3dSmrg     std::size_t result;
431debfc3dSmrg     __builtin_memcpy(&result, p, sizeof(result));
441debfc3dSmrg     return result;
451debfc3dSmrg   }
461debfc3dSmrg 
471debfc3dSmrg #if __SIZEOF_SIZE_T__ == 8
481debfc3dSmrg   // Loads n bytes, where 1 <= n < 8.
491debfc3dSmrg   inline std::size_t
load_bytes(const char * p,int n)501debfc3dSmrg   load_bytes(const char* p, int n)
511debfc3dSmrg   {
521debfc3dSmrg     std::size_t result = 0;
531debfc3dSmrg     --n;
541debfc3dSmrg     do
551debfc3dSmrg       result = (result << 8) + static_cast<unsigned char>(p[n]);
561debfc3dSmrg     while (--n >= 0);
571debfc3dSmrg     return result;
581debfc3dSmrg   }
591debfc3dSmrg 
601debfc3dSmrg   inline std::size_t
shift_mix(std::size_t v)611debfc3dSmrg   shift_mix(std::size_t v)
621debfc3dSmrg   { return v ^ (v >> 47);}
631debfc3dSmrg #endif
641debfc3dSmrg }
651debfc3dSmrg 
661debfc3dSmrg namespace std
671debfc3dSmrg {
681debfc3dSmrg _GLIBCXX_BEGIN_NAMESPACE_VERSION
691debfc3dSmrg 
701debfc3dSmrg #if __SIZEOF_SIZE_T__ == 4
711debfc3dSmrg 
721debfc3dSmrg   // Implementation of Murmur hash for 32-bit size_t.
731debfc3dSmrg   size_t
_Hash_bytes(const void * ptr,size_t len,size_t seed)741debfc3dSmrg   _Hash_bytes(const void* ptr, size_t len, size_t seed)
751debfc3dSmrg   {
761debfc3dSmrg     const size_t m = 0x5bd1e995;
771debfc3dSmrg     size_t hash = seed ^ len;
781debfc3dSmrg     const char* buf = static_cast<const char*>(ptr);
791debfc3dSmrg 
801debfc3dSmrg     // Mix 4 bytes at a time into the hash.
811debfc3dSmrg     while(len >= 4)
821debfc3dSmrg       {
831debfc3dSmrg 	size_t k = unaligned_load(buf);
841debfc3dSmrg 	k *= m;
851debfc3dSmrg 	k ^= k >> 24;
861debfc3dSmrg 	k *= m;
871debfc3dSmrg 	hash *= m;
881debfc3dSmrg 	hash ^= k;
891debfc3dSmrg 	buf += 4;
901debfc3dSmrg 	len -= 4;
911debfc3dSmrg       }
921debfc3dSmrg 
931debfc3dSmrg     // Handle the last few bytes of the input array.
941debfc3dSmrg     switch(len)
951debfc3dSmrg       {
961debfc3dSmrg       case 3:
971debfc3dSmrg 	hash ^= static_cast<unsigned char>(buf[2]) << 16;
981debfc3dSmrg 	[[gnu::fallthrough]];
991debfc3dSmrg       case 2:
1001debfc3dSmrg 	hash ^= static_cast<unsigned char>(buf[1]) << 8;
1011debfc3dSmrg 	[[gnu::fallthrough]];
1021debfc3dSmrg       case 1:
1031debfc3dSmrg 	hash ^= static_cast<unsigned char>(buf[0]);
1041debfc3dSmrg 	hash *= m;
1051debfc3dSmrg       };
1061debfc3dSmrg 
1071debfc3dSmrg     // Do a few final mixes of the hash.
1081debfc3dSmrg     hash ^= hash >> 13;
1091debfc3dSmrg     hash *= m;
1101debfc3dSmrg     hash ^= hash >> 15;
1111debfc3dSmrg     return hash;
1121debfc3dSmrg   }
1131debfc3dSmrg 
1141debfc3dSmrg   // Implementation of FNV hash for 32-bit size_t.
1151debfc3dSmrg   // N.B. This function should work on unsigned char, otherwise it does not
1161debfc3dSmrg   // correctly implement the FNV-1a algorithm (see PR59406).
1171debfc3dSmrg   // The existing behaviour is retained for backwards compatibility.
1181debfc3dSmrg   size_t
_Fnv_hash_bytes(const void * ptr,size_t len,size_t hash)1191debfc3dSmrg   _Fnv_hash_bytes(const void* ptr, size_t len, size_t hash)
1201debfc3dSmrg   {
1211debfc3dSmrg     const char* cptr = static_cast<const char*>(ptr);
1221debfc3dSmrg     for (; len; --len)
1231debfc3dSmrg       {
1241debfc3dSmrg 	hash ^= static_cast<size_t>(*cptr++);
1251debfc3dSmrg 	hash *= static_cast<size_t>(16777619UL);
1261debfc3dSmrg       }
1271debfc3dSmrg     return hash;
1281debfc3dSmrg   }
1291debfc3dSmrg 
1301debfc3dSmrg #elif __SIZEOF_SIZE_T__ == 8
1311debfc3dSmrg 
1321debfc3dSmrg   // Implementation of Murmur hash for 64-bit size_t.
1331debfc3dSmrg   size_t
1341debfc3dSmrg   _Hash_bytes(const void* ptr, size_t len, size_t seed)
1351debfc3dSmrg   {
1361debfc3dSmrg     static const size_t mul = (((size_t) 0xc6a4a793UL) << 32UL)
1371debfc3dSmrg 			      + (size_t) 0x5bd1e995UL;
1381debfc3dSmrg     const char* const buf = static_cast<const char*>(ptr);
1391debfc3dSmrg 
1401debfc3dSmrg     // Remove the bytes not divisible by the sizeof(size_t).  This
1411debfc3dSmrg     // allows the main loop to process the data as 64-bit integers.
142a2dc1f3fSmrg     const size_t len_aligned = len & ~(size_t)0x7;
1431debfc3dSmrg     const char* const end = buf + len_aligned;
1441debfc3dSmrg     size_t hash = seed ^ (len * mul);
1451debfc3dSmrg     for (const char* p = buf; p != end; p += 8)
1461debfc3dSmrg       {
1471debfc3dSmrg 	const size_t data = shift_mix(unaligned_load(p) * mul) * mul;
1481debfc3dSmrg 	hash ^= data;
1491debfc3dSmrg 	hash *= mul;
1501debfc3dSmrg       }
1511debfc3dSmrg     if ((len & 0x7) != 0)
1521debfc3dSmrg       {
1531debfc3dSmrg 	const size_t data = load_bytes(end, len & 0x7);
1541debfc3dSmrg 	hash ^= data;
1551debfc3dSmrg 	hash *= mul;
1561debfc3dSmrg       }
1571debfc3dSmrg     hash = shift_mix(hash) * mul;
1581debfc3dSmrg     hash = shift_mix(hash);
1591debfc3dSmrg     return hash;
1601debfc3dSmrg   }
1611debfc3dSmrg 
1621debfc3dSmrg   // Implementation of FNV hash for 64-bit size_t.
1631debfc3dSmrg   // N.B. This function should work on unsigned char, otherwise it does not
1641debfc3dSmrg   // correctly implement the FNV-1a algorithm (see PR59406).
1651debfc3dSmrg   // The existing behaviour is retained for backwards compatibility.
1661debfc3dSmrg   size_t
1671debfc3dSmrg   _Fnv_hash_bytes(const void* ptr, size_t len, size_t hash)
1681debfc3dSmrg   {
1691debfc3dSmrg     const char* cptr = static_cast<const char*>(ptr);
1701debfc3dSmrg     for (; len; --len)
1711debfc3dSmrg       {
1721debfc3dSmrg 	hash ^= static_cast<size_t>(*cptr++);
1731debfc3dSmrg 	hash *= static_cast<size_t>(1099511628211ULL);
1741debfc3dSmrg       }
1751debfc3dSmrg     return hash;
1761debfc3dSmrg   }
1771debfc3dSmrg 
1781debfc3dSmrg #else
1791debfc3dSmrg 
1801debfc3dSmrg   // Dummy hash implementation for unusual sizeof(size_t).
1811debfc3dSmrg   size_t
1821debfc3dSmrg   _Hash_bytes(const void* ptr, size_t len, size_t seed)
1831debfc3dSmrg   {
1841debfc3dSmrg     size_t hash = seed;
1851debfc3dSmrg     const char* cptr = reinterpret_cast<const char*>(ptr);
1861debfc3dSmrg     for (; len; --len)
1871debfc3dSmrg       hash = (hash * 131) + *cptr++;
1881debfc3dSmrg     return hash;
1891debfc3dSmrg   }
1901debfc3dSmrg 
1911debfc3dSmrg   size_t
1921debfc3dSmrg   _Fnv_hash_bytes(const void* ptr, size_t len, size_t seed)
1931debfc3dSmrg   { return _Hash_bytes(ptr, len, seed); }
1941debfc3dSmrg 
1951debfc3dSmrg #endif /* __SIZEOF_SIZE_T__ */
1961debfc3dSmrg 
1971debfc3dSmrg _GLIBCXX_END_NAMESPACE_VERSION
1981debfc3dSmrg } // namespace
199