Skip to content

Commit 94982e4

Browse files
committed
refactor(deglib): modularize header layout, add top-level facades and align test structure
- Restructure deglib headers into logical subdirectories (utils/, optimization/, graph/) - Add top-level facade headers (optimization.h, graph.h) to eliminate deep directory includes for library users - Extract CPU detection to utils/cpu.h while maintaining config.h macro compatibility - Extract SearchGraph and MutableGraph interfaces into graph/ - Reorganize unit, integration, and regression test suites to mirror deglib layout 1:1
1 parent 7515d50 commit 94982e4

31 files changed

Lines changed: 1089 additions & 833 deletions

‎cpp/deglib/include/deglib/analysis.h‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#include <thread>
77

88
#include "deglib/concurrent.h"
9-
#include "deglib/memory.h"
9+
#include "deglib/utils/memory.h"
1010
#include "deglib/search.h"
1111
#include "deglib/graph.h"
1212

‎cpp/deglib/include/deglib/builder.h‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
#include "deglib/concurrent.h"
1818
#include "deglib/analysis.h"
1919
#include "deglib/graph.h"
20-
#include "deglib/random.h"
20+
#include "deglib/utils/random.h"
2121

2222
namespace deglib::builder
2323
{

‎cpp/deglib/include/deglib/config.h‎

Lines changed: 2 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -35,86 +35,5 @@
3535
#endif
3636
#endif
3737

38-
39-
// ---------------------------------------------------------------------------
40-
// Runtime CPU feature detection
41-
// ---------------------------------------------------------------------------
42-
// Uses CPUID (via __cpuidex on MSVC, __cpuid_count on GCC/Clang) to detect
43-
// AVX2 and AVX-512F at runtime. Results are cached in a function-local static
44-
// so the CPUID query runs only once.
45-
//
46-
// AVX2 is the minimum x86 baseline requirement. F16C is always available on
47-
// CPUs that support AVX2, so it is not tracked separately.
48-
//
49-
// The distance headers compile all SIMD code paths unconditionally (the
50-
// intrinsic headers are always included below). At runtime, select_dist()
51-
// uses deglib::cpu::has_*() to dispatch to the best variant. This means there
52-
// is zero loop overhead — capability checks happen during variant selection,
53-
// not inside distance calculation loops.
54-
// ---------------------------------------------------------------------------
55-
56-
namespace deglib::cpu {
57-
58-
namespace detail {
59-
60-
#if defined(DEGLIB_X86)
61-
// Query CPUID leaf/subleaf into a 4-element int array.
62-
// Uses __cpuidex on MSVC and __cpuid_count on GCC/Clang.
63-
inline void cpuid(int leaf, int subleaf, int cpu_info[4]) {
64-
#if defined(_MSC_VER)
65-
__cpuidex(cpu_info, leaf, subleaf);
66-
#else
67-
__cpuid_count(leaf, subleaf, cpu_info[0], cpu_info[1], cpu_info[2], cpu_info[3]);
68-
#endif
69-
}
70-
#endif
71-
72-
// Cached hardware feature flags, populated on first call via a function-local static.
73-
struct CpuFeatures {
74-
bool avx2{false};
75-
bool avx512f{false};
76-
77-
CpuFeatures() {
78-
#if defined(DEGLIB_X86)
79-
int cpu_info[4] = {0};
80-
81-
// Leaf 7, subleaf 0: extended feature flags in EBX and ECX
82-
cpuid(7, 0, cpu_info);
83-
avx2 = (cpu_info[1] & (1 << 5)) != 0;
84-
avx512f = (cpu_info[1] & (1 << 16)) != 0;
85-
#endif
86-
}
87-
};
88-
89-
inline const CpuFeatures& features() {
90-
static CpuFeatures cached;
91-
return cached;
92-
}
93-
94-
} // namespace detail
95-
96-
enum class InstructionSet : uint8_t {
97-
Auto = 0,
98-
Scalar = 1,
99-
AVX2 = 2,
100-
AVX512 = 3
101-
};
102-
103-
inline const char* instruction_set_to_string(InstructionSet inst) {
104-
switch (inst) {
105-
case InstructionSet::Auto: return "Auto";
106-
case InstructionSet::Scalar: return "Scalar";
107-
case InstructionSet::AVX2: return "AVX2";
108-
case InstructionSet::AVX512: return "AVX512";
109-
}
110-
return "Unknown";
111-
}
112-
113-
// Runtime CPU feature detection — safe to call from any translation unit.
114-
// These checks are performed once (cached) and have zero cost per call thereafter.
115-
116-
inline bool has_avx2() { return detail::features().avx2; }
117-
inline bool has_avx512() { return detail::features().avx512f; }
118-
119-
} // namespace deglib::cpu
120-
38+
// CPU detection utilities
39+
#include "deglib/utils/cpu.h"

‎cpp/deglib/include/deglib/deglib.h‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
#pragma once
22

33
#include "deglib/config.h"
4-
#include "deglib/memory.h"
4+
#include "deglib/utils/memory.h"
5+
#include "deglib/utils/random.h"
56
#include "deglib/distances.h"
67
#include "deglib/filter.h"
78
#include "deglib/search.h"
89
#include "deglib/repository.h"
910
#include "deglib/graph.h"
1011
#include "deglib/analysis.h"
11-
#include "deglib/graph/readonly_graph.h"
12-
#include "deglib/graph/sizebounded_graph.h"
1312
#include "deglib/builder.h"
14-
#include "deglib/random.h"
13+
#include "deglib/optimization.h"

‎cpp/deglib/include/deglib/distances.h‎

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,4 +283,54 @@ namespace deglib {
283283
~FloatSpace() {}
284284
};
285285

286+
namespace distances {
287+
288+
/**
289+
* Compute distance between two feature vectors in the given FloatSpace.
290+
*/
291+
inline float compute_distance(const deglib::FloatSpace& space, const void* vec1, const void* vec2) {
292+
if (vec1 == nullptr || vec2 == nullptr) {
293+
throw std::invalid_argument("compute_distance: vec1 and vec2 must not be null");
294+
}
295+
const auto dist_func = space.get_dist_func();
296+
const auto param = space.get_dist_func_param();
297+
return dist_func(vec1, vec2, param);
298+
}
299+
300+
/**
301+
* Compute distances between queries and targets using the given FloatSpace.
302+
*/
303+
inline void compute_distances(
304+
const deglib::FloatSpace& space,
305+
const void* queries,
306+
size_t num_queries,
307+
const void* targets,
308+
size_t num_targets,
309+
float* result_distances
310+
) {
311+
if (queries == nullptr || targets == nullptr || result_distances == nullptr) {
312+
throw std::invalid_argument("compute_distances: arguments must not be null");
313+
}
314+
315+
const size_t byte_stride = space.get_data_size();
316+
const uint8_t* q_ptr = static_cast<const uint8_t*>(queries);
317+
const uint8_t* t_ptr = static_cast<const uint8_t*>(targets);
318+
319+
const auto param = space.get_dist_func_param();
320+
space.compute([&](const auto& dist_func_obj) {
321+
using DistType = std::decay_t<decltype(dist_func_obj)>;
322+
for (size_t q = 0; q < num_queries; ++q) {
323+
const uint8_t* current_query = q_ptr + q * byte_stride;
324+
float* out_row = result_distances + q * num_targets;
325+
326+
for (size_t t = 0; t < num_targets; ++t) {
327+
out_row[t] = DistType::compare(current_query, t_ptr + t * byte_stride, param);
328+
}
329+
}
330+
});
331+
}
332+
333+
} // namespace distances
334+
286335
} // end namespace deglib
336+

