Skip to content

Commit ee63e64

Browse files
committed
Merge branch 'main-dev' of https://github.com/unum-cloud/usearch into main-dev
2 parents fef9234 + 02270d9 commit ee63e64

File tree

3 files changed

+76
-47
lines changed

3 files changed

+76
-47
lines changed

cpp/README.md

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,29 @@ Once included, the high-level C++11 interface is as simple as it gets: `reserve(
1616
This covers 90% of use cases.
1717

1818
```cpp
19-
using namespace unum::usearch;
20-
21-
metric_punned_t metric(256, metric_kind_t::l2sq_k, scalar_kind_t::f32_k);
19+
#include <usearch/index.hpp>
20+
#include <usearch/index_dense.hpp>
2221

23-
// If you plan to store more than 4 Billion entries - use `index_dense_big_t`.
24-
// Or directly instantiate the template variant you need - `index_dense_gt<vector_key_t, internal_id_t>`.
25-
index_dense_t index = index_dense_t::make(metric);
26-
float vec[3] = {0.1, 0.3, 0.2};
27-
28-
index.reserve(10); // Pre-allocate memory for 10 vectors
29-
index.add(42, &vec[0]); // Pass a key and a vector
30-
auto results = index.search(&vec[0], 5); // Pass a query and limit number of results
22+
using namespace unum::usearch;
3123

