Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feat]: add custom allocator #29

Open
wants to merge 1 commit into
base: main-lantern
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion c/lib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ using lantern_storage_t = lantern_external_storage_t;
#else
using lantern_storage_t = lantern_internal_storage_t;
#endif
using index_dense_t = index_dense_gt<default_key_t, default_slot_t, lantern_storage_t>;
using custom_allocator_t = custom_allocator_gt<byte_t>;
using index_dense_t = index_dense_gt<default_key_t, default_slot_t, lantern_storage_t, custom_allocator_t>;

using add_result_t = typename index_dense_t::add_result_t;
using search_result_t = typename index_dense_t::search_result_t;
Expand Down Expand Up @@ -145,6 +146,7 @@ USEARCH_EXPORT usearch_index_t usearch_init(usearch_init_options_t* options, flo
opts.num_centroids = options->num_centroids;
opts.num_subvectors = options->num_subvectors;
opts.scalar_bytes = bits_per_scalar(scalar_kind) / 8;
index_dense_t::dynamic_allocator_t(options->alloc_func, options->free_func);
index_dense_t index = index_dense_t::make(metric, opts, options->num_threads, config, codebook);

if (options->retriever != nullptr || options->retriever_mut != nullptr) {
Expand Down
5 changes: 5 additions & 0 deletions c/usearch.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ USEARCH_EXPORT typedef enum usearch_scalar_kind_t {
usearch_scalar_b1_k,
} usearch_scalar_kind_t;

USEARCH_EXPORT typedef void* (*usearch_alloc_func)(size_t);
USEARCH_EXPORT typedef void (*usearch_free_func)(void *);

USEARCH_EXPORT typedef struct usearch_init_options_t {
/**
* @brief The metric kind used for distance calculation between vectors.
Expand Down Expand Up @@ -110,6 +113,8 @@ USEARCH_EXPORT typedef struct usearch_init_options_t {
bool pq;
size_t num_centroids;
size_t num_subvectors;
usearch_alloc_func alloc_func;
usearch_free_func free_func;
} usearch_init_options_t;

USEARCH_EXPORT typedef struct {
Expand Down
12 changes: 9 additions & 3 deletions include/usearch/index_dense.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
namespace unum {
namespace usearch {

template <typename, typename, typename> class index_dense_gt;
template <typename, typename, typename, typename> class index_dense_gt;

/**
* @brief The "magic" sequence helps infer the type of the file.
Expand Down Expand Up @@ -294,7 +294,8 @@ inline index_dense_metadata_result_t index_dense_metadata_from_buffer(memory_map
*/
template <typename key_at = default_key_t, //
typename compressed_slot_at = default_slot_t, //
typename storage_at = storage_v2_at<key_at, compressed_slot_at>> //
typename storage_at = storage_v2_at<key_at, compressed_slot_at>,
typename dynamic_allocator_at = std::allocator<byte_t>> //
class index_dense_gt {
public:
using vector_key_t = key_at;
Expand All @@ -313,6 +314,8 @@ class index_dense_gt {
using serialization_config_t = index_dense_serialization_config_t;
using storage_t = storage_at;

using dynamic_allocator_t = dynamic_allocator_at;

private:
/// @brief Schema: input buffer, bytes in input buffer, output buffer.
using cast_t = std::function<bool(byte_t const*, std::size_t, byte_t*)>;
Expand All @@ -321,7 +324,10 @@ class index_dense_gt {
storage_t, //
distance_t, vector_key_t, compressed_slot_t, //
dynamic_allocator_t>;
using index_allocator_t = aligned_allocator_gt<index_t, 64>;

using dynamic_allocator_traits_t = std::allocator_traits<dynamic_allocator_at>;
using index_allocator_t = typename dynamic_allocator_traits_t::template rebind_alloc<index_t>;


using member_iterator_t = typename index_t::member_iterator_t;
using member_citerator_t = typename index_t::member_citerator_t;
Expand Down
54 changes: 54 additions & 0 deletions include/usearch/index_plugins.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,60 @@ using executor_default_t = executor_stl_t;

#endif

template<typename element_at = char>
class custom_allocator_gt {
public:
// Standard allocator types
using value_type = element_at;
using size_type = std::size_t;
using pointer = element_at*;
using const_pointer = const element_at*;
using difference_type = std::ptrdiff_t;

// Function pointer types
using alloc_func_ptr = void* (*)(size_t);
using free_func_ptr = void (*)(void*);

// Rebind mechanism
template<typename other_element_at> struct rebind {
using other = custom_allocator_gt<other_element_at>;
};

// Constructor
custom_allocator_gt(alloc_func_ptr alloc_func = std::malloc, free_func_ptr free_func = std::free)
: alloc_func(alloc_func), free_func(free_func) {}

// Allocate memory for n elements
pointer allocate(size_type n) const {
return static_cast<pointer>(alloc_func(n * sizeof(value_type)));
}

// Deallocate memory pointed to by p
void deallocate(pointer p, size_type n) const {
free_func(p);
}

// Maximum size that may be allocated
size_type max_size() const noexcept {
return std::allocator_traits<custom_allocator_gt>::max_size(*this);
}

// Compare two allocators for equality (always true for stateless allocators)
template<typename other_element_at>
bool operator==(const custom_allocator_gt<other_element_at>&) const noexcept {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these are just operators to conform c++'s requirement for an allocator

return true;
}

template<typename other_element_at>
bool operator!=(const custom_allocator_gt<other_element_at>&) const noexcept {
return false;
}

private:
alloc_func_ptr alloc_func;
free_func_ptr free_func;
};

/**
* @brief Uses OS-specific APIs for aligned memory allocations.
*/
Expand Down