Repository: unum-cloud/usearch (language: python)

Issue:
Bug:  Add/search function use questions
### Describe the bug


I used the C++ example on the official website, but I encountered a problem with the add and search function. I don’t know which function should be used here in metric_at&& metric. The following is the official website code. 




I hope you can give me an example that can be used. Thank you.

### Steps to reproduce

index_gt<metric_cos_gt<float>> index;
float vec[3] = {0.1, 0.3, 0.2};

index.reserve(10);
index.add(/* key: */ 42, /* vector: */ {&vec[0], 3});  ??? has problem.
auto results = index.search(/* query: */ {&vec[0], 3}, 5 /* neighbors */);

### Expected behavior

I hope you can give me a case where C++ can be used

### USearch version

lastest

### Operating System

windows 11

### Hardware architecture

x86

### Which interface are you using?

C++ implementation

### Contact Details

nauhwuun2009@gmail.com

### Is there an existing issue for this?

- [X] I have searched the existing issues

### Code of Conduct

- [X] I agree to follow this project's Code of Conduct


Discussion / hints:
Oh, the example may be describing the interface to the high-level API located in the index_dense.hpp. 

What’s your use case like? If you only plan to search through dense vectors - I’d recommend using the high-level variant. 
Can you give me a complete and usable example of reserve(), add(), search(), size(), capacity(), save(), load(), view()? Although I don't know what the high-level variant usage is, I just used it. I hope you can help me. Thank you.
It would be best if you could give a more complete case. Due to the lack of documentation, the code looks very laborious, but I like to use C++ to achieve high-quality projects, so I hope it can help. Thanks again
Sure, @NauhWuun, I will do my best to help 🤗 

I'll upload more examples in a couple of hours. In the meantime, you can find the [docs of the high-level API on our website here](https://unum-cloud.github.io/usearch/cpp/reference.html#usearch-index-dense-hpp).


> Sure, @NauhWuun, I will do my best to help 🤗
> 
> I'll upload more examples in a couple of hours. In the meantime, you can find the [docs of the high-level API on our website here](https://unum-cloud.github.io/usearch/cpp/reference.html#usearch-index-dense-hpp).

I'm so looking forward to it. It feels great. Looking forward to the good news. :)

Fix patch:
diff --git a/. npmignore b/. npmignore
new file mode 100644
index 00000000..f932e9da
--- /dev/null
+++ b/. npmignore
@@ -0,0 +1,14 @@
+node_modules/
+.vscode/
+build/
+csharp/
+golang/
+java/
+objc/
+rust/
+swift/
+wolfram/
+python/
+docs/
+wasm/
+Package.swift
\ No newline at end of file
diff --git a/cpp/README.md b/cpp/README.md
index 8ac1542b..a397b79f 100644
--- a/cpp/README.md
+++ b/cpp/README.md
@@ -2,8 +2,8 @@
 
 ## Installation
 
-To use in a C++ project simply copy the `include/usearch/index.hpp` header into your project.
-Alternatively fetch it with CMake:
+To use in a C++ project, copy the `include/usearch/*` headers into your project.
+Alternatively, fetch it with CMake:
 
 ```cmake
 FetchContent_Declare(usearch GIT_REPOSITORY https://github.com/unum-cloud/usearch.git)
@@ -12,13 +12,17 @@ FetchContent_MakeAvailable(usearch)
 
 ## Quickstart
 
-Once included, the low-level C++11 interface is as simple as it gets: `reserve()`, `add()`, `search()`, `size()`, `capacity()`, `save()`, `load()`, `view()`.
-This covers 90% of use-cases.
+Once included, the high-level C++11 interface is as simple as it gets: `reserve()`, `add()`, `search()`, `size()`, `capacity()`, `save()`, `load()`, `view()`.
+This covers 90% of use cases.
 
-```c++
+```cpp
 using namespace unum::usearch;
 
-index_gt<metric_cos_gt<float>> index;
+metric_punned_t metric(256, metric_kind_t::l2sq_k, scalar_kind_t::f32_k);
+
+// If you plan to store more than 4 Billion entries - use `index_dense_big_t`.
+// Or directly instantiate the template variant you need - `index_dense_gt<key_t, internal_id_t>`.
+index_dense_t index = index_dense_t::make(metric);
 float vec[3] = {0.1, 0.3, 0.2};
 
 index.reserve(10);
@@ -30,10 +34,19 @@ for (std::size_t i = 0; i != results.size(); ++i)
 ```
 
 The `add` is thread-safe for concurrent index construction.
+It also has an overload for different vector types, casting them under the hood.
+The same applies to the `search`, `get`, `cluster`, and `distance_between` functions.
+
+```cpp
+double vec_double[3] = {0.1, 0.3, 0.2};
+_Float16 vec_half[3] = {0.1, 0.3, 0.2};
+index.add(43, {&vec_double[0], 3});
+index.add(44, {&vec_half[0], 3});
+```
 
 ## Serialization
 
-```c++
+```cpp
 index.save("index.usearch");
 index.load("index.usearch"); // Copying from disk
 index.view("index.usearch"); // Memory-mapping from disk
@@ -44,23 +57,14 @@ index.view("index.usearch"); // Memory-mapping from disk
 For advanced users, more compile-time abstractions are available.
 
 ```cpp
-template <typename metric_at = metric_ip_gt<float>,            //
-          typename key_at = std::size_t,              // `uint32_t`, `uuid_t`...
-          typename id_at = std::uint32_t,               // `uint40_t`, `uint64_t`...
-          typename scalar_at = float,                   // `double`, `half`, `char`...
-          typename allocator_at = std::allocator<char>> //
+template <typename distance_at = default_distance_t,              // `float`
+          typename key_at = default_key_t,                        // `int64_t`, `uuid_t`
+          typename compressed_slot_at = default_slot_t,           // `uint32_t`, `uint40_t`
+          typename dynamic_allocator_at = std::allocator<byte_t>, //
+          typename tape_allocator_at = dynamic_allocator_at>      //
 class index_gt;
 ```
 