32-
for (std::size_t i = 0; i != results.size(); ++i)
33-
results[i].element.key, results[i].element.vector, results[i].distance;
24+
int main(int argc, char **argv) {
25+
metric_punned_t metric(3, metric_kind_t::l2sq_k, scalar_kind_t::f32_k);
26+
27+
// If you plan to store more than 4 Billion entries - use `index_dense_big_t`.
28+
// Or directly instantiate the template variant you need - `index_dense_gt<vector_key_t, internal_id_t>`.
29+
index_dense_t index = index_dense_t::make(metric);
30+
float vec[3] = {0.1, 0.3, 0.2};
31+
32+
index.reserve(10); // Pre-allocate memory for 10 vectors
33+
index.add(42, &vec[0]); // Pass a key and a vector
34+
auto results = index.search(&vec[0], 5); // Pass a query and limit number of results
35+
36+
for (std::size_t i = 0; i != results.size(); ++i)
37+
// You can access the following properties of every match:
38+
// results[i].element.key, results[i].element.vector, results[i].distance;
39+
std::printf("Found matching key: %zu", results[i].element.key);
40+
return 0;
41+
}
3442
```
3543
3644
Here we:

cpp/test.cpp

Lines changed: 51 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -122,33 +122,6 @@ void test_uint40() {
122122
}
123123
}
124124

125-
/**
126-
* Tests the behavior of various move-constructors and move-assignment operators for the index.
127-
*
128-
* Constructs an index and performs tests with it before and after move operations to ensure that the index maintains
129-
* its integrity and functionality after being moved.
130-
*
131-
* @param config Configuration settings for the index.
132-
* @tparam index_at Type of the index being tested.
133-
*/
134-
template <typename index_at> void test_move_constructors(index_config_t const& config) {
135-
{
136-
index_at index{config};
137-
test_sets(index);
138-
}
139-
{
140-
index_at index{config};
141-
index.reserve(1);
142-
test_sets(index_at(std::move(index)));
143-
}
144-
{
145-
index_at index{config};
146-
index.reserve(1);
147-
index_at index_moved = std::move(index);
148-
test_sets(index_moved);
149-
}
150-
}
151-
152125
/**
153126
* The goal of this test is to invoke as many different interfaces as possible, making sure that all code-paths compile.
154127
* For that it only uses a tiny set of 3 predefined vectors.
@@ -199,15 +172,18 @@ void test_minimal_three_vectors(index_at& index, //
199172
index.add(key_third, vector_third.data(), args...);
200173
expect(index.size() == 3);
201174

202-
// Perform exact search
203-
matched_count = index.search(vector_first.data(), 5, args...).dump_to(matched_keys, matched_distances);
175+
// Perform single entry search
176+
matched_count = index //
177+
.search(vector_first.data(), 5, args...) //
178+
.dump_to(matched_keys, matched_distances);
204179
expect(matched_count != 0);
205180

206181
// Perform filtered exact search, keeping only odd values
207182
if constexpr (punned_ak) {
208183
auto is_odd = [](vector_key_t key) -> bool { return (key & 1) != 0; };
209-
matched_count =
210-
index.filtered_search(vector_first.data(), 5, is_odd, args...).dump_to(matched_keys, matched_distances);
184+
matched_count = index //
185+
.filtered_search(vector_first.data(), 5, is_odd, args...) //
186+
.dump_to(matched_keys, matched_distances);
211187
expect(matched_count != 0);
212188
for (std::size_t i = 0; i < matched_count; i++)
213189
expect(is_odd(matched_keys[i]));
@@ -240,6 +216,50 @@ void test_minimal_three_vectors(index_at& index, //
240216

241217
index.save("tmp.usearch");
242218

219+
// Perform content and scan validations for a copy
220+
{
221+
auto copy_result = index.copy();
222+
expect(bool(copy_result));
223+
auto& copied_index = copy_result.index;
224+
225+
// Perform single entry search
226+
matched_count = copied_index //
227+
.search(vector_first.data(), 5, args...) //
228+
.dump_to(matched_keys, matched_distances);
229+
expect(matched_count != 0);
230+
231+
// Validate scans
232+
std::size_t count = 0;
233+
for (auto member : copied_index) {
234+
vector_key_t id = member.key;
235+
expect(id >= key_first && id <= key_third);
236+
count++;
237+
}
238+
expect((count == 3));
239+
expect((copied_index.stats(0).nodes == 3));
240+
}
241+
242+
// Perform content and scan validations for a moved
243+
{
244+
index_at moved_index(std::move(index));
245+
246+
// Perform single entry search
247+
matched_count = moved_index //
248+
.search(vector_first.data(), 5, args...) //
249+
.dump_to(matched_keys, matched_distances);
250+
expect(matched_count != 0);
251+
252+
// Validate scans
253+
std::size_t count = 0;
254+
for (auto member : moved_index) {
255+
vector_key_t id = member.key;
256+
expect(id >= key_first && id <= key_third);
257+
count++;
258+
}
259+
expect((count == 3));
260+
expect((moved_index.stats(0).nodes == 3));
261+
}
262+
243263
// Check if metadata is retrieved correctly
244264
if constexpr (punned_ak) {
245265
auto head = index_dense_metadata_from_path("tmp.usearch");

include/usearch/index_dense.hpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1523,11 +1523,12 @@ class index_dense_gt {
15231523
if (!config.force_vector_copy && copy.config_.exclude_vectors) {
15241524
std::memcpy(copy.vectors_lookup_.data(), vectors_lookup_.data(), vectors_lookup_.size() * sizeof(byte_t*));
15251525
} else {
1526-
for (std::size_t slot = 0; slot != vectors_lookup_.size(); ++slot)
1526+
std::size_t slots_count = typed_result.index.size();
1527+
for (std::size_t slot = 0; slot != slots_count; ++slot)
15271528
copy.vectors_lookup_[slot] = copy.vectors_tape_allocator_.allocate(copy.metric_.bytes_per_vector());
1528-
if (std::count(copy.vectors_lookup_.begin(), copy.vectors_lookup_.end(), nullptr))
1529+
if (std::count(copy.vectors_lookup_.begin(), copy.vectors_lookup_.begin() + slots_count, nullptr))
15291530
return result.failed("Out of memory!");
1530-
for (std::size_t slot = 0; slot != vectors_lookup_.size(); ++slot)
1531+
for (std::size_t slot = 0; slot != slots_count; ++slot)
15311532
std::memcpy(copy.vectors_lookup_[slot], vectors_lookup_[slot], metric_.bytes_per_vector());
15321533
}
15331534

0 commit comments

Comments
 (0)