native-vector-store 0.3.8 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -3
- package/binding.gyp +3 -2
- package/deps/parallel_hashmap/btree.h +4076 -0
- package/deps/parallel_hashmap/meminfo.h +195 -0
- package/deps/parallel_hashmap/phmap.h +5236 -0
- package/deps/parallel_hashmap/phmap_base.h +5115 -0
- package/deps/parallel_hashmap/phmap_bits.h +665 -0
- package/deps/parallel_hashmap/phmap_config.h +790 -0
- package/deps/parallel_hashmap/phmap_dump.h +335 -0
- package/deps/parallel_hashmap/phmap_fwd_decl.h +186 -0
- package/deps/parallel_hashmap/phmap_utils.h +407 -0
- package/docs/index.html +52 -3
- package/lib/index.d.ts +35 -1
- package/package.json +1 -1
- package/prebuilds/darwin-arm64/native-vector-store.node +0 -0
- package/prebuilds/darwin-x64/native-vector-store.node +0 -0
- package/prebuilds/linux-arm64/native-vector-store.node +0 -0
- package/prebuilds/linux-x64/native-vector-store.node +0 -0
- package/src/Makefile +26 -6
- package/src/binding.cc +185 -2
- package/src/english_abbreviations.h +197 -0
- package/src/english_dictionary.h +25185 -0
- package/src/english_punctuations.h +42 -0
- package/src/english_stop_words.h +434 -0
- package/src/simple_sentence_splitter.h +218 -0
- package/src/simple_tokenizer.cpp +92 -0
- package/src/simple_tokenizer.h +30 -0
- package/src/test_bm25.cpp +357 -0
- package/src/test_hybrid_search.cpp +496 -0
- package/src/vector_store.cpp +239 -3
- package/src/vector_store.h +52 -1
- package/src/vector_store_loader.cpp +1 -1
- package/src/vector_store_loader_adaptive.cpp +1 -1
- package/src/vector_store_loader_mmap.cpp +2 -2
- package/prebuilds/win32-x64/native-vector-store.node +0 -0
|
@@ -0,0 +1,665 @@
|
|
|
1
|
+
#if !defined(phmap_bits_h_guard_)
|
|
2
|
+
#define phmap_bits_h_guard_
|
|
3
|
+
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// Copyright (c) 2019, Gregory Popovitch - greg7mdp@gmail.com
|
|
6
|
+
//
|
|
7
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
// you may not use this file except in compliance with the License.
|
|
9
|
+
// You may obtain a copy of the License at
|
|
10
|
+
//
|
|
11
|
+
// https://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
//
|
|
13
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
// See the License for the specific language governing permissions and
|
|
17
|
+
// limitations under the License.
|
|
18
|
+
//
|
|
19
|
+
// Includes work from abseil-cpp (https://github.com/abseil/abseil-cpp)
|
|
20
|
+
// with modifications.
|
|
21
|
+
//
|
|
22
|
+
// Copyright 2018 The Abseil Authors.
|
|
23
|
+
//
|
|
24
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
25
|
+
// you may not use this file except in compliance with the License.
|
|
26
|
+
// You may obtain a copy of the License at
|
|
27
|
+
//
|
|
28
|
+
// https://www.apache.org/licenses/LICENSE-2.0
|
|
29
|
+
//
|
|
30
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
31
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
32
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
33
|
+
// See the License for the specific language governing permissions and
|
|
34
|
+
// limitations under the License.
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
|
|
37
|
+
// The following guarantees declaration of the byte swap functions
|
|
38
|
+
#ifdef _MSC_VER
|
|
39
|
+
#include <stdlib.h> // NOLINT(build/include)
|
|
40
|
+
#elif defined(__APPLE__)
|
|
41
|
+
// Mac OS X / Darwin features
|
|
42
|
+
#include <libkern/OSByteOrder.h>
|
|
43
|
+
#elif defined(__FreeBSD__)
|
|
44
|
+
#include <sys/endian.h>
|
|
45
|
+
#elif defined(__GLIBC__)
|
|
46
|
+
#include <byteswap.h> // IWYU pragma: export
|
|
47
|
+
#endif
|
|
48
|
+
|
|
49
|
+
#include <string.h>
|
|
50
|
+
#include <cstdint>
|
|
51
|
+
#include "phmap_config.h"
|
|
52
|
+
|
|
53
|
+
#ifdef _MSC_VER
|
|
54
|
+
#pragma warning(push)
|
|
55
|
+
#pragma warning(disable : 4514) // unreferenced inline function has been removed
|
|
56
|
+
#endif
|
|
57
|
+
|
|
58
|
+
// -----------------------------------------------------------------------------
|
|
59
|
+
// unaligned APIs
|
|
60
|
+
// -----------------------------------------------------------------------------
|
|
61
|
+
// Portable handling of unaligned loads, stores, and copies.
|
|
62
|
+
// On some platforms, like ARM, the copy functions can be more efficient
|
|
63
|
+
// then a load and a store.
|
|
64
|
+
// -----------------------------------------------------------------------------
|
|
65
|
+
|
|
66
|
+
#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) ||\
|
|
67
|
+
defined(MEMORY_SANITIZER)
|
|
68
|
+
#include <stdint.h>
|
|
69
|
+
|
|
70
|
+
extern "C" {
|
|
71
|
+
uint16_t __sanitizer_unaligned_load16(const void *p);
|
|
72
|
+
uint32_t __sanitizer_unaligned_load32(const void *p);
|
|
73
|
+
uint64_t __sanitizer_unaligned_load64(const void *p);
|
|
74
|
+
void __sanitizer_unaligned_store16(void *p, uint16_t v);
|
|
75
|
+
void __sanitizer_unaligned_store32(void *p, uint32_t v);
|
|
76
|
+
void __sanitizer_unaligned_store64(void *p, uint64_t v);
|
|
77
|
+
} // extern "C"
|
|
78
|
+
|
|
79
|
+
namespace phmap {
|
|
80
|
+
namespace bits {
|
|
81
|
+
|
|
82
|
+
inline uint16_t UnalignedLoad16(const void *p) {
|
|
83
|
+
return __sanitizer_unaligned_load16(p);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
inline uint32_t UnalignedLoad32(const void *p) {
|
|
87
|
+
return __sanitizer_unaligned_load32(p);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
inline uint64_t UnalignedLoad64(const void *p) {
|
|
91
|
+
return __sanitizer_unaligned_load64(p);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
inline void UnalignedStore16(void *p, uint16_t v) {
|
|
95
|
+
__sanitizer_unaligned_store16(p, v);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
inline void UnalignedStore32(void *p, uint32_t v) {
|
|
99
|
+
__sanitizer_unaligned_store32(p, v);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
inline void UnalignedStore64(void *p, uint64_t v) {
|
|
103
|
+
__sanitizer_unaligned_store64(p, v);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
} // namespace bits
|
|
107
|
+
} // namespace phmap
|
|
108
|
+
|
|
109
|
+
#define PHMAP_INTERNAL_UNALIGNED_LOAD16(_p) (phmap::bits::UnalignedLoad16(_p))
|
|
110
|
+
#define PHMAP_INTERNAL_UNALIGNED_LOAD32(_p) (phmap::bits::UnalignedLoad32(_p))
|
|
111
|
+
#define PHMAP_INTERNAL_UNALIGNED_LOAD64(_p) (phmap::bits::UnalignedLoad64(_p))
|
|
112
|
+
|
|
113
|
+
#define PHMAP_INTERNAL_UNALIGNED_STORE16(_p, _val) (phmap::bits::UnalignedStore16(_p, _val))
|
|
114
|
+
#define PHMAP_INTERNAL_UNALIGNED_STORE32(_p, _val) (phmap::bits::UnalignedStore32(_p, _val))
|
|
115
|
+
#define PHMAP_INTERNAL_UNALIGNED_STORE64(_p, _val) (phmap::bits::UnalignedStore64(_p, _val))
|
|
116
|
+
|
|
117
|
+
#else
|
|
118
|
+
|
|
119
|
+
namespace phmap {
|
|
120
|
+
namespace bits {
|
|
121
|
+
|
|
122
|
+
inline uint16_t UnalignedLoad16(const void *p) {
|
|
123
|
+
uint16_t t;
|
|
124
|
+
memcpy(&t, p, sizeof t);
|
|
125
|
+
return t;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
inline uint32_t UnalignedLoad32(const void *p) {
|
|
129
|
+
uint32_t t;
|
|
130
|
+
memcpy(&t, p, sizeof t);
|
|
131
|
+
return t;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
inline uint64_t UnalignedLoad64(const void *p) {
|
|
135
|
+
uint64_t t;
|
|
136
|
+
memcpy(&t, p, sizeof t);
|
|
137
|
+
return t;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
inline void UnalignedStore16(void *p, uint16_t v) { memcpy(p, &v, sizeof v); }
|
|
141
|
+
|
|
142
|
+
inline void UnalignedStore32(void *p, uint32_t v) { memcpy(p, &v, sizeof v); }
|
|
143
|
+
|
|
144
|
+
inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); }
|
|
145
|
+
|
|
146
|
+
} // namespace bits
|
|
147
|
+
} // namespace phmap
|
|
148
|
+
|
|
149
|
+
#define PHMAP_INTERNAL_UNALIGNED_LOAD16(_p) (phmap::bits::UnalignedLoad16(_p))
|
|
150
|
+
#define PHMAP_INTERNAL_UNALIGNED_LOAD32(_p) (phmap::bits::UnalignedLoad32(_p))
|
|
151
|
+
#define PHMAP_INTERNAL_UNALIGNED_LOAD64(_p) (phmap::bits::UnalignedLoad64(_p))
|
|
152
|
+
|
|
153
|
+
#define PHMAP_INTERNAL_UNALIGNED_STORE16(_p, _val) (phmap::bits::UnalignedStore16(_p, _val))
|
|
154
|
+
#define PHMAP_INTERNAL_UNALIGNED_STORE32(_p, _val) (phmap::bits::UnalignedStore32(_p, _val))
|
|
155
|
+
#define PHMAP_INTERNAL_UNALIGNED_STORE64(_p, _val) (phmap::bits::UnalignedStore64(_p, _val))
|
|
156
|
+
|
|
157
|
+
#endif
|
|
158
|
+
|
|
159
|
+
// -----------------------------------------------------------------------------
|
|
160
|
+
// File: optimization.h
|
|
161
|
+
// -----------------------------------------------------------------------------
|
|
162
|
+
|
|
163
|
+
#if defined(__pnacl__)
|
|
164
|
+
#define PHMAP_BLOCK_TAIL_CALL_OPTIMIZATION() if (volatile int x = 0) { (void)x; }
|
|
165
|
+
#elif defined(__clang__)
|
|
166
|
+
// Clang will not tail call given inline volatile assembly.
|
|
167
|
+
#define PHMAP_BLOCK_TAIL_CALL_OPTIMIZATION() __asm__ __volatile__("")
|
|
168
|
+
#elif defined(__GNUC__)
|
|
169
|
+
// GCC will not tail call given inline volatile assembly.
|
|
170
|
+
#define PHMAP_BLOCK_TAIL_CALL_OPTIMIZATION() __asm__ __volatile__("")
|
|
171
|
+
#elif defined(_MSC_VER)
|
|
172
|
+
#include <intrin.h>
|
|
173
|
+
// The __nop() intrinsic blocks the optimisation.
|
|
174
|
+
#define PHMAP_BLOCK_TAIL_CALL_OPTIMIZATION() __nop()
|
|
175
|
+
#else
|
|
176
|
+
#define PHMAP_BLOCK_TAIL_CALL_OPTIMIZATION() if (volatile int x = 0) { (void)x; }
|
|
177
|
+
#endif
|
|
178
|
+
|
|
179
|
+
#if defined(__GNUC__)
|
|
180
|
+
// Cache line alignment
|
|
181
|
+
#if defined(__i386__) || defined(__x86_64__)
|
|
182
|
+
#define PHMAP_CACHELINE_SIZE 64
|
|
183
|
+
#elif defined(__powerpc64__)
|
|
184
|
+
#define PHMAP_CACHELINE_SIZE 128
|
|
185
|
+
#elif defined(__aarch64__)
|
|
186
|
+
// We would need to read special register ctr_el0 to find out L1 dcache size.
|
|
187
|
+
// This value is a good estimate based on a real aarch64 machine.
|
|
188
|
+
#define PHMAP_CACHELINE_SIZE 64
|
|
189
|
+
#elif defined(__arm__)
|
|
190
|
+
// Cache line sizes for ARM: These values are not strictly correct since
|
|
191
|
+
// cache line sizes depend on implementations, not architectures. There
|
|
192
|
+
// are even implementations with cache line sizes configurable at boot
|
|
193
|
+
// time.
|
|
194
|
+
#if defined(__ARM_ARCH_5T__)
|
|
195
|
+
#define PHMAP_CACHELINE_SIZE 32
|
|
196
|
+
#elif defined(__ARM_ARCH_7A__)
|
|
197
|
+
#define PHMAP_CACHELINE_SIZE 64
|
|
198
|
+
#endif
|
|
199
|
+
#endif
|
|
200
|
+
|
|
201
|
+
#ifndef PHMAP_CACHELINE_SIZE
|
|
202
|
+
// A reasonable default guess. Note that overestimates tend to waste more
|
|
203
|
+
// space, while underestimates tend to waste more time.
|
|
204
|
+
#define PHMAP_CACHELINE_SIZE 64
|
|
205
|
+
#endif
|
|
206
|
+
|
|
207
|
+
#define PHMAP_CACHELINE_ALIGNED __attribute__((aligned(PHMAP_CACHELINE_SIZE)))
|
|
208
|
+
#elif defined(_MSC_VER)
|
|
209
|
+
#define PHMAP_CACHELINE_SIZE 64
|
|
210
|
+
#define PHMAP_CACHELINE_ALIGNED __declspec(align(PHMAP_CACHELINE_SIZE))
|
|
211
|
+
#else
|
|
212
|
+
#define PHMAP_CACHELINE_SIZE 64
|
|
213
|
+
#define PHMAP_CACHELINE_ALIGNED
|
|
214
|
+
#endif
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
#if PHMAP_HAVE_BUILTIN(__builtin_expect) || \
|
|
218
|
+
(defined(__GNUC__) && !defined(__clang__))
|
|
219
|
+
#define PHMAP_PREDICT_FALSE(x) (__builtin_expect(x, 0))
|
|
220
|
+
#define PHMAP_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
|
|
221
|
+
#else
|
|
222
|
+
#define PHMAP_PREDICT_FALSE(x) (x)
|
|
223
|
+
#define PHMAP_PREDICT_TRUE(x) (x)
|
|
224
|
+
#endif
|
|
225
|
+
|
|
226
|
+
// -----------------------------------------------------------------------------
|
|
227
|
+
// File: bits.h
|
|
228
|
+
// -----------------------------------------------------------------------------
|
|
229
|
+
|
|
230
|
+
#if defined(_MSC_VER)
|
|
231
|
+
// We can achieve something similar to attribute((always_inline)) with MSVC by
|
|
232
|
+
// using the __forceinline keyword, however this is not perfect. MSVC is
|
|
233
|
+
// much less aggressive about inlining, and even with the __forceinline keyword.
|
|
234
|
+
#define PHMAP_BASE_INTERNAL_FORCEINLINE __forceinline
|
|
235
|
+
#else
|
|
236
|
+
// Use default attribute inline.
|
|
237
|
+
#define PHMAP_BASE_INTERNAL_FORCEINLINE inline PHMAP_ATTRIBUTE_ALWAYS_INLINE
|
|
238
|
+
#endif
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
namespace phmap {
|
|
242
|
+
|
|
243
|
+
#if defined(__GNUC__)
|
|
244
|
+
#pragma GCC diagnostic push
|
|
245
|
+
#pragma GCC diagnostic ignored "-Wpedantic"
|
|
246
|
+
#endif
|
|
247
|
+
|
|
248
|
+
#ifdef PHMAP_HAVE_INTRINSIC_INT128
|
|
249
|
+
__extension__ typedef unsigned __int128 phmap_uint128;
|
|
250
|
+
inline uint64_t umul128(uint64_t a, uint64_t b, uint64_t* high)
|
|
251
|
+
{
|
|
252
|
+
auto result = static_cast<phmap_uint128>(a) * static_cast<phmap_uint128>(b);
|
|
253
|
+
*high = static_cast<uint64_t>(result >> 64);
|
|
254
|
+
return static_cast<uint64_t>(result);
|
|
255
|
+
}
|
|
256
|
+
#define PHMAP_HAS_UMUL128 1
|
|
257
|
+
#elif (defined(_MSC_VER))
|
|
258
|
+
#if defined(_M_X64)
|
|
259
|
+
#pragma intrinsic(_umul128)
|
|
260
|
+
inline uint64_t umul128(uint64_t a, uint64_t b, uint64_t* high)
|
|
261
|
+
{
|
|
262
|
+
return _umul128(a, b, high);
|
|
263
|
+
}
|
|
264
|
+
#define PHMAP_HAS_UMUL128 1
|
|
265
|
+
#endif
|
|
266
|
+
#endif
|
|
267
|
+
|
|
268
|
+
#if defined(__GNUC__)
|
|
269
|
+
#pragma GCC diagnostic pop
|
|
270
|
+
#endif
|
|
271
|
+
|
|
272
|
+
namespace base_internal {
|
|
273
|
+
|
|
274
|
+
PHMAP_BASE_INTERNAL_FORCEINLINE uint32_t CountLeadingZeros64Slow(uint64_t n) {
|
|
275
|
+
int zeroes = 60;
|
|
276
|
+
if (n >> 32) zeroes -= 32, n >>= 32;
|
|
277
|
+
if (n >> 16) zeroes -= 16, n >>= 16;
|
|
278
|
+
if (n >> 8) zeroes -= 8, n >>= 8;
|
|
279
|
+
if (n >> 4) zeroes -= 4, n >>= 4;
|
|
280
|
+
return (uint32_t)("\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[n] + zeroes);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
PHMAP_BASE_INTERNAL_FORCEINLINE uint32_t CountLeadingZeros64(uint64_t n) {
|
|
284
|
+
#if defined(_MSC_VER) && defined(_M_X64)
|
|
285
|
+
// MSVC does not have __buitin_clzll. Use _BitScanReverse64.
|
|
286
|
+
unsigned long result = 0; // NOLINT(runtime/int)
|
|
287
|
+
if (_BitScanReverse64(&result, n)) {
|
|
288
|
+
return (uint32_t)(63 - result);
|
|
289
|
+
}
|
|
290
|
+
return 64;
|
|
291
|
+
#elif defined(_MSC_VER) && !defined(__clang__)
|
|
292
|
+
// MSVC does not have __buitin_clzll. Compose two calls to _BitScanReverse
|
|
293
|
+
unsigned long result = 0; // NOLINT(runtime/int)
|
|
294
|
+
if ((n >> 32) && _BitScanReverse(&result, (unsigned long)(n >> 32))) {
|
|
295
|
+
return (uint32_t)(31 - result);
|
|
296
|
+
}
|
|
297
|
+
if (_BitScanReverse(&result, (unsigned long)n)) {
|
|
298
|
+
return (uint32_t)(63 - result);
|
|
299
|
+
}
|
|
300
|
+
return 64;
|
|
301
|
+
#elif defined(__GNUC__) || defined(__clang__)
|
|
302
|
+
// Use __builtin_clzll, which uses the following instructions:
|
|
303
|
+
// x86: bsr
|
|
304
|
+
// ARM64: clz
|
|
305
|
+
// PPC: cntlzd
|
|
306
|
+
static_assert(sizeof(unsigned long long) == sizeof(n), // NOLINT(runtime/int)
|
|
307
|
+
"__builtin_clzll does not take 64-bit arg");
|
|
308
|
+
|
|
309
|
+
// Handle 0 as a special case because __builtin_clzll(0) is undefined.
|
|
310
|
+
if (n == 0) {
|
|
311
|
+
return 64;
|
|
312
|
+
}
|
|
313
|
+
return (uint32_t)__builtin_clzll(n);
|
|
314
|
+
#else
|
|
315
|
+
return CountLeadingZeros64Slow(n);
|
|
316
|
+
#endif
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
PHMAP_BASE_INTERNAL_FORCEINLINE uint32_t CountLeadingZeros32Slow(uint64_t n) {
|
|
320
|
+
uint32_t zeroes = 28;
|
|
321
|
+
if (n >> 16) zeroes -= 16, n >>= 16;
|
|
322
|
+
if (n >> 8) zeroes -= 8, n >>= 8;
|
|
323
|
+
if (n >> 4) zeroes -= 4, n >>= 4;
|
|
324
|
+
return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[n] + zeroes;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
PHMAP_BASE_INTERNAL_FORCEINLINE uint32_t CountLeadingZeros32(uint32_t n) {
|
|
328
|
+
#if defined(_MSC_VER) && !defined(__clang__)
|
|
329
|
+
unsigned long result = 0; // NOLINT(runtime/int)
|
|
330
|
+
if (_BitScanReverse(&result, n)) {
|
|
331
|
+
return (uint32_t)(31 - result);
|
|
332
|
+
}
|
|
333
|
+
return 32;
|
|
334
|
+
#elif defined(__GNUC__) || defined(__clang__)
|
|
335
|
+
// Use __builtin_clz, which uses the following instructions:
|
|
336
|
+
// x86: bsr
|
|
337
|
+
// ARM64: clz
|
|
338
|
+
// PPC: cntlzd
|
|
339
|
+
static_assert(sizeof(int) == sizeof(n),
|
|
340
|
+
"__builtin_clz does not take 32-bit arg");
|
|
341
|
+
|
|
342
|
+
// Handle 0 as a special case because __builtin_clz(0) is undefined.
|
|
343
|
+
if (n == 0) {
|
|
344
|
+
return 32;
|
|
345
|
+
}
|
|
346
|
+
return __builtin_clz(n);
|
|
347
|
+
#else
|
|
348
|
+
return CountLeadingZeros32Slow(n);
|
|
349
|
+
#endif
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
PHMAP_BASE_INTERNAL_FORCEINLINE uint32_t CountTrailingZerosNonZero64Slow(uint64_t n) {
|
|
353
|
+
uint32_t c = 63;
|
|
354
|
+
n &= ~n + 1;
|
|
355
|
+
if (n & 0x00000000FFFFFFFF) c -= 32;
|
|
356
|
+
if (n & 0x0000FFFF0000FFFF) c -= 16;
|
|
357
|
+
if (n & 0x00FF00FF00FF00FF) c -= 8;
|
|
358
|
+
if (n & 0x0F0F0F0F0F0F0F0F) c -= 4;
|
|
359
|
+
if (n & 0x3333333333333333) c -= 2;
|
|
360
|
+
if (n & 0x5555555555555555) c -= 1;
|
|
361
|
+
return c;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
PHMAP_BASE_INTERNAL_FORCEINLINE uint32_t CountTrailingZerosNonZero64(uint64_t n) {
|
|
365
|
+
#if defined(_MSC_VER) && !defined(__clang__) && defined(_M_X64)
|
|
366
|
+
unsigned long result = 0; // NOLINT(runtime/int)
|
|
367
|
+
_BitScanForward64(&result, n);
|
|
368
|
+
return (uint32_t)result;
|
|
369
|
+
#elif defined(_MSC_VER) && !defined(__clang__)
|
|
370
|
+
unsigned long result = 0; // NOLINT(runtime/int)
|
|
371
|
+
if (static_cast<uint32_t>(n) == 0) {
|
|
372
|
+
_BitScanForward(&result, (unsigned long)(n >> 32));
|
|
373
|
+
return result + 32;
|
|
374
|
+
}
|
|
375
|
+
_BitScanForward(&result, (unsigned long)n);
|
|
376
|
+
return result;
|
|
377
|
+
#elif defined(__GNUC__) || defined(__clang__)
|
|
378
|
+
static_assert(sizeof(unsigned long long) == sizeof(n), // NOLINT(runtime/int)
|
|
379
|
+
"__builtin_ctzll does not take 64-bit arg");
|
|
380
|
+
return __builtin_ctzll(n);
|
|
381
|
+
#else
|
|
382
|
+
return CountTrailingZerosNonZero64Slow(n);
|
|
383
|
+
#endif
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
PHMAP_BASE_INTERNAL_FORCEINLINE uint32_t CountTrailingZerosNonZero32Slow(uint32_t n) {
|
|
387
|
+
uint32_t c = 31;
|
|
388
|
+
n &= ~n + 1;
|
|
389
|
+
if (n & 0x0000FFFF) c -= 16;
|
|
390
|
+
if (n & 0x00FF00FF) c -= 8;
|
|
391
|
+
if (n & 0x0F0F0F0F) c -= 4;
|
|
392
|
+
if (n & 0x33333333) c -= 2;
|
|
393
|
+
if (n & 0x55555555) c -= 1;
|
|
394
|
+
return c;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
PHMAP_BASE_INTERNAL_FORCEINLINE uint32_t CountTrailingZerosNonZero32(uint32_t n) {
|
|
398
|
+
#if defined(_MSC_VER) && !defined(__clang__)
|
|
399
|
+
unsigned long result = 0; // NOLINT(runtime/int)
|
|
400
|
+
_BitScanForward(&result, n);
|
|
401
|
+
return (uint32_t)result;
|
|
402
|
+
#elif defined(__GNUC__) || defined(__clang__)
|
|
403
|
+
static_assert(sizeof(int) == sizeof(n),
|
|
404
|
+
"__builtin_ctz does not take 32-bit arg");
|
|
405
|
+
return __builtin_ctz(n);
|
|
406
|
+
#else
|
|
407
|
+
return CountTrailingZerosNonZero32Slow(n);
|
|
408
|
+
#endif
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
#undef PHMAP_BASE_INTERNAL_FORCEINLINE
|
|
412
|
+
|
|
413
|
+
} // namespace base_internal
|
|
414
|
+
} // namespace phmap
|
|
415
|
+
|
|
416
|
+
// -----------------------------------------------------------------------------
|
|
417
|
+
// File: endian.h
|
|
418
|
+
// -----------------------------------------------------------------------------
|
|
419
|
+
|
|
420
|
+
namespace phmap {
|
|
421
|
+
|
|
422
|
+
// Use compiler byte-swapping intrinsics if they are available. 32-bit
|
|
423
|
+
// and 64-bit versions are available in Clang and GCC as of GCC 4.3.0.
|
|
424
|
+
// The 16-bit version is available in Clang and GCC only as of GCC 4.8.0.
|
|
425
|
+
// For simplicity, we enable them all only for GCC 4.8.0 or later.
|
|
426
|
+
#if defined(__clang__) || \
|
|
427
|
+
(defined(__GNUC__) && \
|
|
428
|
+
((__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || __GNUC__ >= 5))
|
|
429
|
+
|
|
430
|
+
inline uint64_t gbswap_64(uint64_t host_int) {
|
|
431
|
+
return __builtin_bswap64(host_int);
|
|
432
|
+
}
|
|
433
|
+
inline uint32_t gbswap_32(uint32_t host_int) {
|
|
434
|
+
return __builtin_bswap32(host_int);
|
|
435
|
+
}
|
|
436
|
+
inline uint16_t gbswap_16(uint16_t host_int) {
|
|
437
|
+
return __builtin_bswap16(host_int);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
#elif defined(_MSC_VER)
|
|
441
|
+
|
|
442
|
+
inline uint64_t gbswap_64(uint64_t host_int) {
|
|
443
|
+
return _byteswap_uint64(host_int);
|
|
444
|
+
}
|
|
445
|
+
inline uint32_t gbswap_32(uint32_t host_int) {
|
|
446
|
+
return _byteswap_ulong(host_int);
|
|
447
|
+
}
|
|
448
|
+
inline uint16_t gbswap_16(uint16_t host_int) {
|
|
449
|
+
return _byteswap_ushort(host_int);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
#elif defined(__APPLE__)
|
|
453
|
+
|
|
454
|
+
inline uint64_t gbswap_64(uint64_t host_int) { return OSSwapInt16(host_int); }
|
|
455
|
+
inline uint32_t gbswap_32(uint32_t host_int) { return OSSwapInt32(host_int); }
|
|
456
|
+
inline uint16_t gbswap_16(uint16_t host_int) { return OSSwapInt64(host_int); }
|
|
457
|
+
|
|
458
|
+
#else
|
|
459
|
+
|
|
460
|
+
inline uint64_t gbswap_64(uint64_t host_int) {
|
|
461
|
+
#if defined(__GNUC__) && defined(__x86_64__) && !defined(__APPLE__)
|
|
462
|
+
// Adapted from /usr/include/byteswap.h. Not available on Mac.
|
|
463
|
+
if (__builtin_constant_p(host_int)) {
|
|
464
|
+
return __bswap_constant_64(host_int);
|
|
465
|
+
} else {
|
|
466
|
+
uint64_t result;
|
|
467
|
+
__asm__("bswap %0" : "=r"(result) : "0"(host_int));
|
|
468
|
+
return result;
|
|
469
|
+
}
|
|
470
|
+
#elif defined(__GLIBC__)
|
|
471
|
+
return bswap_64(host_int);
|
|
472
|
+
#else
|
|
473
|
+
return (((host_int & uint64_t{0xFF}) << 56) |
|
|
474
|
+
((host_int & uint64_t{0xFF00}) << 40) |
|
|
475
|
+
((host_int & uint64_t{0xFF0000}) << 24) |
|
|
476
|
+
((host_int & uint64_t{0xFF000000}) << 8) |
|
|
477
|
+
((host_int & uint64_t{0xFF00000000}) >> 8) |
|
|
478
|
+
((host_int & uint64_t{0xFF0000000000}) >> 24) |
|
|
479
|
+
((host_int & uint64_t{0xFF000000000000}) >> 40) |
|
|
480
|
+
((host_int & uint64_t{0xFF00000000000000}) >> 56));
|
|
481
|
+
#endif // bswap_64
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
inline uint32_t gbswap_32(uint32_t host_int) {
|
|
485
|
+
#if defined(__GLIBC__)
|
|
486
|
+
return bswap_32(host_int);
|
|
487
|
+
#else
|
|
488
|
+
return (((host_int & uint32_t{0xFF}) << 24) |
|
|
489
|
+
((host_int & uint32_t{0xFF00}) << 8) |
|
|
490
|
+
((host_int & uint32_t{0xFF0000}) >> 8) |
|
|
491
|
+
((host_int & uint32_t{0xFF000000}) >> 24));
|
|
492
|
+
#endif
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
inline uint16_t gbswap_16(uint16_t host_int) {
|
|
496
|
+
#if defined(__GLIBC__)
|
|
497
|
+
return bswap_16(host_int);
|
|
498
|
+
#else
|
|
499
|
+
return (((host_int & uint16_t{0xFF}) << 8) |
|
|
500
|
+
((host_int & uint16_t{0xFF00}) >> 8));
|
|
501
|
+
#endif
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
#endif // intrinics available
|
|
505
|
+
|
|
506
|
+
#ifdef PHMAP_IS_LITTLE_ENDIAN
|
|
507
|
+
|
|
508
|
+
// Definitions for ntohl etc. that don't require us to include
|
|
509
|
+
// netinet/in.h. We wrap gbswap_32 and gbswap_16 in functions rather
|
|
510
|
+
// than just #defining them because in debug mode, gcc doesn't
|
|
511
|
+
// correctly handle the (rather involved) definitions of bswap_32.
|
|
512
|
+
// gcc guarantees that inline functions are as fast as macros, so
|
|
513
|
+
// this isn't a performance hit.
|
|
514
|
+
inline uint16_t ghtons(uint16_t x) { return gbswap_16(x); }
|
|
515
|
+
inline uint32_t ghtonl(uint32_t x) { return gbswap_32(x); }
|
|
516
|
+
inline uint64_t ghtonll(uint64_t x) { return gbswap_64(x); }
|
|
517
|
+
|
|
518
|
+
#elif defined PHMAP_IS_BIG_ENDIAN
|
|
519
|
+
|
|
520
|
+
// These definitions are simpler on big-endian machines
|
|
521
|
+
// These are functions instead of macros to avoid self-assignment warnings
|
|
522
|
+
// on calls such as "i = ghtnol(i);". This also provides type checking.
|
|
523
|
+
inline uint16_t ghtons(uint16_t x) { return x; }
|
|
524
|
+
inline uint32_t ghtonl(uint32_t x) { return x; }
|
|
525
|
+
inline uint64_t ghtonll(uint64_t x) { return x; }
|
|
526
|
+
|
|
527
|
+
#else
|
|
528
|
+
#error \
|
|
529
|
+
"Unsupported byte order: Either PHMAP_IS_BIG_ENDIAN or " \
|
|
530
|
+
"PHMAP_IS_LITTLE_ENDIAN must be defined"
|
|
531
|
+
#endif // byte order
|
|
532
|
+
|
|
533
|
+
inline uint16_t gntohs(uint16_t x) { return ghtons(x); }
|
|
534
|
+
inline uint32_t gntohl(uint32_t x) { return ghtonl(x); }
|
|
535
|
+
inline uint64_t gntohll(uint64_t x) { return ghtonll(x); }
|
|
536
|
+
|
|
537
|
+
// Utilities to convert numbers between the current hosts's native byte
|
|
538
|
+
// order and little-endian byte order
|
|
539
|
+
//
|
|
540
|
+
// Load/Store methods are alignment safe
|
|
541
|
+
namespace little_endian {
|
|
542
|
+
// Conversion functions.
|
|
543
|
+
#ifdef PHMAP_IS_LITTLE_ENDIAN
|
|
544
|
+
|
|
545
|
+
inline uint16_t FromHost16(uint16_t x) { return x; }
|
|
546
|
+
inline uint16_t ToHost16(uint16_t x) { return x; }
|
|
547
|
+
|
|
548
|
+
inline uint32_t FromHost32(uint32_t x) { return x; }
|
|
549
|
+
inline uint32_t ToHost32(uint32_t x) { return x; }
|
|
550
|
+
|
|
551
|
+
inline uint64_t FromHost64(uint64_t x) { return x; }
|
|
552
|
+
inline uint64_t ToHost64(uint64_t x) { return x; }
|
|
553
|
+
|
|
554
|
+
inline constexpr bool IsLittleEndian() { return true; }
|
|
555
|
+
|
|
556
|
+
#elif defined PHMAP_IS_BIG_ENDIAN
|
|
557
|
+
|
|
558
|
+
inline uint16_t FromHost16(uint16_t x) { return gbswap_16(x); }
|
|
559
|
+
inline uint16_t ToHost16(uint16_t x) { return gbswap_16(x); }
|
|
560
|
+
|
|
561
|
+
inline uint32_t FromHost32(uint32_t x) { return gbswap_32(x); }
|
|
562
|
+
inline uint32_t ToHost32(uint32_t x) { return gbswap_32(x); }
|
|
563
|
+
|
|
564
|
+
inline uint64_t FromHost64(uint64_t x) { return gbswap_64(x); }
|
|
565
|
+
inline uint64_t ToHost64(uint64_t x) { return gbswap_64(x); }
|
|
566
|
+
|
|
567
|
+
inline constexpr bool IsLittleEndian() { return false; }
|
|
568
|
+
|
|
569
|
+
#endif /* ENDIAN */
|
|
570
|
+
|
|
571
|
+
// Functions to do unaligned loads and stores in little-endian order.
|
|
572
|
+
// ------------------------------------------------------------------
|
|
573
|
+
inline uint16_t Load16(const void *p) {
|
|
574
|
+
return ToHost16(PHMAP_INTERNAL_UNALIGNED_LOAD16(p));
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
inline void Store16(void *p, uint16_t v) {
|
|
578
|
+
PHMAP_INTERNAL_UNALIGNED_STORE16(p, FromHost16(v));
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
inline uint32_t Load32(const void *p) {
|
|
582
|
+
return ToHost32(PHMAP_INTERNAL_UNALIGNED_LOAD32(p));
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
inline void Store32(void *p, uint32_t v) {
|
|
586
|
+
PHMAP_INTERNAL_UNALIGNED_STORE32(p, FromHost32(v));
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
inline uint64_t Load64(const void *p) {
|
|
590
|
+
return ToHost64(PHMAP_INTERNAL_UNALIGNED_LOAD64(p));
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
inline void Store64(void *p, uint64_t v) {
|
|
594
|
+
PHMAP_INTERNAL_UNALIGNED_STORE64(p, FromHost64(v));
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
} // namespace little_endian
|
|
598
|
+
|
|
599
|
+
// Utilities to convert numbers between the current hosts's native byte
|
|
600
|
+
// order and big-endian byte order (same as network byte order)
|
|
601
|
+
//
|
|
602
|
+
// Load/Store methods are alignment safe
|
|
603
|
+
namespace big_endian {
|
|
604
|
+
#ifdef PHMAP_IS_LITTLE_ENDIAN
|
|
605
|
+
|
|
606
|
+
inline uint16_t FromHost16(uint16_t x) { return gbswap_16(x); }
|
|
607
|
+
inline uint16_t ToHost16(uint16_t x) { return gbswap_16(x); }
|
|
608
|
+
|
|
609
|
+
inline uint32_t FromHost32(uint32_t x) { return gbswap_32(x); }
|
|
610
|
+
inline uint32_t ToHost32(uint32_t x) { return gbswap_32(x); }
|
|
611
|
+
|
|
612
|
+
inline uint64_t FromHost64(uint64_t x) { return gbswap_64(x); }
|
|
613
|
+
inline uint64_t ToHost64(uint64_t x) { return gbswap_64(x); }
|
|
614
|
+
|
|
615
|
+
inline constexpr bool IsLittleEndian() { return true; }
|
|
616
|
+
|
|
617
|
+
#elif defined PHMAP_IS_BIG_ENDIAN
|
|
618
|
+
|
|
619
|
+
inline uint16_t FromHost16(uint16_t x) { return x; }
|
|
620
|
+
inline uint16_t ToHost16(uint16_t x) { return x; }
|
|
621
|
+
|
|
622
|
+
inline uint32_t FromHost32(uint32_t x) { return x; }
|
|
623
|
+
inline uint32_t ToHost32(uint32_t x) { return x; }
|
|
624
|
+
|
|
625
|
+
inline uint64_t FromHost64(uint64_t x) { return x; }
|
|
626
|
+
inline uint64_t ToHost64(uint64_t x) { return x; }
|
|
627
|
+
|
|
628
|
+
inline constexpr bool IsLittleEndian() { return false; }
|
|
629
|
+
|
|
630
|
+
#endif /* ENDIAN */
|
|
631
|
+
|
|
632
|
+
// Functions to do unaligned loads and stores in big-endian order.
|
|
633
|
+
inline uint16_t Load16(const void *p) {
|
|
634
|
+
return ToHost16(PHMAP_INTERNAL_UNALIGNED_LOAD16(p));
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
inline void Store16(void *p, uint16_t v) {
|
|
638
|
+
PHMAP_INTERNAL_UNALIGNED_STORE16(p, FromHost16(v));
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
inline uint32_t Load32(const void *p) {
|
|
642
|
+
return ToHost32(PHMAP_INTERNAL_UNALIGNED_LOAD32(p));
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
inline void Store32(void *p, uint32_t v) {
|
|
646
|
+
PHMAP_INTERNAL_UNALIGNED_STORE32(p, FromHost32(v));
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
inline uint64_t Load64(const void *p) {
|
|
650
|
+
return ToHost64(PHMAP_INTERNAL_UNALIGNED_LOAD64(p));
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
inline void Store64(void *p, uint64_t v) {
|
|
654
|
+
PHMAP_INTERNAL_UNALIGNED_STORE64(p, FromHost64(v));
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
} // namespace big_endian
|
|
658
|
+
|
|
659
|
+
} // namespace phmap
|
|
660
|
+
|
|
661
|
+
#ifdef _MSC_VER
|
|
662
|
+
#pragma warning(pop)
|
|
663
|
+
#endif
|
|
664
|
+
|
|
665
|
+
#endif // phmap_bits_h_guard_
|