-You may want to use a custom memory allocator or a rare scalar type, but most often, you would start by defining a custom similarity measure.
-The function object should have the following signature to support different-length vectors.
-
-```cpp
-struct custom_metric_t {
-    T operator()(T const* a, T const* b, std::size_t a_length, std::size_t b_length) const;
-};
-```
-
 The following distances are pre-packaged:
 
 - `metric_cos_gt<scalar_t>` for "Cosine" or "Angular" distance.
@@ -81,7 +85,7 @@ Instead of spawning additional threads within USearch, we focus on the thread sa
 ```cpp
 #pragma omp parallel for
     for (std::size_t i = 0; i < n; ++i)
-        native.add(key, span_t{vector, dims}, index_update_config_t { .thread = omp_get_thread_num() });
+        native.add(key, span_t{vector, dims});
 ```
 
 During initialization, we allocate enough temporary memory for all the cores on the machine.
diff --git a/package.json b/package.json
index b630b53a..b3254287 100644
--- a/package.json
+++ b/package.json
@@ -19,7 +19,7 @@
         "node-addon-api": "^3.0.0"
     },
     "scripts": {
-        "test": "node javascript/test.js"
+        "test": "node --test ./javascript/usearch.test.js"
     },
     "devDependencies": {
         "@semantic-release/exec": "^6.0.3",


Test patch:
diff --git a/javascript/test.js b/javascript/test.js
deleted file mode 100644
index f190af89..00000000
--- a/javascript/test.js
+++ /dev/null
@@ -1,32 +0,0 @@
-var assert = require('assert');
-var usearch = require('bindings')('usearch');
-
-// Single-entry operations
-
-var index = new usearch.Index({ metric: 'l2sq', connectivity: 16n, dimensions: 2n });
-assert.equal(index.connectivity(), 16n, 'connectivity should be 16');
-assert.equal(index.dimensions(), 2n, 'dimensions should be 2');
-assert.equal(index.size(), 0n, 'initial size should be 0');
-
-index.add(15n, new Float32Array([10, 20]));
-index.add(16n, new Float32Array([10, 25]));
-assert.equal(index.size(), 2n, 'size after adding elements should be 2');
-assert.equal(index.contains(15n), true, 'entry must be present after insertion');
-
-var results = index.search(new Float32Array([13, 14]), 2n);
-assert.deepEqual(results.keys, new BigUint64Array([15n, 16n]), 'keys should be 15 and 16');
-assert.deepEqual(results.distances, new Float32Array([45, 130]), 'distances should be 45 and 130');
-
-// Batch operations
-
-var indexBatch = new usearch.Index({ metric: 'l2sq', connectivity: 16n, dimensions: 2n });
-const keys = [15n, 16n];
-const vectors = [new Float32Array([10, 20]), new Float32Array([10, 25])];
-indexBatch.add(keys, vectors);
-assert.equal(indexBatch.size(), 2, 'size after adding batch should be 2');
-
-results = indexBatch.search(new Float32Array([13, 14]), 2n);
-assert.deepEqual(results.keys, new BigUint64Array([15n, 16n]), 'keys should be 15 and 16');
-assert.deepEqual(results.distances, new Float32Array([45, 130]), 'distances should be 45 and 130');
-
-console.log('JavaScript tests passed!');
diff --git a/javascript/usearch.test.js b/javascript/usearch.test.js
new file mode 100644
index 00000000..aae25263
--- /dev/null
+++ b/javascript/usearch.test.js
@@ -0,0 +1,45 @@
+const test = require('node:test');
+const assert = require('node:assert');
+const usearch = require('bindings')('usearch');
+
+test('Single-entry operations', () => {
+    const index = new usearch.Index({
+        metric: 'l2sq',
+        dimensions: 2n,
+        connectivity: 16n,
+    });
+
+    assert.equal(index.connectivity(), 16n, 'connectivity should be 16');
+    assert.equal(index.dimensions(), 2n, 'dimensions should be 2');
+    assert.equal(index.size(), 0n, 'initial size should be 0');
+    
+    index.add(15n, new Float32Array([ 10, 20 ]));
+    index.add(16n, new Float32Array([ 10, 25 ]));
+
+    assert.equal(index.size(), 2n, 'size after adding elements should be 2');
+    assert.equal(index.contains(15n), true, 'entry must be present after insertion');
+    
+    const results = index.search(new Float32Array([ 13, 14 ]), 2n);
+
+    assert.deepEqual(results.keys, new BigUint64Array([ 15n, 16n ]), 'keys should be 15 and 16');
+    assert.deepEqual(results.distances, new Float32Array([ 45, 130 ]), 'distances should be 45 and 130');
+});
+
+test('Batch operations', () => {
+    const indexBatch = new usearch.Index({
+        metric: 'l2sq',
+        dimensions: 2n,
+        connectivity: 16n,
+    });
+
+    const keys = [15n, 16n];
+    const vectors = [new Float32Array([ 10, 20 ]), new Float32Array([ 10, 25 ])];
+
+    indexBatch.add(keys, vectors);
+    assert.equal(indexBatch.size(), 2, 'size after adding batch should be 2');
+    
+    const results = indexBatch.search(new Float32Array([ 13, 14 ]), 2n);
+
+    assert.deepEqual(results.keys, new BigUint64Array([ 15n, 16n ]), 'keys should be 15 and 16');
+    assert.deepEqual(results.distances, new Float32Array([ 45, 130 ]), 'distances should be 45 and 130');
+});