@delali/narsil-react-native 0.0.0-stage → 0.3.1-next.146

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.
Files changed (186) hide show
  1. package/LICENSE +201 -0
  2. package/NarsilReactNative.podspec +57 -0
  3. package/README.md +46 -2
  4. package/android/CMakeLists.txt +48 -0
  5. package/android/build.gradle +151 -0
  6. package/android/gradle.properties +5 -0
  7. package/android/src/main/AndroidManifest.xml +2 -0
  8. package/android/src/main/cpp/AndroidEnvironment.cpp +44 -0
  9. package/android/src/main/cpp/AndroidEnvironment.hpp +11 -0
  10. package/android/src/main/cpp/cpp-adapter.cpp +11 -0
  11. package/android/src/main/java/com/margelo/nitro/narsil/NarsilAndroidEnvironment.kt +29 -0
  12. package/android/src/main/java/com/margelo/nitro/narsil/NarsilReactNativePackage.kt +22 -0
  13. package/app.plugin.js +25 -0
  14. package/cpp/AttachedField.cpp +234 -0
  15. package/cpp/AttachedField.hpp +61 -0
  16. package/cpp/Compression.cpp +113 -0
  17. package/cpp/Compression.hpp +16 -0
  18. package/cpp/GraphHeldAlone.cpp +29 -0
  19. package/cpp/GraphHeldAlone.hpp +25 -0
  20. package/cpp/HostMemory.cpp +123 -0
  21. package/cpp/HostMemory.hpp +53 -0
  22. package/cpp/HybridNarsilCoreImpl.cpp +390 -0
  23. package/cpp/HybridNarsilCoreImpl.hpp +68 -0
  24. package/cpp/HybridNarsilFilesImpl.cpp +245 -0
  25. package/cpp/HybridNarsilFilesImpl.hpp +34 -0
  26. package/cpp/HybridNarsilHostImpl.cpp +126 -0
  27. package/cpp/HybridNarsilHostImpl.hpp +42 -0
  28. package/cpp/NativeAtomics.cpp +110 -0
  29. package/cpp/NativeAtomics.hpp +11 -0
  30. package/cpp/ProcessInfo.cpp +83 -0
  31. package/cpp/ProcessInfo.hpp +11 -0
  32. package/cpp/ThreadPriority.cpp +77 -0
  33. package/cpp/ThreadPriority.hpp +8 -0
  34. package/cpp/WorkletRuntimeDispatcher.cpp +61 -0
  35. package/cpp/WorkletRuntimeDispatcher.hpp +9 -0
  36. package/cpp/core/include/narsil_core.h +208 -0
  37. package/cpp/core/src/connect.c +213 -0
  38. package/cpp/core/src/distance.c +103 -0
  39. package/cpp/core/src/files.c +99 -0
  40. package/cpp/core/src/heap.c +84 -0
  41. package/cpp/core/src/internal.h +284 -0
  42. package/cpp/core/src/kernels_code.c +209 -0
  43. package/cpp/core/src/kernels_float.c +197 -0
  44. package/cpp/core/src/kernels_pair.c +133 -0
  45. package/cpp/core/src/last_links.c +145 -0
  46. package/cpp/core/src/links.c +195 -0
  47. package/cpp/core/src/locks.c +168 -0
  48. package/cpp/core/src/nearest_links.c +147 -0
  49. package/cpp/core/src/place.c +215 -0
  50. package/cpp/core/src/quantize.c +226 -0
  51. package/cpp/core/src/records.c +97 -0
  52. package/cpp/core/src/remove.c +205 -0
  53. package/cpp/core/src/vectors.c +139 -0
  54. package/cpp/core/src/walk.c +231 -0
  55. package/cpp/core/src/workspace.c +167 -0
  56. package/ios/PrivacyInfo.xcprivacy +23 -0
  57. package/lib/client.d.ts +19 -0
  58. package/lib/client.js +41 -0
  59. package/lib/constants.d.ts +9 -0
  60. package/lib/constants.js +9 -0
  61. package/lib/engine/byte-files.d.ts +5 -0
  62. package/lib/engine/byte-files.js +97 -0
  63. package/lib/engine/core.d.ts +3 -0
  64. package/lib/engine/core.js +113 -0
  65. package/lib/engine/files.d.ts +3 -0
  66. package/lib/engine/files.js +188 -0
  67. package/lib/engine/host.d.ts +13 -0
  68. package/lib/engine/host.js +102 -0
  69. package/lib/engine/install.d.ts +4 -0
  70. package/lib/engine/install.js +29 -0
  71. package/lib/engine/native-error.d.ts +1 -0
  72. package/lib/engine/native-error.js +12 -0
  73. package/lib/engine/stand-ins/atomics.d.ts +5 -0
  74. package/lib/engine/stand-ins/atomics.js +236 -0
  75. package/lib/engine/stand-ins/crypto.d.ts +2 -0
  76. package/lib/engine/stand-ins/crypto.js +65 -0
  77. package/lib/engine/stand-ins/process.d.ts +2 -0
  78. package/lib/engine/stand-ins/process.js +22 -0
  79. package/lib/engine/stand-ins/streams.d.ts +1 -0
  80. package/lib/engine/stand-ins/streams.js +31 -0
  81. package/lib/engine/stand-ins/structured-clone.d.ts +1 -0
  82. package/lib/engine/stand-ins/structured-clone.js +121 -0
  83. package/lib/engine/streamed.d.ts +6 -0
  84. package/lib/engine/streamed.js +29 -0
  85. package/lib/engine/transfer.d.ts +3 -0
  86. package/lib/engine/transfer.js +77 -0
  87. package/lib/errors.d.ts +25 -0
  88. package/lib/errors.js +59 -0
  89. package/lib/index.d.ts +3 -0
  90. package/lib/index.js +2 -0
  91. package/lib/methods.d.ts +5 -0
  92. package/lib/methods.js +47 -0
  93. package/lib/native-objects.d.ts +2 -0
  94. package/lib/native-objects.js +24 -0
  95. package/lib/specs/core.nitro.d.ts +79 -0
  96. package/lib/specs/core.nitro.js +1 -0
  97. package/lib/specs/files.nitro.d.ts +36 -0
  98. package/lib/specs/files.nitro.js +1 -0
  99. package/lib/specs/host.nitro.d.ts +24 -0
  100. package/lib/specs/host.nitro.js +1 -0
  101. package/lib/transferred.d.ts +15 -0
  102. package/lib/transferred.js +6 -0
  103. package/lib/types.d.ts +136 -0
  104. package/lib/types.js +1 -0
  105. package/lib/worklets/app-turns.d.ts +1 -0
  106. package/lib/worklets/app-turns.js +44 -0
  107. package/lib/worklets/client.d.ts +30 -0
  108. package/lib/worklets/client.js +144 -0
  109. package/lib/worklets/index.d.ts +4 -0
  110. package/lib/worklets/index.js +2 -0
  111. package/lib/worklets/instances.d.ts +15 -0
  112. package/lib/worklets/instances.js +194 -0
  113. package/lib/worklets/json-part.d.ts +1 -0
  114. package/lib/worklets/json-part.js +42 -0
  115. package/lib/worklets/runtime.d.ts +25 -0
  116. package/lib/worklets/runtime.js +80 -0
  117. package/lib/worklets/transfer-queue.d.ts +7 -0
  118. package/lib/worklets/transfer-queue.js +79 -0
  119. package/lib/worklets/types.d.ts +26 -0
  120. package/lib/worklets/types.js +1 -0
  121. package/nitro.json +32 -0
  122. package/nitrogen/generated/.gitattributes +1 -0
  123. package/nitrogen/generated/android/NarsilReactNative+autolinking.cmake +85 -0
  124. package/nitrogen/generated/android/NarsilReactNative+autolinking.gradle +27 -0
  125. package/nitrogen/generated/android/NarsilReactNativeOnLoad.cpp +69 -0
  126. package/nitrogen/generated/android/NarsilReactNativeOnLoad.hpp +34 -0
  127. package/nitrogen/generated/android/kotlin/com/margelo/nitro/narsil/NarsilReactNativeOnLoad.kt +35 -0
  128. package/nitrogen/generated/ios/NarsilReactNative+autolinking.rb +62 -0
  129. package/nitrogen/generated/ios/NarsilReactNative-Swift-Cxx-Bridge.cpp +17 -0
  130. package/nitrogen/generated/ios/NarsilReactNative-Swift-Cxx-Bridge.hpp +27 -0
  131. package/nitrogen/generated/ios/NarsilReactNative-Swift-Cxx-Umbrella.hpp +38 -0
  132. package/nitrogen/generated/ios/NarsilReactNativeAutolinking.mm +55 -0
  133. package/nitrogen/generated/ios/NarsilReactNativeAutolinking.swift +16 -0
  134. package/nitrogen/generated/shared/c++/DirectoryEntry.hpp +91 -0
  135. package/nitrogen/generated/shared/c++/FileStatus.hpp +103 -0
  136. package/nitrogen/generated/shared/c++/GraphMemory.hpp +120 -0
  137. package/nitrogen/generated/shared/c++/HybridNarsilAttachedGraphSpec.cpp +21 -0
  138. package/nitrogen/generated/shared/c++/HybridNarsilAttachedGraphSpec.hpp +62 -0
  139. package/nitrogen/generated/shared/c++/HybridNarsilAttachedStoreSpec.cpp +21 -0
  140. package/nitrogen/generated/shared/c++/HybridNarsilAttachedStoreSpec.hpp +62 -0
  141. package/nitrogen/generated/shared/c++/HybridNarsilCoreSpec.cpp +35 -0
  142. package/nitrogen/generated/shared/c++/HybridNarsilCoreSpec.hpp +100 -0
  143. package/nitrogen/generated/shared/c++/HybridNarsilFilesSpec.cpp +37 -0
  144. package/nitrogen/generated/shared/c++/HybridNarsilFilesSpec.hpp +86 -0
  145. package/nitrogen/generated/shared/c++/HybridNarsilHostSpec.cpp +34 -0
  146. package/nitrogen/generated/shared/c++/HybridNarsilHostSpec.hpp +78 -0
  147. package/nitrogen/generated/shared/c++/MemoryView.hpp +91 -0
  148. package/nitrogen/generated/shared/c++/NativeConnectOutcome.hpp +87 -0
  149. package/nitrogen/generated/shared/c++/NativeScores.hpp +87 -0
  150. package/nitrogen/generated/shared/c++/NativeSearchHits.hpp +91 -0
  151. package/nitrogen/generated/shared/c++/ProcessMemory.hpp +87 -0
  152. package/nitrogen/generated/shared/c++/StoreMemory.hpp +142 -0
  153. package/package.json +87 -3
  154. package/react-native.config.js +8 -0
  155. package/src/client.ts +44 -0
  156. package/src/constants.ts +9 -0
  157. package/src/engine/byte-files.ts +99 -0
  158. package/src/engine/core.ts +162 -0
  159. package/src/engine/files.ts +186 -0
  160. package/src/engine/host.ts +111 -0
  161. package/src/engine/install.ts +31 -0
  162. package/src/engine/native-error.ts +10 -0
  163. package/src/engine/stand-ins/atomics.ts +288 -0
  164. package/src/engine/stand-ins/crypto.ts +81 -0
  165. package/src/engine/stand-ins/process.ts +30 -0
  166. package/src/engine/stand-ins/streams.ts +45 -0
  167. package/src/engine/stand-ins/structured-clone.ts +118 -0
  168. package/src/engine/streamed.ts +40 -0
  169. package/src/engine/transfer.ts +72 -0
  170. package/src/errors.ts +73 -0
  171. package/src/index.ts +3 -0
  172. package/src/methods.ts +52 -0
  173. package/src/native-objects.ts +30 -0
  174. package/src/specs/core.nitro.ts +140 -0
  175. package/src/specs/files.nitro.ts +42 -0
  176. package/src/specs/host.nitro.ts +30 -0
  177. package/src/transferred.ts +18 -0
  178. package/src/types.ts +164 -0
  179. package/src/worklets/app-turns.ts +48 -0
  180. package/src/worklets/client.ts +165 -0
  181. package/src/worklets/index.ts +4 -0
  182. package/src/worklets/instances.ts +231 -0
  183. package/src/worklets/json-part.ts +38 -0
  184. package/src/worklets/runtime.ts +190 -0
  185. package/src/worklets/transfer-queue.ts +98 -0
  186. package/src/worklets/types.ts +37 -0