‎cpp/deglib/include/deglib/graph.h‎

Lines changed: 9 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,13 @@
11
#pragma once
22

3-
#include "deglib/search.h"
3+
// Graph Interfaces
4+
#include "deglib/graph/search_graph.h"
5+
#include "deglib/graph/mutable_graph.h"
6+
#include "deglib/graph/dynamic_graph.h"
47

5-
namespace deglib::graph
6-
{
8+
// Visited List Pool Helper
9+
#include "deglib/graph/visited_list_pool.h"
710

8-
class MutableGraph : public deglib::search::SearchGraph
9-
{
10-
public:
11-
12-
/**
13-
* Add a new vertex. The neighbor indices will be prefilled with a self-loop, the weights will be 0.
14-
*
15-
* @return the internal index of the new vertex
16-
*/
17-
virtual uint32_t addVertex(const uint32_t external_label, const std::byte* feature_vector) = 0;
18-
19-
/**
20-
* Remove an existing vertex and returns its list of neighbors
21-
*/
22-
virtual std::vector<uint32_t> removeVertex(const uint32_t external_labelr) = 0;
23-
24-
/**
25-
* Swap a neighbor with another neighbor and its weight.
26-
*
27-
* @param internal_index vertex index which neighbors should be changed
28-
* @param from_neighbor_index neighbor index to remove
29-
* @param to_neighbor_index neighbor index to add
30-
* @param to_neighbor_weight weight of the neighbor to add
31-
* @return true if the from_neighbor_index was found and changed
32-
*/
33-
virtual bool changeEdge(const uint32_t internal_index, const uint32_t from_neighbor_index, const uint32_t to_neighbor_index, const float to_neighbor_weight) = 0;
34-
35-
36-
/**
37-
* Change all edges of a vertex.
38-
* The neighbor indices/weights and feature vectors will be copied.
39-
* The neighbor array need to have enough neighbors to match the edge-per-vertex count of the graph.
40-
* The indices in the neighbor_indices array must be sorted.
41-
*/
42-
virtual void changeEdges(const uint32_t internal_index, const uint32_t* neighbor_indices, const float* neighbor_weights) = 0;
43-
44-
45-
/**
46-
*
47-
*/
48-
virtual const float* getNeighborWeights(const uint32_t internal_index) const = 0;
49-
50-
virtual const float getEdgeWeight(const uint32_t from_neighbor_index, const uint32_t to_neighbor_index) const = 0;
51-
52-
virtual const bool saveGraph(const char* path_to_graph) const = 0;
53-
};
54-
55-
} // end namespace deglib::graph
11+
// Concrete Graph Implementations
12+
#include "deglib/graph/readonly_graph.h"
13+
#include "deglib/graph/sizebounded_graph.h"
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#pragma once
2+
3+
#include "deglib/graph/search_graph.h"
4+
5+
#include <cstdint>
6+
#include <cstddef>
7+
#include <vector>
8+
9+
namespace deglib::graph
10+
{
11+
12+
class MutableGraph : public deglib::search::SearchGraph
13+
{
14+
public:
15+
16+
/**
17+
* Add a new vertex. The neighbor indices will be prefilled with a self-loop, the weights will be 0.
18+
*
19+
* @return the internal index of the new vertex
20+
*/
21+
virtual uint32_t addVertex(const uint32_t external_label, const std::byte* feature_vector) = 0;
22+
23+
/**
24+
* Remove an existing vertex and returns its list of neighbors
25+
*/
26+
virtual std::vector<uint32_t> removeVertex(const uint32_t external_labelr) = 0;
27+
28+
/**
29+
* Swap a neighbor with another neighbor and its weight.
30+
*
31+
* @param internal_index vertex index which neighbors should be changed
32+
* @param from_neighbor_index neighbor index to remove
33+
* @param to_neighbor_index neighbor index to add
34+
* @param to_neighbor_weight weight of the neighbor to add
35+
* @return true if the from_neighbor_index was found and changed
36+
*/
37+
virtual bool changeEdge(const uint32_t internal_index, const uint32_t from_neighbor_index, const uint32_t to_neighbor_index, const float to_neighbor_weight) = 0;
38+
39+
40+
/**
41+
* Change all edges of a vertex.
42+
* The neighbor indices/weights and feature vectors will be copied.
43+
* The neighbor array need to have enough neighbors to match the edge-per-vertex count of the graph.
44+
* The indices in the neighbor_indices array must be sorted.
45+
*/
46+
virtual void changeEdges(const uint32_t internal_index, const uint32_t* neighbor_indices, const float* neighbor_weights) = 0;
47+
48+
49+
/**
50+
*
51+
*/
52+
virtual const float* getNeighborWeights(const uint32_t internal_index) const = 0;
53+
54+
virtual const float getEdgeWeight(const uint32_t from_neighbor_index, const uint32_t to_neighbor_index) const = 0;
55+
56+
virtual const bool saveGraph(const char* path_to_graph) const = 0;
57+
};
58+
59+
} // end namespace deglib::graph

‎cpp/deglib/include/deglib/graph/readonly_graph.h‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@
1414

1515
#include "deglib/graph.h"
1616
#include "deglib/repository.h"
17-
#include "deglib/memory.h"
17+
#include "deglib/utils/memory.h"
1818
#include "deglib/distances.h"
1919
#include "deglib/search.h"
20-
#include "deglib/visited_list_pool.h"
20+
#include "deglib/graph/visited_list_pool.h"
2121

2222
namespace deglib::graph
2323
{

0 commit comments

Comments
 (0)