xref: /freebsd-12.1/contrib/llvm/lib/Support/DJB.cpp (revision 4ba319b5)
1*4ba319b5SDimitry Andric //===-- Support/DJB.cpp ---DJB Hash -----------------------------*- C++ -*-===//
2*4ba319b5SDimitry Andric //
3*4ba319b5SDimitry Andric //                     The LLVM Compiler Infrastructure
4*4ba319b5SDimitry Andric //
5*4ba319b5SDimitry Andric // This file is distributed under the University of Illinois Open Source
6*4ba319b5SDimitry Andric // License. See LICENSE.TXT for details.
7*4ba319b5SDimitry Andric //
8*4ba319b5SDimitry Andric //===----------------------------------------------------------------------===//
9*4ba319b5SDimitry Andric //
10*4ba319b5SDimitry Andric // This file contains support for the DJ Bernstein hash function.
11*4ba319b5SDimitry Andric //
12*4ba319b5SDimitry Andric //===----------------------------------------------------------------------===//
13*4ba319b5SDimitry Andric 
14*4ba319b5SDimitry Andric #include "llvm/Support/DJB.h"
15*4ba319b5SDimitry Andric #include "llvm/ADT/ArrayRef.h"
16*4ba319b5SDimitry Andric #include "llvm/Support/Compiler.h"
17*4ba319b5SDimitry Andric #include "llvm/Support/ConvertUTF.h"
18*4ba319b5SDimitry Andric #include "llvm/Support/Unicode.h"
19*4ba319b5SDimitry Andric 
20*4ba319b5SDimitry Andric using namespace llvm;
21*4ba319b5SDimitry Andric 
chopOneUTF32(StringRef & Buffer)22*4ba319b5SDimitry Andric static UTF32 chopOneUTF32(StringRef &Buffer) {
23*4ba319b5SDimitry Andric   UTF32 C;
24*4ba319b5SDimitry Andric   const UTF8 *const Begin8Const =
25*4ba319b5SDimitry Andric       reinterpret_cast<const UTF8 *>(Buffer.begin());
26*4ba319b5SDimitry Andric   const UTF8 *Begin8 = Begin8Const;
27*4ba319b5SDimitry Andric   UTF32 *Begin32 = &C;
28*4ba319b5SDimitry Andric 
29*4ba319b5SDimitry Andric   // In lenient mode we will always end up with a "reasonable" value in C for
30*4ba319b5SDimitry Andric   // non-empty input.
31*4ba319b5SDimitry Andric   assert(!Buffer.empty());
32*4ba319b5SDimitry Andric   ConvertUTF8toUTF32(&Begin8, reinterpret_cast<const UTF8 *>(Buffer.end()),
33*4ba319b5SDimitry Andric                      &Begin32, &C + 1, lenientConversion);
34*4ba319b5SDimitry Andric   Buffer = Buffer.drop_front(Begin8 - Begin8Const);
35*4ba319b5SDimitry Andric   return C;
36*4ba319b5SDimitry Andric }
37*4ba319b5SDimitry Andric 
toUTF8(UTF32 C,MutableArrayRef<UTF8> Storage)38*4ba319b5SDimitry Andric static StringRef toUTF8(UTF32 C, MutableArrayRef<UTF8> Storage) {
39*4ba319b5SDimitry Andric   const UTF32 *Begin32 = &C;
40*4ba319b5SDimitry Andric   UTF8 *Begin8 = Storage.begin();
41*4ba319b5SDimitry Andric 
42*4ba319b5SDimitry Andric   // The case-folded output should always be a valid unicode character, so use
43*4ba319b5SDimitry Andric   // strict mode here.
44*4ba319b5SDimitry Andric   ConversionResult CR = ConvertUTF32toUTF8(&Begin32, &C + 1, &Begin8,
45*4ba319b5SDimitry Andric                                            Storage.end(), strictConversion);
46*4ba319b5SDimitry Andric   assert(CR == conversionOK && "Case folding produced invalid char?");
47*4ba319b5SDimitry Andric   (void)CR;
48*4ba319b5SDimitry Andric   return StringRef(reinterpret_cast<char *>(Storage.begin()),
49*4ba319b5SDimitry Andric                    Begin8 - Storage.begin());
50*4ba319b5SDimitry Andric }
51*4ba319b5SDimitry Andric 
foldCharDwarf(UTF32 C)52*4ba319b5SDimitry Andric static UTF32 foldCharDwarf(UTF32 C) {
53*4ba319b5SDimitry Andric   // DWARF v5 addition to the unicode folding rules.
54*4ba319b5SDimitry Andric   // Fold "Latin Small Letter Dotless I" and "Latin Capital Letter I With Dot
55*4ba319b5SDimitry Andric   // Above" into "i".
56*4ba319b5SDimitry Andric   if (C == 0x130 || C == 0x131)
57*4ba319b5SDimitry Andric     return 'i';
58*4ba319b5SDimitry Andric   return sys::unicode::foldCharSimple(C);
59*4ba319b5SDimitry Andric }
60*4ba319b5SDimitry Andric 
caseFoldingDjbHashCharSlow(StringRef & Buffer,uint32_t H)61*4ba319b5SDimitry Andric static uint32_t caseFoldingDjbHashCharSlow(StringRef &Buffer, uint32_t H) {
62*4ba319b5SDimitry Andric   UTF32 C = chopOneUTF32(Buffer);
63*4ba319b5SDimitry Andric 
64*4ba319b5SDimitry Andric   C = foldCharDwarf(C);
65*4ba319b5SDimitry Andric 
66*4ba319b5SDimitry Andric   std::array<UTF8, UNI_MAX_UTF8_BYTES_PER_CODE_POINT> Storage;
67*4ba319b5SDimitry Andric   StringRef Folded = toUTF8(C, Storage);
68*4ba319b5SDimitry Andric   return djbHash(Folded, H);
69*4ba319b5SDimitry Andric }
70*4ba319b5SDimitry Andric 
caseFoldingDjbHash(StringRef Buffer,uint32_t H)71*4ba319b5SDimitry Andric uint32_t llvm::caseFoldingDjbHash(StringRef Buffer, uint32_t H) {
72*4ba319b5SDimitry Andric   while (!Buffer.empty()) {
73*4ba319b5SDimitry Andric     unsigned char C = Buffer.front();
74*4ba319b5SDimitry Andric     if (LLVM_LIKELY(C <= 0x7f)) {
75*4ba319b5SDimitry Andric       // US-ASCII, encoded as one character in utf-8.
76*4ba319b5SDimitry Andric       // This is by far the most common case, so handle this specially.
77*4ba319b5SDimitry Andric       if (C >= 'A' && C <= 'Z')
78*4ba319b5SDimitry Andric         C = 'a' + (C - 'A'); // fold uppercase into lowercase
79*4ba319b5SDimitry Andric       H = (H << 5) + H + C;
80*4ba319b5SDimitry Andric       Buffer = Buffer.drop_front();
81*4ba319b5SDimitry Andric       continue;
82*4ba319b5SDimitry Andric     }
83*4ba319b5SDimitry Andric     H = caseFoldingDjbHashCharSlow(Buffer, H);
84*4ba319b5SDimitry Andric   }
85*4ba319b5SDimitry Andric   return H;
86*4ba319b5SDimitry Andric }
87