@@ -0,0 +1,99 @@
1
+ #include "../include/narsil_core.h"
2
+
3
+ #include <stddef.h>
4
+ #include <stdint.h>
5
+
6
+ static void forget_mapping(narsil_vector_file *file) {
7
+ file->bytes = NULL;
8
+ file->length = 0;
9
+ file->mapping = NULL;
10
+ }
11
+
12
+ #ifdef _WIN32
13
+
14
+ #include <stdlib.h>
15
+ #include <windows.h>
16
+
17
+ static WCHAR *wide_path_of(const char *path) {
18
+ int length = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, path, -1, NULL, 0);
19
+ if (length <= 0) { return NULL; }
20
+ WCHAR *wide = calloc((size_t)length, sizeof *wide);
21
+ if (wide == NULL) { return NULL; }
22
+ if (MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, path, -1, wide, length) != length) {
23
+ free(wide);
24
+ return NULL;
25
+ }
26
+ return wide;
27
+ }
28
+
29
+ static narsil_status map_open_file(HANDLE opened, narsil_vector_file *file) {
30
+ LARGE_INTEGER size;
31
+ if (!GetFileSizeEx(opened, &size) || size.QuadPart <= 0) { return NARSIL_FILE_UNREADABLE; }
32
+ HANDLE mapping = CreateFileMappingW(opened, NULL, PAGE_READONLY, 0, 0, NULL);
33
+ if (mapping == NULL) { return NARSIL_FILE_UNREADABLE; }
34
+ void *view = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
35
+ CloseHandle(mapping);
36
+ if (view == NULL) { return NARSIL_FILE_UNREADABLE; }
37
+ file->mapping = view;
38
+ file->bytes = view;
39
+ file->length = (uint64_t)size.QuadPart;
40
+ return NARSIL_OK;
41
+ }
42
+
43
+ narsil_status narsil_vector_file_map(const char *path, narsil_vector_file *file) {
44
+ if (path == NULL || file == NULL) { return NARSIL_INVALID_ARGUMENT; }
45
+ forget_mapping(file);
46
+ WCHAR *wide = wide_path_of(path);
47
+ if (wide == NULL) { return NARSIL_FILE_UNREADABLE; }
48
+ HANDLE opened = CreateFileW(wide, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
49
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
50
+ free(wide);
51
+ if (opened == INVALID_HANDLE_VALUE) { return NARSIL_FILE_UNREADABLE; }
52
+ narsil_status status = map_open_file(opened, file);
53
+ CloseHandle(opened);
54
+ return status;
55
+ }
56
+
57
+ void narsil_vector_file_unmap(narsil_vector_file *file) {
58
+ if (file == NULL || file->mapping == NULL) { return; }
59
+ UnmapViewOfFile(file->mapping);
60
+ forget_mapping(file);
61
+ }
62
+
63
+ #else
64
+
65
+ #include <fcntl.h>
66
+ #include <sys/mman.h>
67
+ #include <sys/stat.h>
68
+ #include <unistd.h>
69
+
70
+ static narsil_status map_open_file(int descriptor, narsil_vector_file *file) {
71
+ struct stat status;
72
+ if (fstat(descriptor, &status) != 0 || status.st_size <= 0) { return NARSIL_FILE_UNREADABLE; }
73
+ size_t length = (size_t)status.st_size;
74
+ void *view = mmap(NULL, length, PROT_READ, MAP_SHARED, descriptor, 0);
75
+ if (view == MAP_FAILED) { return NARSIL_FILE_UNREADABLE; }
76
+ (void)posix_madvise(view, length, POSIX_MADV_RANDOM);
77
+ file->mapping = view;
78
+ file->bytes = view;
79
+ file->length = (uint64_t)length;
80
+ return NARSIL_OK;
81
+ }
82
+
83
+ narsil_status narsil_vector_file_map(const char *path, narsil_vector_file *file) {
84
+ if (path == NULL || file == NULL) { return NARSIL_INVALID_ARGUMENT; }
85
+ forget_mapping(file);
86
+ int descriptor = open(path, O_RDONLY | O_CLOEXEC);
87
+ if (descriptor < 0) { return NARSIL_FILE_UNREADABLE; }
88
+ narsil_status status = map_open_file(descriptor, file);
89
+ (void)close(descriptor);
90
+ return status;
91
+ }
92
+
93
+ void narsil_vector_file_unmap(narsil_vector_file *file) {
94
+ if (file == NULL || file->mapping == NULL) { return; }
95
+ (void)munmap(file->mapping, (size_t)file->length);
96
+ forget_mapping(file);
97
+ }
98
+
99
+ #endif
@@ -0,0 +1,84 @@
1
+ #include "internal.h"
2
+
3
+ #include "../include/narsil_core.h"
4
+
5
+ #include <stddef.h>
6
+ #include <stdint.h>
7
+ #include <stdlib.h>
8
+
9
+ #define INITIAL_HEAP_CAPACITY 256
10
+
11
+ narsil_status heap_reserve(distance_heap *heap, uint32_t capacity) {
12
+ if (capacity <= heap->capacity) { return NARSIL_OK; }
13
+ uint32_t held = heap->capacity == 0 ? INITIAL_HEAP_CAPACITY : heap->capacity;
14
+ uint32_t next = grown_capacity(held, capacity);
15
+ int32_t *ordinals = realloc(heap->ordinals, (size_t)next * sizeof *ordinals);
16
+ if (ordinals == NULL) { return NARSIL_OUT_OF_MEMORY; }
17
+ heap->ordinals = ordinals;
18
+ double *distances = realloc(heap->distances, (size_t)next * sizeof *distances);
19
+ if (distances == NULL) { return NARSIL_OUT_OF_MEMORY; }
20
+ heap->distances = distances;
21
+ heap->capacity = next;
22
+ return NARSIL_OK;
23
+ }
24
+
25
+ void heap_release(distance_heap *heap) {
26
+ free(heap->ordinals);
27
+ free(heap->distances);
28
+ heap->ordinals = NULL;
29
+ heap->distances = NULL;
30
+ heap->capacity = 0;
31
+ heap->size = 0;
32
+ }
33
+
34
+ static inline int leaves_first(const distance_heap *heap, double candidate, double other) {
35
+ return heap->greatest_first ? candidate > other : candidate < other;
36
+ }
37
+
38
+ narsil_status heap_push(distance_heap *heap, scored_node node) {
39
+ narsil_status status = heap_reserve(heap, heap->size + 1);
40
+ if (status != NARSIL_OK) { return status; }
41
+ uint32_t index = heap->size;
42
+ heap->size += 1;
43
+ while (index > 0) {
44
+ uint32_t parent = (index - 1) >> 1;
45
+ if (!leaves_first(heap, node.distance, heap->distances[parent])) { break; }
46
+ heap->ordinals[index] = heap->ordinals[parent];
47
+ heap->distances[index] = heap->distances[parent];
48
+ index = parent;
49
+ }
50
+ heap->ordinals[index] = node.ordinal;
51
+ heap->distances[index] = node.distance;
52
+ return NARSIL_OK;
53
+ }
54
+
55
+ int heap_pop(distance_heap *heap) {
56
+ if (heap->size == 0) { return 0; }
57
+ heap->top.ordinal = heap->ordinals[0];
58
+ heap->top.distance = heap->distances[0];
59
+ heap->size -= 1;
60
+ if (heap->size == 0) { return 1; }
61
+
62
+ uint32_t size = heap->size;
63
+ int32_t ordinal = heap->ordinals[size];
64
+ double distance = heap->distances[size];
65
+ uint32_t index = 0;
66
+ for (;;) {
67
+ uint32_t left = (2 * index) + 1;
68
+ uint32_t right = left + 1;
69
+ uint32_t first = index;
70
+ double first_distance = distance;
71
+ if (left < size && leaves_first(heap, heap->distances[left], first_distance)) {
72
+ first = left;
73
+ first_distance = heap->distances[left];
74
+ }
75
+ if (right < size && leaves_first(heap, heap->distances[right], first_distance)) { first = right; }
76
+ if (first == index) { break; }
77
+ heap->ordinals[index] = heap->ordinals[first];
78
+ heap->distances[index] = heap->distances[first];
79
+ index = first;
80
+ }
81
+ heap->ordinals[index] = ordinal;
82
+ heap->distances[index] = distance;
83
+ return 1;
84
+ }
@@ -0,0 +1,284 @@
1
+ #ifndef NARSIL_CORE_INTERNAL_H
2
+ #define NARSIL_CORE_INTERNAL_H
3
+
4
+ #include "../include/narsil_core.h"
5
+
6
+ #include <stdatomic.h>
7
+ #include <stddef.h>
8
+ #include <stdint.h>
9
+
10
+ #define NODE_WRITE_HELD 1
11
+ #define NODE_WRITER_WAITING 2
12
+ #define NODE_VERSION_STEP 4U
13
+
14
+ #define QUERY_PLANES 4
15
+ #define MAX_M 512
16
+ #define MAX_NEIGHBOURS_PER_LIST ((2 * MAX_M) + 1)
17
+ #define MAX_REPAIR_CANDIDATES (2 * MAX_NEIGHBOURS_PER_LIST)
18
+ #define BITS_PER_BYTE 8
19
+ #define TRAILER_LOWER 0
20
+ #define TRAILER_UPPER 4
21
+ #define TRAILER_CORRECTION 8
22
+ #define TRAILER_SUM 12
23
+ #define NO_ENTRY_POINT (-1)
24
+ #define NO_NODE (-1)
25
+
26
+ #ifdef NARSIL_PORTABLE_KERNELS
27
+ #elif defined(__aarch64__) || defined(_M_ARM64)
28
+ #define NARSIL_NEON 1
29
+ #elif defined(__SSE2__) || defined(_M_X64)
30
+ #define NARSIL_SSE2 1
31
+ #endif
32
+
33
+ #if defined(NARSIL_SSE2) && (defined(__GNUC__) || defined(__clang__)) && !defined(NARSIL_SSE2_ONLY)
34
+ #define NARSIL_HARDWARE_POPCOUNT 1
35
+ #endif
36
+
37
+ #define INLINED_IN_EACH_KERNEL static inline __attribute__((always_inline))
38
+
39
+ typedef struct {
40
+ int32_t ordinal;
41
+ double distance;
42
+ } scored_node;
43
+
44
+ typedef struct {
45
+ int32_t *ordinals;
46
+ double *distances;
47
+ uint32_t size;
48
+ uint32_t capacity;
49
+ int greatest_first;
50
+ scored_node top;
51
+ } distance_heap;
52
+
53
+ typedef struct {
54
+ int32_t *ordinals;
55
+ double *distances;
56
+ uint32_t count;
57
+ uint32_t capacity;
58
+ } scored_list;
59
+
60
+ typedef struct {
61
+ double lower;
62
+ double upper;
63
+ } level_range;
64
+
65
+ typedef struct {
66
+ level_range range;
67
+ double correction;
68
+ const double *centred;
69
+ } quantised_vector;
70
+
71
+ typedef struct {
72
+ uint32_t bits;
73
+ level_range range;
74
+ double correction;
75
+ double sum;
76
+ uint8_t *levels;
77
+ uint8_t *low_levels;
78
+ uint8_t *high_levels;
79
+ uint8_t *planes;
80
+ } prepared_code;
81
+
82
+ typedef struct {
83
+ const uint8_t *bytes;
84
+ uint32_t byte_count;
85
+ uint32_t bits;
86
+ } packed_code;
87
+
88
+ typedef struct {
89
+ const float *values;
90
+ double magnitude;
91
+ } float_query;
92
+
93
+ typedef struct {
94
+ int32_t ordinal;
95
+ int32_t layer;
96
+ } node_layer;
97
+
98
+ typedef struct {
99
+ uint32_t candidate_limit;
100
+ int32_t layer;
101
+ int excludes_tombstones;
102
+ narsil_ordinal_set accepted;
103
+ } layer_search;
104
+
105
+ typedef struct {
106
+ int32_t graph_top;
107
+ int32_t link_top;
108
+ } link_span;
109
+
110
+ typedef struct {
111
+ int32_t ordinal;
112
+ uint32_t former_count;
113
+ } removed_node;
114
+
115
+ typedef struct {
116
+ const narsil_graph *graph;
117
+ const narsil_store *store;
118
+ narsil_workspace *workspace;
119
+ narsil_metric metric;
120
+ uint32_t thread_slot;
121
+ int uses_codes;
122
+ int pairs_use_codes;
123
+ uint32_t slots;
124
+ uint32_t store_slots;
125
+ uint32_t code_bytes;
126
+ uint32_t record_bytes;
127
+ double centroid_dot;
128
+ float_query query;
129
+ int32_t *fence;
130
+ prepared_code code;
131
+ } walk_context;
132
+
133
+ struct narsil_workspace {
134
+ distance_heap frontier;
135
+ distance_heap found;
136
+ uint32_t *visited;
137
+ uint32_t visited_capacity;
138
+ uint32_t stamp;
139
+ int32_t *entry_points;
140
+ uint32_t entry_point_count;
141
+ uint32_t entry_point_capacity;
142
+ uint32_t dimension_capacity;
143
+ size_t dimension_scratch_bytes;
144
+ double *normalised;
145
+ double *centred;
146
+ float *placed_vector;
147
+ float *stored_vector;
148
+ float *other_vector;
149
+ prepared_code code;
150
+ scored_list layer_candidates;
151
+ scored_list link_candidates;
152
+ scored_list repair_candidates;
153
+ scored_list dropped_links;
154
+ int32_t *selections;
155
+ uint32_t *selection_counts;
156
+ uint32_t selection_layers;
157
+ uint32_t selection_stride;
158
+ int32_t fence;
159
+ int32_t neighbours[MAX_NEIGHBOURS_PER_LIST];
160
+ int32_t former[MAX_NEIGHBOURS_PER_LIST];
161
+ int32_t kept[MAX_NEIGHBOURS_PER_LIST];
162
+ int32_t repaired[MAX_NEIGHBOURS_PER_LIST];
163
+ double kept_distances[MAX_NEIGHBOURS_PER_LIST];
164
+ uint8_t replacement_tried[MAX_NEIGHBOURS_PER_LIST];
165
+ };
166
+
167
+ typedef struct {
168
+ const int32_t *ordinals;
169
+ uint32_t count;
170
+ int every_candidate;
171
+ } held_links;
172
+
173
+ static inline int32_t load_word(const int32_t *words, uint32_t index) {
174
+ return atomic_load((const _Atomic(int32_t) *)(words + index));
175
+ }
176
+
177
+ static inline _Atomic(int32_t) *atomic_word(int32_t *words, uint32_t index) {
178
+ return (_Atomic(int32_t) *)(words + index);
179
+ }
180
+
181
+ static inline _Atomic(uint8_t) *atomic_byte(uint8_t *bytes, uint32_t index) {
182
+ return (_Atomic(uint8_t) *)(bytes + index);
183
+ }
184
+
185
+ static inline int is_tombstoned(const walk_context *context, int32_t ordinal) {
186
+ return atomic_load(atomic_byte(context->graph->tombstones, (uint32_t)ordinal)) == 1;
187
+ }
188
+
189
+ uint32_t grown_capacity(uint32_t first, uint32_t needed);
190
+
191
+ narsil_status heap_reserve(distance_heap *heap, uint32_t capacity);
192
+ void heap_release(distance_heap *heap);
193
+ narsil_status heap_push(distance_heap *heap, scored_node node);
194
+ int heap_pop(distance_heap *heap);
195
+
196
+ narsil_status list_reserve(scored_list *list, uint32_t capacity);
197
+ void list_release(scored_list *list);
198
+ void list_sort_nearest_first(scored_list *list);
199
+
200
+ void graph_lock_shared(const narsil_graph *graph, uint32_t thread_slot);
201
+ void graph_unlock_shared(const narsil_graph *graph, uint32_t thread_slot);
202
+ void node_lock(const walk_context *context, int32_t ordinal);
203
+ void node_unlock(const walk_context *context, int32_t ordinal);
204
+ void entry_lock(const walk_context *context);
205
+ void entry_unlock(const walk_context *context);
206
+ uint32_t read_neighbours(const walk_context *context, node_layer position, int32_t *out);
207
+
208
+ int32_t node_top_layer(const walk_context *context, int32_t ordinal);
209
+ int32_t *list_at(const walk_context *context, node_layer position, uint32_t *capacity);
210
+ uint32_t list_limit(const narsil_graph *graph, int32_t layer);
211
+ void list_add(const walk_context *context, node_layer position, int32_t neighbour);
212
+ void list_take_out(const walk_context *context, node_layer position, int32_t neighbour);
213
+ void list_replace(const walk_context *context, node_layer position, const int32_t *neighbours, uint32_t count);
214
+ uint32_t select_neighbours(const walk_context *context, scored_list *candidates, uint32_t limit, int32_t *selected);
215
+ void list_prune(const walk_context *context, node_layer position);
216
+ uint32_t stored_count(const int32_t *list, uint32_t capacity);
217
+ void list_write_counted(const walk_context *context, node_layer position, const int32_t *neighbours, uint32_t count);
218
+ int32_t highest_node(const walk_context *context, int include_tombstoned);
219
+
220
+ int32_t incoming_count(const walk_context *context, int32_t ordinal);
221
+ void note_linked(const walk_context *context, int32_t ordinal);
222
+ void note_unlinked(const walk_context *context, int32_t ordinal);
223
+ void note_node_left_unlinked(const walk_context *context);
224
+ void note_nearest_link_due(const walk_context *context, int32_t ordinal);
225
+ narsil_status link_from_nearest(const walk_context *context);
226
+ int release_unless_last(const walk_context *context, int32_t ordinal);
227
+ int is_live(const walk_context *context, int32_t ordinal);
228
+ narsil_status reserve_last_links(narsil_workspace *workspace);
229
+ int list_holds(held_links list, int32_t ordinal);
230
+ uint32_t write_keeping_last_links(const walk_context *context, int32_t ordinal, const scored_list *sorted,
231
+ int32_t *kept, uint32_t kept_count, held_links held);
232
+ void store_entry_point(const walk_context *context, int32_t ordinal);
233
+
234
+ narsil_status workspace_reserve_dimension(narsil_workspace *workspace, uint32_t dimension);
235
+ narsil_status workspace_reserve_visited(narsil_workspace *workspace, uint32_t slots);
236
+ narsil_status workspace_reserve_entry_points(narsil_workspace *workspace, uint32_t count);
237
+ narsil_status workspace_reserve_links(narsil_workspace *workspace, const narsil_graph *graph, uint32_t layers);
238
+
239
+ narsil_status begin_walk(walk_context *context, narsil_workspace *workspace, const narsil_graph *graph,
240
+ const narsil_store *store, uint32_t metric);
241
+ void walk_with_query(walk_context *context, const float *vector);
242
+ void walk_with_placement_query(walk_context *context, const float *vector);
243
+ narsil_status read_graph_extent(walk_context *context);
244
+ void use_single_entry(narsil_workspace *workspace, int32_t ordinal);
245
+ narsil_status search_layer(const walk_context *context, layer_search search, narsil_candidates *out);
246
+ narsil_status descend_layers(const walk_context *context, int32_t first, int32_t last, narsil_candidates *out);
247
+
248
+ void normalise_into(double *normalised, const float *vector, uint32_t dimension);
249
+ void quantise_vector(narsil_workspace *workspace, const narsil_store *store, narsil_metric metric, const float *vector,
250
+ uint32_t bits, quantised_vector *quantised);
251
+ double quantised_level(double value, level_range range, uint32_t bits);
252
+ void prepare_code(narsil_workspace *workspace, const narsil_store *store, narsil_metric metric, const float *vector,
253
+ prepared_code *code);
254
+ void prepare_code_with_bits(narsil_workspace *workspace, const narsil_store *store, narsil_metric metric,
255
+ const float *vector, uint32_t query_bits, prepared_code *code);
256
+ uint32_t code_bytes_of(uint32_t dimension, uint32_t bits);
257
+ uint32_t query_bits_of(uint32_t bits);
258
+ uint32_t placement_query_bits_of(uint32_t bits);
259
+ double estimate_distance(const walk_context *context, const uint8_t *record);
260
+ double estimate_pair_distance(const walk_context *context, const uint8_t *first, const uint8_t *second);
261
+ double pair_distance(const walk_context *context, int32_t first, int32_t second);
262
+
263
+ float kernel_dot(const float *lhs, const float *rhs, uint32_t dimension);
264
+ float kernel_squared_distance(const float *lhs, const float *rhs, uint32_t dimension);
265
+ float kernel_magnitude(const float *values, uint32_t dimension);
266
+ uint32_t kernel_products_8x8(const uint8_t *document, const uint8_t *query, uint32_t dimension);
267
+ uint32_t kernel_products_4x4(const uint8_t *document, const uint8_t *low, const uint8_t *high, uint32_t bytes);
268
+ uint32_t kernel_products_bits(packed_code document, const uint8_t *planes);
269
+ uint32_t kernel_pair_products(packed_code first, const uint8_t *second, uint32_t dimension);
270
+ #ifdef NARSIL_HARDWARE_POPCOUNT
271
+ int uses_hardware_popcount(void);
272
+ #endif
273
+
274
+ int is_metric(uint32_t metric);
275
+ int is_code_width(uint32_t bits);
276
+ int store_is_complete(const narsil_store *store);
277
+ int graph_is_complete(const narsil_graph *graph);
278
+ const float *stored_vector(const narsil_store *store, int32_t ordinal, float *scratch);
279
+ uint8_t *stored_record(const narsil_store *store, int32_t ordinal);
280
+ double float_distance(const walk_context *context, float_query query, int32_t ordinal);
281
+ double walk_distance(const walk_context *context, int32_t ordinal);
282
+ void prefetch_for_walk(const walk_context *context, int32_t ordinal);
283
+
284
+ #endif
@@ -0,0 +1,209 @@
1
+ #include "internal.h"
2
+
3
+ #include <stddef.h>
4
+ #include <stdint.h>
5
+ #include <string.h>
6
+
7
+ #define VECTOR_BYTES 16U
8
+ #define WORD_BYTES 8U
9
+ #define LOW_NIBBLE_MASK 15U
10
+ #define NIBBLE_BITS 4
11
+ #define TWO_BIT_LOW_BITS UINT64_C(0x5555555555555555)
12
+
13
+ #ifdef NARSIL_NEON
14
+ #include <arm_neon.h>
15
+ #endif
16
+
17
+ #ifdef NARSIL_SSE2
18
+ #include <emmintrin.h>
19
+ #endif
20
+
21
+ #ifdef NARSIL_HARDWARE_POPCOUNT
22
+ #include <cpuid.h>
23
+ #include <stdatomic.h>
24
+ #endif
25
+
26
+ #ifdef NARSIL_SSE2
27
+ static inline __m128i load_bytes(const uint8_t *source) {
28
+ __m128i loaded;
29
+ memcpy(&loaded, source, sizeof loaded);
30
+ return loaded;
31
+ }
32
+
33
+ static inline uint32_t sum_of_lanes(__m128i running) {
34
+ uint32_t lane[4];
35
+ memcpy(lane, &running, sizeof lane);
36
+ return lane[0] + lane[1] + lane[2] + lane[3];
37
+ }
38
+ #endif
39
+
40
+ uint32_t kernel_products_8x8(const uint8_t *document, const uint8_t *query, uint32_t dimension) {
41
+ uint32_t total = 0;
42
+ uint32_t offset = 0;
43
+ #ifdef NARSIL_NEON
44
+ uint32x4_t running = vdupq_n_u32(0);
45
+ for (; offset + VECTOR_BYTES <= dimension; offset += VECTOR_BYTES) {
46
+ uint8x16_t document_bytes = vld1q_u8(document + offset);
47
+ uint8x16_t query_bytes = vld1q_u8(query + offset);
48
+ running = vpadalq_u16(running, vmull_u8(vget_low_u8(document_bytes), vget_low_u8(query_bytes)));
49
+ running = vpadalq_u16(running, vmull_u8(vget_high_u8(document_bytes), vget_high_u8(query_bytes)));
50
+ }
51
+ total = vaddvq_u32(running);
52
+ #elif defined(NARSIL_SSE2)
53
+ __m128i zero = _mm_setzero_si128();
54
+ __m128i running = zero;
55
+ for (; offset + VECTOR_BYTES <= dimension; offset += VECTOR_BYTES) {
56
+ __m128i document_bytes = load_bytes(document + offset);
57
+ __m128i query_bytes = load_bytes(query + offset);
58
+ __m128i low = _mm_mullo_epi16(_mm_unpacklo_epi8(document_bytes, zero), _mm_unpacklo_epi8(query_bytes, zero));
59
+ __m128i high = _mm_mullo_epi16(_mm_unpackhi_epi8(document_bytes, zero), _mm_unpackhi_epi8(query_bytes, zero));
60
+ running = _mm_add_epi32(running, _mm_add_epi32(_mm_unpacklo_epi16(low, zero), _mm_unpackhi_epi16(low, zero)));
61
+ running = _mm_add_epi32(running, _mm_add_epi32(_mm_unpacklo_epi16(high, zero), _mm_unpackhi_epi16(high, zero)));
62
+ }
63
+ total = sum_of_lanes(running);
64
+ #endif
65
+ for (; offset < dimension; offset++) { total += (uint32_t)document[offset] * (uint32_t)query[offset]; }
66
+ return total;
67
+ }
68
+
69
+ uint32_t kernel_products_4x4(const uint8_t *document, const uint8_t *low, const uint8_t *high, uint32_t bytes) {
70
+ uint32_t total = 0;
71
+ uint32_t offset = 0;
72
+ #ifdef NARSIL_NEON
73
+ uint8x16_t mask = vdupq_n_u8(LOW_NIBBLE_MASK);
74
+ uint32x4_t running = vdupq_n_u32(0);
75
+ for (; offset + VECTOR_BYTES <= bytes; offset += VECTOR_BYTES) {
76
+ uint8x16_t document_bytes = vld1q_u8(document + offset);
77
+ uint8x16_t document_low = vandq_u8(document_bytes, mask);
78
+ uint8x16_t document_high = vshrq_n_u8(document_bytes, NIBBLE_BITS);
79
+ uint8x16_t low_bytes = vld1q_u8(low + offset);
80
+ uint8x16_t high_bytes = vld1q_u8(high + offset);
81
+ uint16x8_t first = vmlal_u8(vmull_u8(vget_low_u8(document_low), vget_low_u8(low_bytes)), vget_low_u8(document_high),
82
+ vget_low_u8(high_bytes));
83
+ uint16x8_t second = vmlal_u8(vmull_u8(vget_high_u8(document_low), vget_high_u8(low_bytes)),
84
+ vget_high_u8(document_high), vget_high_u8(high_bytes));
85
+ running = vpadalq_u16(vpadalq_u16(running, first), second);
86
+ }
87
+ total = vaddvq_u32(running);
88
+ #elif defined(NARSIL_SSE2)
89
+ __m128i zero = _mm_setzero_si128();
90
+ __m128i mask = _mm_set1_epi8((char)LOW_NIBBLE_MASK);
91
+ __m128i running = zero;
92
+ for (; offset + VECTOR_BYTES <= bytes; offset += VECTOR_BYTES) {
93
+ __m128i document_bytes = load_bytes(document + offset);
94
+ __m128i low_bytes = load_bytes(low + offset);
95
+ __m128i high_bytes = load_bytes(high + offset);
96
+ __m128i document_low = _mm_and_si128(document_bytes, mask);
97
+ __m128i document_high = _mm_and_si128(_mm_srli_epi16(document_bytes, NIBBLE_BITS), mask);
98
+ __m128i even =
99
+ _mm_add_epi32(_mm_madd_epi16(_mm_unpacklo_epi8(document_low, zero), _mm_unpacklo_epi8(low_bytes, zero)),
100
+ _mm_madd_epi16(_mm_unpackhi_epi8(document_low, zero), _mm_unpackhi_epi8(low_bytes, zero)));
101
+ __m128i odd =
102
+ _mm_add_epi32(_mm_madd_epi16(_mm_unpacklo_epi8(document_high, zero), _mm_unpacklo_epi8(high_bytes, zero)),
103
+ _mm_madd_epi16(_mm_unpackhi_epi8(document_high, zero), _mm_unpackhi_epi8(high_bytes, zero)));
104
+ running = _mm_add_epi32(running, _mm_add_epi32(even, odd));
105
+ }
106
+ total = sum_of_lanes(running);
107
+ #endif
108
+ for (; offset < bytes; offset++) {
109
+ total += ((uint32_t)(document[offset] & LOW_NIBBLE_MASK) * low[offset]) +
110
+ ((uint32_t)(document[offset] >> NIBBLE_BITS) * high[offset]);
111
+ }
112
+ return total;
113
+ }
114
+
115
+ INLINED_IN_EACH_KERNEL uint32_t one_bit_products(packed_code document, const uint8_t *planes) {
116
+ uint32_t total = 0;
117
+ uint32_t offset = 0;
118
+ for (; offset + WORD_BYTES <= document.byte_count; offset += WORD_BYTES) {
119
+ uint64_t word = 0;
120
+ memcpy(&word, document.bytes + offset, sizeof word);
121
+ for (uint32_t plane = 0; plane < QUERY_PLANES; plane++) {
122
+ uint64_t query = 0;
123
+ memcpy(&query, planes + ((size_t)plane * document.byte_count) + offset, sizeof query);
124
+ total += (uint32_t)__builtin_popcountll(word & query) << plane;
125
+ }
126
+ }
127
+ for (; offset < document.byte_count; offset++) {
128
+ for (uint32_t plane = 0; plane < QUERY_PLANES; plane++) {
129
+ uint32_t query = planes[((size_t)plane * document.byte_count) + offset];
130
+ total += (uint32_t)__builtin_popcount(document.bytes[offset] & query) << plane;
131
+ }
132
+ }
133
+ return total;
134
+ }
135
+
136
+ INLINED_IN_EACH_KERNEL uint32_t weighted_bits(uint64_t low, uint64_t high, uint64_t plane) {
137
+ return (uint32_t)__builtin_popcountll(low & plane) + (2 * (uint32_t)__builtin_popcountll(high & plane));
138
+ }
139
+
140
+ INLINED_IN_EACH_KERNEL uint32_t two_bit_products(packed_code document, const uint8_t *planes) {
141
+ uint32_t total = 0;
142
+ uint32_t offset = 0;
143
+ for (; offset + WORD_BYTES <= document.byte_count; offset += WORD_BYTES) {
144
+ uint64_t word = 0;
145
+ memcpy(&word, document.bytes + offset, sizeof word);
146
+ uint64_t low = word & TWO_BIT_LOW_BITS;
147
+ uint64_t high = (word >> 1) & TWO_BIT_LOW_BITS;
148
+ for (uint32_t plane = 0; plane < QUERY_PLANES; plane++) {
149
+ uint64_t query = 0;
150
+ memcpy(&query, planes + ((size_t)plane * document.byte_count) + offset, sizeof query);
151
+ total += weighted_bits(low, high, query) << plane;
152
+ }
153
+ }
154
+ for (; offset < document.byte_count; offset++) {
155
+ uint64_t low = document.bytes[offset] & TWO_BIT_LOW_BITS;
156
+ uint64_t high = ((uint64_t)document.bytes[offset] >> 1) & TWO_BIT_LOW_BITS;
157
+ for (uint32_t plane = 0; plane < QUERY_PLANES; plane++) {
158
+ total += weighted_bits(low, high, planes[((size_t)plane * document.byte_count) + offset]) << plane;
159
+ }
160
+ }
161
+ return total;
162
+ }
163
+
164
+ #ifdef NARSIL_HARDWARE_POPCOUNT
165
+ #define POPCOUNT_UNKNOWN 0
166
+ #define POPCOUNT_ABSENT 1
167
+ #define POPCOUNT_PRESENT 2
168
+ #define CPUID_FEATURES_LEAF 1U
169
+
170
+ static atomic_int popcount_state = POPCOUNT_UNKNOWN;
171
+
172
+ static int processor_counts_bits(void) {
173
+ unsigned int eax = 0;
174
+ unsigned int ebx = 0;
175
+ unsigned int ecx = 0;
176
+ unsigned int edx = 0;
177
+ if (!__get_cpuid(CPUID_FEATURES_LEAF, &eax, &ebx, &ecx, &edx)) { return 0; }
178
+ return (ecx & bit_POPCNT) != 0;
179
+ }
180
+
181
+ int uses_hardware_popcount(void) {
182
+ int state = atomic_load_explicit(&popcount_state, memory_order_relaxed);
183
+ if (state == POPCOUNT_UNKNOWN) {
184
+ state = processor_counts_bits() ? POPCOUNT_PRESENT : POPCOUNT_ABSENT;
185
+ atomic_store_explicit(&popcount_state, state, memory_order_relaxed);
186
+ }
187
+ return state == POPCOUNT_PRESENT;
188
+ }
189
+
190
+ __attribute__((target("popcnt"))) static uint32_t one_bit_products_with_popcnt(packed_code document,
191
+ const uint8_t *planes) {
192
+ return one_bit_products(document, planes);
193
+ }
194
+
195
+ __attribute__((target("popcnt"))) static uint32_t two_bit_products_with_popcnt(packed_code document,
196
+ const uint8_t *planes) {
197
+ return two_bit_products(document, planes);
198
+ }
199
+ #endif
200
+
201
+ uint32_t kernel_products_bits(packed_code document, const uint8_t *planes) {
202
+ #ifdef NARSIL_HARDWARE_POPCOUNT
203
+ if (uses_hardware_popcount()) {
204
+ return document.bits == 2 ? two_bit_products_with_popcnt(document, planes)
205
+ : one_bit_products_with_popcnt(document, planes);
206
+ }
207
+ #endif
208
+ return document.bits == 2 ? two_bit_products(document, planes) : one_bit_products(document, planes);
209
+ }