From e23c66175d7d5469aee00c9939ccb1ecf7bb4ac5 Mon Sep 17 00:00:00 2001 From: Matthijs Douze Date: Mon, 20 Apr 2026 06:32:07 -0700 Subject: [PATCH] Replace dispatch_HammingComputer with with_HammingComputer (#5126) Summary: Pull Request resolved: https://github.com/facebookresearch/faiss/pull/5126 Replace the dispatch_HammingComputer + Run_XXX consumer struct pattern with with_HammingComputer that takes a C++20 template lambda directly. This eliminates boilerplate wrapper structs across 8 files. Before: struct Run_foo { using T = void; template void f(T... a) { foo(a...); } }; Run_foo r; dispatch_HammingComputer(code_size, r, args...); After: with_HammingComputer(code_size, [&]() { foo(args...); }); Reviewed By: algoriddle Differential Revision: D101350351 fbshipit-source-id: 02a346e8c33ffdb49153cbe13415b748f0a1e847 --- faiss/IndexBinaryHNSW.cpp | 14 ++---- faiss/IndexBinaryHash.cpp | 29 +++-------- faiss/IndexBinaryIVF.cpp | 60 +++++++---------------- faiss/IndexIVFPQ.cpp | 16 ++---- faiss/IndexIVFSpectralHash.cpp | 15 ++---- faiss/IndexPQ.cpp | 30 +++++------- faiss/utils/hamming.cpp | 55 +++++---------------- faiss/utils/hamming_distance/hamdis-inl.h | 37 +++++++------- 8 files changed, 78 insertions(+), 178 deletions(-) diff --git a/faiss/IndexBinaryHNSW.cpp b/faiss/IndexBinaryHNSW.cpp index 890834074..1788868b9 100644 --- a/faiss/IndexBinaryHNSW.cpp +++ b/faiss/IndexBinaryHNSW.cpp @@ -309,14 +309,6 @@ struct FlatHammingDis : DistanceComputer { } }; -struct BuildDistanceComputer { - using T = DistanceComputer*; - template - DistanceComputer* f(IndexBinaryFlat* flat_storage) { - return new FlatHammingDis(*flat_storage); - } -}; - } // namespace DistanceComputer* IndexBinaryHNSW::get_distance_computer() const { @@ -324,8 +316,10 @@ DistanceComputer* IndexBinaryHNSW::get_distance_computer() const { FAISS_THROW_IF_NOT_MSG( flat_storage != nullptr, "IndexBinaryHNSW requires IndexBinaryFlat storage"); - BuildDistanceComputer bd; - return dispatch_HammingComputer(code_size, bd, flat_storage); + return with_HammingComputer( + code_size, [&]() -> DistanceComputer* { + return new FlatHammingDis(*flat_storage); + }); } /************************************************************** diff --git a/faiss/IndexBinaryHash.cpp b/faiss/IndexBinaryHash.cpp index dbd19586c..10d422843 100644 --- a/faiss/IndexBinaryHash.cpp +++ b/faiss/IndexBinaryHash.cpp @@ -175,14 +175,6 @@ void search_single_query_template( } while (fe.next()); } -struct Run_search_single_query { - using T = void; - template - T f(Types*... args) { - search_single_query_template(*args...); - } -}; - template void search_single_query( const IndexBinaryHash& index, @@ -191,9 +183,10 @@ void search_single_query( size_t& n0, size_t& nlist, size_t& ndis) { - Run_search_single_query r; - dispatch_HammingComputer( - index.code_size, r, &index, &q, &res, &n0, &nlist, &ndis); + with_HammingComputer(index.code_size, [&]() { + search_single_query_template( + index, q, res, n0, nlist, ndis); + }); } } // anonymous namespace @@ -343,14 +336,6 @@ static void verify_shortlist( } } -struct Run_verify_shortlist { - using T = void; - template - void f(Types... args) { - verify_shortlist(args...); - } -}; - template void search_1_query_multihash( const IndexBinaryMultiHash& index, @@ -387,9 +372,9 @@ void search_1_query_multihash( ndis += shortlist.size(); // verify shortlist - Run_verify_shortlist r; - dispatch_HammingComputer( - index.code_size, r, index.storage, xi, shortlist, res); + with_HammingComputer(index.code_size, [&]() { + verify_shortlist(index.storage, xi, shortlist, res); + }); } } // anonymous namespace diff --git a/faiss/IndexBinaryIVF.cpp b/faiss/IndexBinaryIVF.cpp index 6de40b41a..2ae487034 100644 --- a/faiss/IndexBinaryIVF.cpp +++ b/faiss/IndexBinaryIVF.cpp @@ -784,40 +784,16 @@ void search_knn_hamming_per_invlist( } } -struct Run_search_knn_hamming_per_invlist { - using T = void; - - template - void f(Types... args) { - search_knn_hamming_per_invlist(args...); - } -}; - -template -struct Run_search_knn_hamming_count { - using T = void; - - template - void f(Types... args) { - search_knn_hamming_count(args...); - } -}; - -struct BuildScanner { - using T = BinaryInvertedListScanner*; - - template - T f(size_t code_size, bool store_pairs) { - return new IVFBinaryScannerL2(code_size, store_pairs); - } -}; - } // anonymous namespace BinaryInvertedListScanner* IndexBinaryIVF::get_InvertedListScanner( bool store_pairs) const { - BuildScanner bs; - return dispatch_HammingComputer(code_size, bs, code_size, store_pairs); + return with_HammingComputer( + code_size, + [&]() -> BinaryInvertedListScanner* { + return new IVFBinaryScannerL2( + code_size, store_pairs); + }); } void IndexBinaryIVF::search_preassigned( @@ -831,23 +807,23 @@ void IndexBinaryIVF::search_preassigned( bool store_pairs, const IVFSearchParameters* params) const { if (per_invlist_search) { - Run_search_knn_hamming_per_invlist r; - // clang-format off - dispatch_HammingComputer( - code_size, r, this, n, x, k, - cidx, cdis, dis, idx, store_pairs, params); - // clang-format on + with_HammingComputer(code_size, [&]() { + search_knn_hamming_per_invlist( + this, n, x, k, cidx, cdis, dis, idx, store_pairs, params); + }); } else if (use_heap) { search_knn_hamming_heap( this, n, x, k, cidx, cdis, dis, idx, store_pairs, params); } else if (store_pairs) { // !use_heap && store_pairs - Run_search_knn_hamming_count r; - dispatch_HammingComputer( - code_size, r, this, n, x, cidx, k, dis, idx, params); + with_HammingComputer(code_size, [&]() { + search_knn_hamming_count( + this, n, x, cidx, k, dis, idx, params); + }); } else { // !use_heap && !store_pairs - Run_search_knn_hamming_count r; - dispatch_HammingComputer( - code_size, r, this, n, x, cidx, k, dis, idx, params); + with_HammingComputer(code_size, [&]() { + search_knn_hamming_count( + this, n, x, cidx, k, dis, idx, params); + }); } } diff --git a/faiss/IndexIVFPQ.cpp b/faiss/IndexIVFPQ.cpp index 39707f6c2..a84e19a96 100644 --- a/faiss/IndexIVFPQ.cpp +++ b/faiss/IndexIVFPQ.cpp @@ -1167,23 +1167,15 @@ struct IVFPQScannerT : QueryTables { } } - template - struct Run_scan_list_polysemous_hc { - using T = void; - template - void f(const IVFPQScannerT* scanner, Types... args) { - scanner->scan_list_polysemous_hc( - args...); - } - }; - template void scan_list_polysemous( size_t ncode, const uint8_t* codes, SearchResultType& res) const { - Run_scan_list_polysemous_hc r; - dispatch_HammingComputer(pq.code_size, r, this, ncode, codes, res); + with_HammingComputer(pq.code_size, [&]() { + this->scan_list_polysemous_hc( + ncode, codes, res); + }); } }; diff --git a/faiss/IndexIVFSpectralHash.cpp b/faiss/IndexIVFSpectralHash.cpp index 523ef8afb..48f596a30 100644 --- a/faiss/IndexIVFSpectralHash.cpp +++ b/faiss/IndexIVFSpectralHash.cpp @@ -299,15 +299,6 @@ struct IVFScanner : InvertedListScanner { } }; -struct BuildScanner { - using T = InvertedListScanner*; - - template - static T f(const IndexIVFSpectralHash* index, bool store_pairs) { - return new IVFScanner(index, store_pairs); - } -}; - } // anonymous namespace InvertedListScanner* IndexIVFSpectralHash::get_InvertedListScanner( @@ -315,8 +306,10 @@ InvertedListScanner* IndexIVFSpectralHash::get_InvertedListScanner( const IDSelector* sel, const IVFSearchParameters*) const { FAISS_THROW_IF_NOT(!sel); - BuildScanner bs; - return dispatch_HammingComputer(code_size, bs, this, store_pairs); + return with_HammingComputer( + code_size, [&]() -> InvertedListScanner* { + return new IVFScanner(this, store_pairs); + }); } void IndexIVFSpectralHash::replace_vt(VectorTransform* vt_in, bool own) { diff --git a/faiss/IndexPQ.cpp b/faiss/IndexPQ.cpp index 521807eb1..c74bfb956 100644 --- a/faiss/IndexPQ.cpp +++ b/faiss/IndexPQ.cpp @@ -323,14 +323,6 @@ size_t polysemous_inner_loop( return n_pass_i; } -struct Run_polysemous_inner_loop { - using T = size_t; - template - size_t f(Types... args) { - return polysemous_inner_loop(args...); - } -}; - } // anonymous namespace void IndexPQ::search_core_polysemous( @@ -381,17 +373,17 @@ void IndexPQ::search_core_polysemous( maxheap_heapify(k, heap_dis, heap_ids); if (!generalized_hamming) { - Run_polysemous_inner_loop r; - n_pass += dispatch_HammingComputer( - pq.code_size, - r, - this, - dis_table_qi, - q_code, - k, - heap_dis, - heap_ids, - param_polysemous_ht); + n_pass += with_HammingComputer( + pq.code_size, [&]() -> size_t { + return polysemous_inner_loop( + this, + dis_table_qi, + q_code, + k, + heap_dis, + heap_ids, + param_polysemous_ht); + }); } else { // generalized hamming switch (pq.code_size) { diff --git a/faiss/utils/hamming.cpp b/faiss/utils/hamming.cpp index 3c7931aa2..ff52bd2c7 100644 --- a/faiss/utils/hamming.cpp +++ b/faiss/utils/hamming.cpp @@ -332,30 +332,6 @@ void hamming_range_search( } } -struct Run_hammings_knn_hc { - using T = void; - template - void f(Types... args) { - hammings_knn_hc(args...); - } -}; - -struct Run_hammings_knn_mc { - using T = void; - template - void f(Types... args) { - hammings_knn_mc(args...); - } -}; - -struct Run_hamming_range_search { - using T = void; - template - void f(Types... args) { - hamming_range_search(args...); - } -}; - } // namespace /* Functions to maps vectors to bits. Assume proper allocation done beforehand, @@ -511,19 +487,10 @@ void hammings_knn_hc( int order, ApproxTopK_mode_t approx_topk_mode, const faiss::IDSelector* sel) { - Run_hammings_knn_hc r; - dispatch_HammingComputer( - ncodes, - r, - ncodes, - ha, - a, - b, - nb, - order, - true, - approx_topk_mode, - sel); + with_HammingComputer(ncodes, [&]() { + hammings_knn_hc( + ncodes, ha, a, b, nb, order, true, approx_topk_mode, sel); + }); } void hammings_knn_mc( @@ -536,9 +503,10 @@ void hammings_knn_mc( int32_t* __restrict distances, int64_t* __restrict labels, const faiss::IDSelector* sel) { - Run_hammings_knn_mc r; - dispatch_HammingComputer( - ncodes, r, ncodes, a, b, na, nb, k, distances, labels, sel); + with_HammingComputer(ncodes, [&]() { + hammings_knn_mc( + ncodes, a, b, na, nb, k, distances, labels, sel); + }); } void hamming_range_search( @@ -550,9 +518,10 @@ void hamming_range_search( size_t code_size, RangeSearchResult* result, const faiss::IDSelector* sel) { - Run_hamming_range_search r; - dispatch_HammingComputer( - code_size, r, a, b, na, nb, radius, code_size, result, sel); + with_HammingComputer(code_size, [&]() { + hamming_range_search( + a, b, na, nb, radius, code_size, result, sel); + }); } /* Count number of matches given a max threshold */ diff --git a/faiss/utils/hamming_distance/hamdis-inl.h b/faiss/utils/hamming_distance/hamdis-inl.h index 0c9ac1ba6..b381c438e 100644 --- a/faiss/utils/hamming_distance/hamdis-inl.h +++ b/faiss/utils/hamming_distance/hamdis-inl.h @@ -56,30 +56,29 @@ SPECIALIZED_HC(64); #undef SPECIALIZED_HC /*************************************************************************** - * Dispatching function that takes a code size and a consumer object - * the consumer object should contain a retun type t and a operation template - * function f() that must be called to perform the operation. + * Dispatching function that takes a code size and a C++20 template lambda. + * The lambda is called with the appropriate HammingComputer type: + * with_HammingComputer(code_size, [&]() { ... }); **************************************************************************/ -template -typename Consumer::T dispatch_HammingComputer( - int code_size, - Consumer& consumer, - Types... args) { +template +decltype(auto) with_HammingComputer(int code_size, F&& f) { switch (code_size) { -#define DISPATCH_HC(CODE_SIZE) \ - case CODE_SIZE: \ - return consumer.template f(args...); - DISPATCH_HC(4); - DISPATCH_HC(8); - DISPATCH_HC(16); - DISPATCH_HC(20); - DISPATCH_HC(32); - DISPATCH_HC(64); + case 4: + return f.template operator()(); + case 8: + return f.template operator()(); + case 16: + return f.template operator()(); + case 20: + return f.template operator()(); + case 32: + return f.template operator()(); + case 64: + return f.template operator()(); default: - return consumer.template f(args...); + return f.template operator()(); } -#undef DISPATCH_HC } } // namespace faiss