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