hnswlib 0.6.2 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,329 +3,324 @@
3
3
 
4
4
  namespace hnswlib {
5
5
 
6
- static float
7
- L2Sqr(const void *pVect1v, const void *pVect2v, const void *qty_ptr) {
8
- float *pVect1 = (float *) pVect1v;
9
- float *pVect2 = (float *) pVect2v;
10
- size_t qty = *((size_t *) qty_ptr);
11
-
12
- float res = 0;
13
- for (size_t i = 0; i < qty; i++) {
14
- float t = *pVect1 - *pVect2;
15
- pVect1++;
16
- pVect2++;
17
- res += t * t;
18
- }
19
- return (res);
6
+ static float
7
+ L2Sqr(const void *pVect1v, const void *pVect2v, const void *qty_ptr) {
8
+ float *pVect1 = (float *) pVect1v;
9
+ float *pVect2 = (float *) pVect2v;
10
+ size_t qty = *((size_t *) qty_ptr);
11
+
12
+ float res = 0;
13
+ for (size_t i = 0; i < qty; i++) {
14
+ float t = *pVect1 - *pVect2;
15
+ pVect1++;
16
+ pVect2++;
17
+ res += t * t;
20
18
  }
19
+ return (res);
20
+ }
21
21
 
22
22
  #if defined(USE_AVX512)
23
23
 
24
- // Favor using AVX512 if available.
25
- static float
26
- L2SqrSIMD16ExtAVX512(const void *pVect1v, const void *pVect2v, const void *qty_ptr) {
27
- float *pVect1 = (float *) pVect1v;
28
- float *pVect2 = (float *) pVect2v;
29
- size_t qty = *((size_t *) qty_ptr);
30
- float PORTABLE_ALIGN64 TmpRes[16];
31
- size_t qty16 = qty >> 4;
32
-
33
- const float *pEnd1 = pVect1 + (qty16 << 4);
34
-
35
- __m512 diff, v1, v2;
36
- __m512 sum = _mm512_set1_ps(0);
37
-
38
- while (pVect1 < pEnd1) {
39
- v1 = _mm512_loadu_ps(pVect1);
40
- pVect1 += 16;
41
- v2 = _mm512_loadu_ps(pVect2);
42
- pVect2 += 16;
43
- diff = _mm512_sub_ps(v1, v2);
44
- // sum = _mm512_fmadd_ps(diff, diff, sum);
45
- sum = _mm512_add_ps(sum, _mm512_mul_ps(diff, diff));
46
- }
24
+ // Favor using AVX512 if available.
25
+ static float
26
+ L2SqrSIMD16ExtAVX512(const void *pVect1v, const void *pVect2v, const void *qty_ptr) {
27
+ float *pVect1 = (float *) pVect1v;
28
+ float *pVect2 = (float *) pVect2v;
29
+ size_t qty = *((size_t *) qty_ptr);
30
+ float PORTABLE_ALIGN64 TmpRes[16];
31
+ size_t qty16 = qty >> 4;
32
+
33
+ const float *pEnd1 = pVect1 + (qty16 << 4);
34
+
35
+ __m512 diff, v1, v2;
36
+ __m512 sum = _mm512_set1_ps(0);
37
+
38
+ while (pVect1 < pEnd1) {
39
+ v1 = _mm512_loadu_ps(pVect1);
40
+ pVect1 += 16;
41
+ v2 = _mm512_loadu_ps(pVect2);
42
+ pVect2 += 16;
43
+ diff = _mm512_sub_ps(v1, v2);
44
+ // sum = _mm512_fmadd_ps(diff, diff, sum);
45
+ sum = _mm512_add_ps(sum, _mm512_mul_ps(diff, diff));
46
+ }
47
47
 
48
- _mm512_store_ps(TmpRes, sum);
49
- float res = TmpRes[0] + TmpRes[1] + TmpRes[2] + TmpRes[3] + TmpRes[4] + TmpRes[5] + TmpRes[6] +
50
- TmpRes[7] + TmpRes[8] + TmpRes[9] + TmpRes[10] + TmpRes[11] + TmpRes[12] +
51
- TmpRes[13] + TmpRes[14] + TmpRes[15];
48
+ _mm512_store_ps(TmpRes, sum);
49
+ float res = TmpRes[0] + TmpRes[1] + TmpRes[2] + TmpRes[3] + TmpRes[4] + TmpRes[5] + TmpRes[6] +
50
+ TmpRes[7] + TmpRes[8] + TmpRes[9] + TmpRes[10] + TmpRes[11] + TmpRes[12] +
51
+ TmpRes[13] + TmpRes[14] + TmpRes[15];
52
52
 
53
- return (res);
53
+ return (res);
54
54
  }
55
55
  #endif
56
56
 
57
57
  #if defined(USE_AVX)
58
58
 
59
- // Favor using AVX if available.
60
- static float
61
- L2SqrSIMD16ExtAVX(const void *pVect1v, const void *pVect2v, const void *qty_ptr) {
62
- float *pVect1 = (float *) pVect1v;
63
- float *pVect2 = (float *) pVect2v;
64
- size_t qty = *((size_t *) qty_ptr);
65
- float PORTABLE_ALIGN32 TmpRes[8];
66
- size_t qty16 = qty >> 4;
67
-
68
- const float *pEnd1 = pVect1 + (qty16 << 4);
69
-
70
- __m256 diff, v1, v2;
71
- __m256 sum = _mm256_set1_ps(0);
72
-
73
- while (pVect1 < pEnd1) {
74
- v1 = _mm256_loadu_ps(pVect1);
75
- pVect1 += 8;
76
- v2 = _mm256_loadu_ps(pVect2);
77
- pVect2 += 8;
78
- diff = _mm256_sub_ps(v1, v2);
79
- sum = _mm256_add_ps(sum, _mm256_mul_ps(diff, diff));
80
-
81
- v1 = _mm256_loadu_ps(pVect1);
82
- pVect1 += 8;
83
- v2 = _mm256_loadu_ps(pVect2);
84
- pVect2 += 8;
85
- diff = _mm256_sub_ps(v1, v2);
86
- sum = _mm256_add_ps(sum, _mm256_mul_ps(diff, diff));
87
- }
88
-
89
- _mm256_store_ps(TmpRes, sum);
90
- return TmpRes[0] + TmpRes[1] + TmpRes[2] + TmpRes[3] + TmpRes[4] + TmpRes[5] + TmpRes[6] + TmpRes[7];
59
+ // Favor using AVX if available.
60
+ static float
61
+ L2SqrSIMD16ExtAVX(const void *pVect1v, const void *pVect2v, const void *qty_ptr) {
62
+ float *pVect1 = (float *) pVect1v;
63
+ float *pVect2 = (float *) pVect2v;
64
+ size_t qty = *((size_t *) qty_ptr);
65
+ float PORTABLE_ALIGN32 TmpRes[8];
66
+ size_t qty16 = qty >> 4;
67
+
68
+ const float *pEnd1 = pVect1 + (qty16 << 4);
69
+
70
+ __m256 diff, v1, v2;
71
+ __m256 sum = _mm256_set1_ps(0);
72
+
73
+ while (pVect1 < pEnd1) {
74
+ v1 = _mm256_loadu_ps(pVect1);
75
+ pVect1 += 8;
76
+ v2 = _mm256_loadu_ps(pVect2);
77
+ pVect2 += 8;
78
+ diff = _mm256_sub_ps(v1, v2);
79
+ sum = _mm256_add_ps(sum, _mm256_mul_ps(diff, diff));
80
+
81
+ v1 = _mm256_loadu_ps(pVect1);
82
+ pVect1 += 8;
83
+ v2 = _mm256_loadu_ps(pVect2);
84
+ pVect2 += 8;
85
+ diff = _mm256_sub_ps(v1, v2);
86
+ sum = _mm256_add_ps(sum, _mm256_mul_ps(diff, diff));
91
87
  }
92
88
 
89
+ _mm256_store_ps(TmpRes, sum);
90
+ return TmpRes[0] + TmpRes[1] + TmpRes[2] + TmpRes[3] + TmpRes[4] + TmpRes[5] + TmpRes[6] + TmpRes[7];
91
+ }
92
+
93
93
  #endif
94
94
 
95
95
  #if defined(USE_SSE)
96
96
 
97
- static float
98
- L2SqrSIMD16ExtSSE(const void *pVect1v, const void *pVect2v, const void *qty_ptr) {
99
- float *pVect1 = (float *) pVect1v;
100
- float *pVect2 = (float *) pVect2v;
101
- size_t qty = *((size_t *) qty_ptr);
102
- float PORTABLE_ALIGN32 TmpRes[8];
103
- size_t qty16 = qty >> 4;
104
-
105
- const float *pEnd1 = pVect1 + (qty16 << 4);
106
-
107
- __m128 diff, v1, v2;
108
- __m128 sum = _mm_set1_ps(0);
109
-
110
- while (pVect1 < pEnd1) {
111
- //_mm_prefetch((char*)(pVect2 + 16), _MM_HINT_T0);
112
- v1 = _mm_loadu_ps(pVect1);
113
- pVect1 += 4;
114
- v2 = _mm_loadu_ps(pVect2);
115
- pVect2 += 4;
116
- diff = _mm_sub_ps(v1, v2);
117
- sum = _mm_add_ps(sum, _mm_mul_ps(diff, diff));
118
-
119
- v1 = _mm_loadu_ps(pVect1);
120
- pVect1 += 4;
121
- v2 = _mm_loadu_ps(pVect2);
122
- pVect2 += 4;
123
- diff = _mm_sub_ps(v1, v2);
124
- sum = _mm_add_ps(sum, _mm_mul_ps(diff, diff));
125
-
126
- v1 = _mm_loadu_ps(pVect1);
127
- pVect1 += 4;
128
- v2 = _mm_loadu_ps(pVect2);
129
- pVect2 += 4;
130
- diff = _mm_sub_ps(v1, v2);
131
- sum = _mm_add_ps(sum, _mm_mul_ps(diff, diff));
132
-
133
- v1 = _mm_loadu_ps(pVect1);
134
- pVect1 += 4;
135
- v2 = _mm_loadu_ps(pVect2);
136
- pVect2 += 4;
137
- diff = _mm_sub_ps(v1, v2);
138
- sum = _mm_add_ps(sum, _mm_mul_ps(diff, diff));
139
- }
140
-
141
- _mm_store_ps(TmpRes, sum);
142
- return TmpRes[0] + TmpRes[1] + TmpRes[2] + TmpRes[3];
97
+ static float
98
+ L2SqrSIMD16ExtSSE(const void *pVect1v, const void *pVect2v, const void *qty_ptr) {
99
+ float *pVect1 = (float *) pVect1v;
100
+ float *pVect2 = (float *) pVect2v;
101
+ size_t qty = *((size_t *) qty_ptr);
102
+ float PORTABLE_ALIGN32 TmpRes[8];
103
+ size_t qty16 = qty >> 4;
104
+
105
+ const float *pEnd1 = pVect1 + (qty16 << 4);
106
+
107
+ __m128 diff, v1, v2;
108
+ __m128 sum = _mm_set1_ps(0);
109
+
110
+ while (pVect1 < pEnd1) {
111
+ //_mm_prefetch((char*)(pVect2 + 16), _MM_HINT_T0);
112
+ v1 = _mm_loadu_ps(pVect1);
113
+ pVect1 += 4;
114
+ v2 = _mm_loadu_ps(pVect2);
115
+ pVect2 += 4;
116
+ diff = _mm_sub_ps(v1, v2);
117
+ sum = _mm_add_ps(sum, _mm_mul_ps(diff, diff));
118
+
119
+ v1 = _mm_loadu_ps(pVect1);
120
+ pVect1 += 4;
121
+ v2 = _mm_loadu_ps(pVect2);
122
+ pVect2 += 4;
123
+ diff = _mm_sub_ps(v1, v2);
124
+ sum = _mm_add_ps(sum, _mm_mul_ps(diff, diff));
125
+
126
+ v1 = _mm_loadu_ps(pVect1);
127
+ pVect1 += 4;
128
+ v2 = _mm_loadu_ps(pVect2);
129
+ pVect2 += 4;
130
+ diff = _mm_sub_ps(v1, v2);
131
+ sum = _mm_add_ps(sum, _mm_mul_ps(diff, diff));
132
+
133
+ v1 = _mm_loadu_ps(pVect1);
134
+ pVect1 += 4;
135
+ v2 = _mm_loadu_ps(pVect2);
136
+ pVect2 += 4;
137
+ diff = _mm_sub_ps(v1, v2);
138
+ sum = _mm_add_ps(sum, _mm_mul_ps(diff, diff));
143
139
  }
140
+
141
+ _mm_store_ps(TmpRes, sum);
142
+ return TmpRes[0] + TmpRes[1] + TmpRes[2] + TmpRes[3];
143
+ }
144
144
  #endif
145
145
 
146
146
  #if defined(USE_SSE) || defined(USE_AVX) || defined(USE_AVX512)
147
- DISTFUNC<float> L2SqrSIMD16Ext = L2SqrSIMD16ExtSSE;
148
-
149
- static float
150
- L2SqrSIMD16ExtResiduals(const void *pVect1v, const void *pVect2v, const void *qty_ptr) {
151
- size_t qty = *((size_t *) qty_ptr);
152
- size_t qty16 = qty >> 4 << 4;
153
- float res = L2SqrSIMD16Ext(pVect1v, pVect2v, &qty16);
154
- float *pVect1 = (float *) pVect1v + qty16;
155
- float *pVect2 = (float *) pVect2v + qty16;
156
-
157
- size_t qty_left = qty - qty16;
158
- float res_tail = L2Sqr(pVect1, pVect2, &qty_left);
159
- return (res + res_tail);
160
- }
147
+ static DISTFUNC<float> L2SqrSIMD16Ext = L2SqrSIMD16ExtSSE;
148
+
149
+ static float
150
+ L2SqrSIMD16ExtResiduals(const void *pVect1v, const void *pVect2v, const void *qty_ptr) {
151
+ size_t qty = *((size_t *) qty_ptr);
152
+ size_t qty16 = qty >> 4 << 4;
153
+ float res = L2SqrSIMD16Ext(pVect1v, pVect2v, &qty16);
154
+ float *pVect1 = (float *) pVect1v + qty16;
155
+ float *pVect2 = (float *) pVect2v + qty16;
156
+
157
+ size_t qty_left = qty - qty16;
158
+ float res_tail = L2Sqr(pVect1, pVect2, &qty_left);
159
+ return (res + res_tail);
160
+ }
161
161
  #endif
162
162
 
163
163
 
164
164
  #if defined(USE_SSE)
165
- static float
166
- L2SqrSIMD4Ext(const void *pVect1v, const void *pVect2v, const void *qty_ptr) {
167
- float PORTABLE_ALIGN32 TmpRes[8];
168
- float *pVect1 = (float *) pVect1v;
169
- float *pVect2 = (float *) pVect2v;
170
- size_t qty = *((size_t *) qty_ptr);
165
+ static float
166
+ L2SqrSIMD4Ext(const void *pVect1v, const void *pVect2v, const void *qty_ptr) {
167
+ float PORTABLE_ALIGN32 TmpRes[8];
168
+ float *pVect1 = (float *) pVect1v;
169
+ float *pVect2 = (float *) pVect2v;
170
+ size_t qty = *((size_t *) qty_ptr);
171
171
 
172
172
 
173
- size_t qty4 = qty >> 2;
173
+ size_t qty4 = qty >> 2;
174
174
 
175
- const float *pEnd1 = pVect1 + (qty4 << 2);
175
+ const float *pEnd1 = pVect1 + (qty4 << 2);
176
176
 
177
- __m128 diff, v1, v2;
178
- __m128 sum = _mm_set1_ps(0);
177
+ __m128 diff, v1, v2;
178
+ __m128 sum = _mm_set1_ps(0);
179
179
 
180
- while (pVect1 < pEnd1) {
181
- v1 = _mm_loadu_ps(pVect1);
182
- pVect1 += 4;
183
- v2 = _mm_loadu_ps(pVect2);
184
- pVect2 += 4;
185
- diff = _mm_sub_ps(v1, v2);
186
- sum = _mm_add_ps(sum, _mm_mul_ps(diff, diff));
187
- }
188
- _mm_store_ps(TmpRes, sum);
189
- return TmpRes[0] + TmpRes[1] + TmpRes[2] + TmpRes[3];
180
+ while (pVect1 < pEnd1) {
181
+ v1 = _mm_loadu_ps(pVect1);
182
+ pVect1 += 4;
183
+ v2 = _mm_loadu_ps(pVect2);
184
+ pVect2 += 4;
185
+ diff = _mm_sub_ps(v1, v2);
186
+ sum = _mm_add_ps(sum, _mm_mul_ps(diff, diff));
190
187
  }
188
+ _mm_store_ps(TmpRes, sum);
189
+ return TmpRes[0] + TmpRes[1] + TmpRes[2] + TmpRes[3];
190
+ }
191
191
 
192
- static float
193
- L2SqrSIMD4ExtResiduals(const void *pVect1v, const void *pVect2v, const void *qty_ptr) {
194
- size_t qty = *((size_t *) qty_ptr);
195
- size_t qty4 = qty >> 2 << 2;
192
+ static float
193
+ L2SqrSIMD4ExtResiduals(const void *pVect1v, const void *pVect2v, const void *qty_ptr) {
194
+ size_t qty = *((size_t *) qty_ptr);
195
+ size_t qty4 = qty >> 2 << 2;
196
196
 
197
- float res = L2SqrSIMD4Ext(pVect1v, pVect2v, &qty4);
198
- size_t qty_left = qty - qty4;
197
+ float res = L2SqrSIMD4Ext(pVect1v, pVect2v, &qty4);
198
+ size_t qty_left = qty - qty4;
199
199
 
200
- float *pVect1 = (float *) pVect1v + qty4;
201
- float *pVect2 = (float *) pVect2v + qty4;
202
- float res_tail = L2Sqr(pVect1, pVect2, &qty_left);
200
+ float *pVect1 = (float *) pVect1v + qty4;
201
+ float *pVect2 = (float *) pVect2v + qty4;
202
+ float res_tail = L2Sqr(pVect1, pVect2, &qty_left);
203
203
 
204
- return (res + res_tail);
205
- }
204
+ return (res + res_tail);
205
+ }
206
206
  #endif
207
207
 
208
- class L2Space : public SpaceInterface<float> {
209
-
210
- DISTFUNC<float> fstdistfunc_;
211
- size_t data_size_;
212
- size_t dim_;
213
- public:
214
- L2Space() : data_size_(0), dim_(0) { }
215
- L2Space(size_t dim) {
216
- fstdistfunc_ = L2Sqr;
217
- #if defined(USE_SSE) || defined(USE_AVX) || defined(USE_AVX512)
218
- #if defined(USE_AVX512)
219
- if (AVX512Capable())
220
- L2SqrSIMD16Ext = L2SqrSIMD16ExtAVX512;
221
- else if (AVXCapable())
222
- L2SqrSIMD16Ext = L2SqrSIMD16ExtAVX;
223
- #elif defined(USE_AVX)
224
- if (AVXCapable())
225
- L2SqrSIMD16Ext = L2SqrSIMD16ExtAVX;
226
- #endif
227
-
228
- if (dim % 16 == 0)
229
- fstdistfunc_ = L2SqrSIMD16Ext;
230
- else if (dim % 4 == 0)
231
- fstdistfunc_ = L2SqrSIMD4Ext;
232
- else if (dim > 16)
233
- fstdistfunc_ = L2SqrSIMD16ExtResiduals;
234
- else if (dim > 4)
235
- fstdistfunc_ = L2SqrSIMD4ExtResiduals;
208
+ class L2Space : public SpaceInterface<float> {
209
+ DISTFUNC<float> fstdistfunc_;
210
+ size_t data_size_;
211
+ size_t dim_;
212
+
213
+ public:
214
+ L2Space() : data_size_(0), dim_(0) { }
215
+
216
+ L2Space(size_t dim) {
217
+ fstdistfunc_ = L2Sqr;
218
+ #if defined(USE_SSE) || defined(USE_AVX) || defined(USE_AVX512)
219
+ #if defined(USE_AVX512)
220
+ if (AVX512Capable())
221
+ L2SqrSIMD16Ext = L2SqrSIMD16ExtAVX512;
222
+ else if (AVXCapable())
223
+ L2SqrSIMD16Ext = L2SqrSIMD16ExtAVX;
224
+ #elif defined(USE_AVX)
225
+ if (AVXCapable())
226
+ L2SqrSIMD16Ext = L2SqrSIMD16ExtAVX;
236
227
  #endif
237
- dim_ = dim;
238
- data_size_ = dim * sizeof(float);
239
- }
240
228
 
241
- size_t get_data_size() {
242
- return data_size_;
243
- }
229
+ if (dim % 16 == 0)
230
+ fstdistfunc_ = L2SqrSIMD16Ext;
231
+ else if (dim % 4 == 0)
232
+ fstdistfunc_ = L2SqrSIMD4Ext;
233
+ else if (dim > 16)
234
+ fstdistfunc_ = L2SqrSIMD16ExtResiduals;
235
+ else if (dim > 4)
236
+ fstdistfunc_ = L2SqrSIMD4ExtResiduals;
237
+ #endif
238
+ dim_ = dim;
239
+ data_size_ = dim * sizeof(float);
240
+ }
244
241
 
245
- DISTFUNC<float> get_dist_func() {
246
- return fstdistfunc_;
247
- }
242
+ size_t get_data_size() {
243
+ return data_size_;
244
+ }
248
245
 
249
- void *get_dist_func_param() {
250
- return &dim_;
251
- }
246
+ DISTFUNC<float> get_dist_func() {
247
+ return fstdistfunc_;
248
+ }
252
249
 
253
- ~L2Space() {}
254
- };
255
-
256
- static int
257
- L2SqrI4x(const void *__restrict pVect1, const void *__restrict pVect2, const void *__restrict qty_ptr) {
258
-
259
- size_t qty = *((size_t *) qty_ptr);
260
- int res = 0;
261
- unsigned char *a = (unsigned char *) pVect1;
262
- unsigned char *b = (unsigned char *) pVect2;
263
-
264
- qty = qty >> 2;
265
- for (size_t i = 0; i < qty; i++) {
266
-
267
- res += ((*a) - (*b)) * ((*a) - (*b));
268
- a++;
269
- b++;
270
- res += ((*a) - (*b)) * ((*a) - (*b));
271
- a++;
272
- b++;
273
- res += ((*a) - (*b)) * ((*a) - (*b));
274
- a++;
275
- b++;
276
- res += ((*a) - (*b)) * ((*a) - (*b));
277
- a++;
278
- b++;
279
- }
280
- return (res);
250
+ void *get_dist_func_param() {
251
+ return &dim_;
281
252
  }
282
253
 
283
- static int L2SqrI(const void* __restrict pVect1, const void* __restrict pVect2, const void* __restrict qty_ptr) {
284
- size_t qty = *((size_t*)qty_ptr);
285
- int res = 0;
286
- unsigned char* a = (unsigned char*)pVect1;
287
- unsigned char* b = (unsigned char*)pVect2;
288
-
289
- for(size_t i = 0; i < qty; i++)
290
- {
291
- res += ((*a) - (*b)) * ((*a) - (*b));
292
- a++;
293
- b++;
294
- }
295
- return (res);
254
+ ~L2Space() {}
255
+ };
256
+
257
+ static int
258
+ L2SqrI4x(const void *__restrict pVect1, const void *__restrict pVect2, const void *__restrict qty_ptr) {
259
+ size_t qty = *((size_t *) qty_ptr);
260
+ int res = 0;
261
+ unsigned char *a = (unsigned char *) pVect1;
262
+ unsigned char *b = (unsigned char *) pVect2;
263
+
264
+ qty = qty >> 2;
265
+ for (size_t i = 0; i < qty; i++) {
266
+ res += ((*a) - (*b)) * ((*a) - (*b));
267
+ a++;
268
+ b++;
269
+ res += ((*a) - (*b)) * ((*a) - (*b));
270
+ a++;
271
+ b++;
272
+ res += ((*a) - (*b)) * ((*a) - (*b));
273
+ a++;
274
+ b++;
275
+ res += ((*a) - (*b)) * ((*a) - (*b));
276
+ a++;
277
+ b++;
296
278
  }
279
+ return (res);
280
+ }
297
281
 
298
- class L2SpaceI : public SpaceInterface<int> {
299
-
300
- DISTFUNC<int> fstdistfunc_;
301
- size_t data_size_;
302
- size_t dim_;
303
- public:
304
- L2SpaceI(size_t dim) {
305
- if(dim % 4 == 0) {
306
- fstdistfunc_ = L2SqrI4x;
307
- }
308
- else {
309
- fstdistfunc_ = L2SqrI;
310
- }
311
- dim_ = dim;
312
- data_size_ = dim * sizeof(unsigned char);
313
- }
282
+ static int L2SqrI(const void* __restrict pVect1, const void* __restrict pVect2, const void* __restrict qty_ptr) {
283
+ size_t qty = *((size_t*)qty_ptr);
284
+ int res = 0;
285
+ unsigned char* a = (unsigned char*)pVect1;
286
+ unsigned char* b = (unsigned char*)pVect2;
314
287
 
315
- size_t get_data_size() {
316
- return data_size_;
317
- }
288
+ for (size_t i = 0; i < qty; i++) {
289
+ res += ((*a) - (*b)) * ((*a) - (*b));
290
+ a++;
291
+ b++;
292
+ }
293
+ return (res);
294
+ }
318
295
 
319
- DISTFUNC<int> get_dist_func() {
320
- return fstdistfunc_;
296
+ class L2SpaceI : public SpaceInterface<int> {
297
+ DISTFUNC<int> fstdistfunc_;
298
+ size_t data_size_;
299
+ size_t dim_;
300
+
301
+ public:
302
+ L2SpaceI(size_t dim) {
303
+ if (dim % 4 == 0) {
304
+ fstdistfunc_ = L2SqrI4x;
305
+ } else {
306
+ fstdistfunc_ = L2SqrI;
321
307
  }
308
+ dim_ = dim;
309
+ data_size_ = dim * sizeof(unsigned char);
310
+ }
322
311
 
323
- void *get_dist_func_param() {
324
- return &dim_;
325
- }
312
+ size_t get_data_size() {
313
+ return data_size_;
314
+ }
326
315
 
327
- ~L2SpaceI() {}
328
- };
316
+ DISTFUNC<int> get_dist_func() {
317
+ return fstdistfunc_;
318
+ }
329
319
 
320
+ void *get_dist_func_param() {
321
+ return &dim_;
322
+ }
330
323
 
331
- }
324
+ ~L2SpaceI() {}
325
+ };
326
+ } // namespace hnswlib