Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
e9fe91f
clang-tidy for runtime bindings
ethanglaser May 20, 2026
5b0c7dc
address gnu/clang-tidy incompatibilities
ethanglaser May 18, 2026
fb3115e
further faiss alignment
ethanglaser May 19, 2026
e35a8e8
address errors
ethanglaser May 19, 2026
45ec6cf
temporary try pip install of clang-toosl 17
ethanglaser May 21, 2026
884219c
pip version tweak
ethanglaser May 21, 2026
755ccfe
Merge branch 'main' into dev/eglaser-clang-tidy-solo
ethanglaser May 21, 2026
bdd955b
conda install instead
ethanglaser May 21, 2026
89e842e
back to pip...
ethanglaser May 21, 2026
cdbdddd
install official clang-tidy 17 binary
ethanglaser May 22, 2026
78005d9
use rhel8 tarball instead of ubuntu22
ethanglaser May 22, 2026
3891e37
another pip attempt
ethanglaser May 22, 2026
ce259e7
add openmp extra arg based on review
ethanglaser May 27, 2026
f027ed8
Merge branch 'main' into dev/eglaser-clang-tidy-solo
ethanglaser May 27, 2026
ad2d800
drop omp due to absence from clang-tidy
ethanglaser May 27, 2026
6e72e56
try pointing clang tidy and gcc headers (omp)
ethanglaser May 27, 2026
17a1464
see if clang-tidy 18 fixes bugs
ethanglaser May 28, 2026
19b4fda
restore previous
ethanglaser May 28, 2026
1149243
remove omp workarounds and add alternative
ethanglaser May 29, 2026
0bff75f
Merge branch 'main' into dev/eglaser-clang-tidy-solo
ethanglaser May 29, 2026
c2a3d21
another attempt at passing gcc omp to clang tidy
ethanglaser May 29, 2026
839df4c
remove SVS_ENABLE_OMP toggle
ethanglaser May 29, 2026
bf283ec
readd fopenmp extra arg
ethanglaser May 29, 2026
2ec1475
swap fopenmp arg for no-unknown-pragmas
ethanglaser May 29, 2026
8fe9981
Refactor namespace declarations to use SVS_DECLARE_NAMESPACE_VERSION …
rfsaliev May 8, 2026
1acbc7d
Fix Clang compilation errors
rfsaliev May 8, 2026
e67d255
More fixes.
rfsaliev May 8, 2026
d8aa4e1
Fix unused exeption parameter warning
rfsaliev May 8, 2026
9be159b
Address code review comments
rfsaliev May 8, 2026
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
1 change: 1 addition & 0 deletions .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,5 @@ KeepEmptyLinesAtTheStartOfBlocks: false
PointerAlignment: Left
ReferenceAlignment: Left
ReflowComments: true
NamespaceMacros: ['SVS_DECLARE_NAMESPACE_VERSION']
---
68 changes: 58 additions & 10 deletions .clang-tidy
Original file line number Diff line number Diff line change
@@ -1,12 +1,60 @@
Checks: "-*,
bugprone*,
-bugprone-easily-swappable-parameters,
-bugprone-macro-parentheses,
clang-analyzer*,
readability*,
-readability-magic-numbers,
-readability-identifier-length"
Checks: '
-*,
bugprone-argument-comment,
bugprone-sizeof-*,
bugprone-use-after-move,
clang-diagnostic-*,
-clang-diagnostic-nrvo,
-clang-diagnostic-missing-designated-field-initializers,
cppcoreguidelines-pro-type-member-init,
cppcoreguidelines-special-member-functions,
google-build-using-namespace,
misc-definitions-in-headers,
modernize-use-emplace,
modernize-use-using,
performance-faster-string-find,
performance-for-range-copy,
performance-implicit-conversion-in-loop,
performance-inefficient-algorithm,
performance-inefficient-string-concatenation,
performance-inefficient-vector-operation,
performance-move-const-arg,
performance-move-constructor-init,
performance-no-automatic-move,
performance-no-int-to-ptr,
performance-noexcept-move-constructor,
performance-trivially-destructible,
performance-type-promotion-in-math-fn,
performance-unnecessary-copy-initialization,
performance-unnecessary-value-param,
readability-operators-representation,
readability-redundant-string-init,
readability-braces-around-statements,
'

WarningsAsErrors: '
bugprone-use-after-move,
'

CheckOptions:
- key: readability-implicit-bool-conversion.AllowIntegerConditions
value: '1'
- key: bugprone-easily-swappable-parameters.MinimumLength
value: 4
- key: cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
value: true
- key: cppcoreguidelines-special-member-functions.AllowImplicitlyDeletedCopyOrMove
value: 1
- key: modernize-use-using.IgnoreExternC
value: true
- key: performance-move-const-arg.CheckTriviallyCopyableMove
value: false
- key: performance-unnecessary-value-param.AllowedTypes
value: '[Pp]ointer$;[Pp]tr$;[Rr]ef(erence)?$'
- key: performance-unnecessary-copy-initialization.AllowedTypes
value: '[Pp]ointer$;[Pp]tr$;[Rr]ef(erence)?$'
- key: readability-operators-representation.BinaryOperators
value: '&&;&=;&;|;~;!;!=;||;|=;^;^='
- key: readability-redundant-string-init.StringNames
value: '::std::basic_string'
- key: readability-named-parameter.InsertPlainNamesInForwardDecls
value: true
...
14 changes: 14 additions & 0 deletions .github/scripts/build-cpp-runtime-bindings.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,19 @@ set -e # Exit on error
# Source environment setup (for compiler)
source /etc/bashrc || true

# Temporary: pip-install clang-tidy 17 to test whether the system clang-tidy
# version is the cause of the template crash. Pin setuptools <81 because the
# wheel's wrapper imports pkg_resources, which setuptools 81 removed.
# Remove once resolved.
pip install 'setuptools<81' clang-tidy==17.0.1

# Stage gcc's omp.h in an isolated dir so clang-tidy can resolve the include
# without picking up gcc's intrinsic headers (which use builtins clang lacks).
SVS_CLANG_TIDY_INCLUDE=/tmp/svs-clang-tidy-include
mkdir -p "$SVS_CLANG_TIDY_INCLUDE"
cp /opt/rh/gcc-toolset-11/root/usr/lib/gcc/x86_64-redhat-linux/11/include/omp.h "$SVS_CLANG_TIDY_INCLUDE/"
export SVS_CLANG_TIDY_INCLUDE

# Source MKL environment (required for IVF)
if [ -f /opt/intel/oneapi/setvars.sh ]; then
source /opt/intel/oneapi/setvars.sh --include-intel-llvm 2>/dev/null || true
Expand All @@ -41,6 +54,7 @@ CMAKE_ARGS=(
"-DCMAKE_INSTALL_LIBDIR=lib"
"-DSVS_RUNTIME_ENABLE_LVQ_LEANVEC=${ENABLE_LVQ_LEANVEC:-ON}"
"-DSVS_RUNTIME_ENABLE_IVF=ON"
"-DSVS_EXPERIMENTAL_CLANG_TIDY=ON"
)

if [ -n "$SVS_URL" ]; then
Expand Down
30 changes: 30 additions & 0 deletions bindings/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,23 @@ target_compile_options(${TARGET_NAME} PRIVATE
-fvisibility=hidden
)

# Optional clang-tidy integration. Reuses the top-level repo's
# cmake/clang-tidy.cmake module so the runtime build runs the same
# .clang-tidy config as the rest of the library.
option(SVS_EXPERIMENTAL_CLANG_TIDY
"Run the clang-tidy static analyzer on the cpp runtime bindings."
OFF
)
if(SVS_EXPERIMENTAL_CLANG_TIDY)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../cmake")
include(clang-tidy)
if(CLANG_TIDY_COMMAND)
set_target_properties(${TARGET_NAME}
PROPERTIES CXX_CLANG_TIDY "${CLANG_TIDY_COMMAND}"
)
endif()
endif()

if(UNIX AND NOT APPLE)
# Don't export 3rd-party symbols from the lib
target_link_options(${TARGET_NAME} PRIVATE "SHELL:-Wl,--exclude-libs,ALL")
Expand Down Expand Up @@ -142,6 +159,19 @@ if (SVS_RUNTIME_ENABLE_LVQ_LEANVEC)
FetchContent_MakeAvailable(svs)
list(APPEND CMAKE_PREFIX_PATH "${svs_SOURCE_DIR}")
find_package(svs REQUIRED)

# Strip svs::svs_compile_options gcc-only flags for clang-tidy
if(SVS_EXPERIMENTAL_CLANG_TIDY AND TARGET svs::svs_compile_options)
get_target_property(_svs_co_opts svs::svs_compile_options INTERFACE_COMPILE_OPTIONS)
if(_svs_co_opts)
list(FILTER _svs_co_opts EXCLUDE REGEX "^-fconcepts-diagnostics-depth")
list(FILTER _svs_co_opts EXCLUDE REGEX "^-ftemplate-backtrace-limit")
set_property(TARGET svs::svs_compile_options
PROPERTY INTERFACE_COMPILE_OPTIONS "${_svs_co_opts}"
)
endif()
endif()

target_link_libraries(${TARGET_NAME} PRIVATE
svs::svs
svs::svs_compile_options
Expand Down
6 changes: 2 additions & 4 deletions bindings/cpp/include/svs/runtime/api_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@

namespace svs {
namespace runtime {
namespace v0 {

SVS_DECLARE_NAMESPACE_VERSION(0) {
class OptionalBool {
enum class Value : int8_t { Undef = -1, True = 1, False = 0 };
Value value_;
Expand Down Expand Up @@ -206,7 +205,6 @@ struct SVS_RUNTIME_API_INTERFACE ResultsAllocator {
return this->allocate(result_counts);
}
};

} // namespace v0
} // SVS_DECLARE_NAMESPACE_VERSION(0)
} // namespace runtime
} // namespace svs
6 changes: 2 additions & 4 deletions bindings/cpp/include/svs/runtime/dynamic_ivf_index.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@

namespace svs {
namespace runtime {
namespace v0 {

SVS_DECLARE_NAMESPACE_VERSION(0) {
/// @brief Abstract interface for dynamic IVF indices (supports add/delete).
struct SVS_RUNTIME_API DynamicIVFIndex : public IVFIndex {
/// @brief Utility function to check storage kind support.
Expand Down Expand Up @@ -160,7 +159,6 @@ struct SVS_RUNTIME_API DynamicIVFIndexLeanVec : public DynamicIVFIndex {
size_t intra_query_threads = 1
) noexcept;
};

} // namespace v0
} // SVS_DECLARE_NAMESPACE_VERSION(0)
} // namespace runtime
} // namespace svs
9 changes: 2 additions & 7 deletions bindings/cpp/include/svs/runtime/dynamic_vamana_index.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,14 @@

namespace svs {
namespace runtime {
namespace v0 {

SVS_DECLARE_NAMESPACE_VERSION(0) {
// Abstract interface for Dynamic Vamana-based indexes.
struct SVS_RUNTIME_API DynamicVamanaIndex : public VamanaIndex {
virtual Status add(size_t n, const size_t* labels, const float* x) noexcept = 0;
virtual Status
remove_selected(size_t* num_removed, const IDFilter& selector) noexcept = 0;
virtual Status remove(size_t n, const size_t* labels) noexcept = 0;

virtual Status reset() noexcept = 0;

// Utility function to check storage kind support
static Status check_storage_kind(StorageKind storage_kind) noexcept;

Expand Down Expand Up @@ -65,7 +62,6 @@ struct SVS_RUNTIME_API DynamicVamanaIndex : public VamanaIndex {

static Status destroy(DynamicVamanaIndex* index) noexcept;

virtual Status save(std::ostream& out) const noexcept = 0;
static Status load(
DynamicVamanaIndex** index,
std::istream& in,
Expand Down Expand Up @@ -131,7 +127,6 @@ struct SVS_RUNTIME_API DynamicVamanaIndexLeanVec : public DynamicVamanaIndex {
const VamanaIndex::DynamicIndexParams& dynamic_index_params
) noexcept;
};

} // namespace v0
} // SVS_DECLARE_NAMESPACE_VERSION(0)
} // namespace runtime
} // namespace svs
6 changes: 2 additions & 4 deletions bindings/cpp/include/svs/runtime/flat_index.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@

namespace svs {
namespace runtime {
namespace v0 {

SVS_DECLARE_NAMESPACE_VERSION(0) {
// Abstract interface for Flat indices.
struct SVS_RUNTIME_API FlatIndex {
// Utility function to check storage kind support
Expand Down Expand Up @@ -55,7 +54,6 @@ struct SVS_RUNTIME_API FlatIndex {
static Status
map_to_memory(FlatIndex** index, void* data, size_t size, MetricType metric) noexcept;
};

} // namespace v0
} // SVS_DECLARE_NAMESPACE_VERSION(0)
} // namespace runtime
} // namespace svs
6 changes: 2 additions & 4 deletions bindings/cpp/include/svs/runtime/ivf_index.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@

namespace svs {
namespace runtime {
namespace v0 {

SVS_DECLARE_NAMESPACE_VERSION(0) {
// Abstract interface for IVF (Inverted File) indices.
struct SVS_RUNTIME_API IVFIndex {
virtual ~IVFIndex();
Expand Down Expand Up @@ -170,7 +169,6 @@ struct SVS_RUNTIME_API IVFIndexLeanVec : public IVFIndex {
size_t intra_query_threads = 1
) noexcept;
};

} // namespace v0
} // SVS_DECLARE_NAMESPACE_VERSION(0)
} // namespace runtime
} // namespace svs
6 changes: 2 additions & 4 deletions bindings/cpp/include/svs/runtime/training.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@

namespace svs {
namespace runtime {
namespace v0 {

SVS_DECLARE_NAMESPACE_VERSION(0) {
struct SVS_RUNTIME_API LeanVecTrainingData {
virtual ~LeanVecTrainingData();

Expand Down Expand Up @@ -70,7 +69,6 @@ struct SVS_RUNTIME_API LeanVecTrainingData {
virtual Status save(std::ostream& out) const noexcept = 0;
static Status load(LeanVecTrainingData** training_data, std::istream& in) noexcept;
};

} // namespace v0
} // SVS_DECLARE_NAMESPACE_VERSION(0)
} // namespace runtime
} // namespace svs
6 changes: 2 additions & 4 deletions bindings/cpp/include/svs/runtime/vamana_index.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@

namespace svs {
namespace runtime {
namespace v0 {

SVS_DECLARE_NAMESPACE_VERSION(0) {
namespace detail {
struct VamanaBuildParameters {
size_t graph_max_degree = Unspecify<size_t>();
Expand Down Expand Up @@ -151,7 +150,6 @@ struct SVS_RUNTIME_API VamanaIndexLeanVec : public VamanaIndex {
const VamanaIndex::SearchParams& default_search_params = {}
) noexcept;
};

} // namespace v0
} // SVS_DECLARE_NAMESPACE_VERSION(0)
} // namespace runtime
} // namespace svs
36 changes: 20 additions & 16 deletions bindings/cpp/include/svs/runtime/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
///
/// This header defines the SVS Runtime API versioning scheme:
/// 1. Versioned namespaces (e.g., v0, v1) for API stability
/// 2. Using declarations to bring current version to parent namespace
/// 2. Inline namespace to expose the current API version at svs::runtime::*
/// 3. Clean integration points for external libraries
///
/// Usage:
Expand Down Expand Up @@ -59,21 +59,21 @@
#define SVS_RUNTIME_API_VERSION SVS_RUNTIME_VERSION_MAJOR
#endif

#define SVS_API_VERSION_NS_IMPL(version) v##version
#define SVS_API_VERSION_NS(version) SVS_API_VERSION_NS_IMPL(version)
#define SVS_RUNTIME_API_VERSION_NAMESPACE SVS_API_VERSION_NS(SVS_RUNTIME_API_VERSION)

#if (SVS_RUNTIME_API_VERSION == 0)
/// Use v0 API
/// Current API version namespace
#define SVS_RUNTIME_CURRENT_API_NAMESPACE v0
namespace svs {
namespace runtime {
/// Current API version namespace (v0)
/// All public runtime APIs live here and are accessible as svs::runtime::FunctionName
/// due to inline namespace
inline namespace v0 {
// Public runtime APIs will be defined in their respective headers
// IMPORTANT: include this header before other runtime headers to ensure proper versioning
}
} // namespace runtime
} // namespace svs
#define SVS_DECLARE_NAMESPACE_VERSION_0 inline namespace SVS_API_VERSION_NS(0)

// Forward declaration for the current version namespace as inline namespace
// This enforces compilation warnings/errors if the v0 namespace is not inlined below
namespace svs::runtime {
inline namespace v0 {}
} // namespace svs::runtime
#else
#error "Unsupported SVS Runtime major version"
#endif
Expand All @@ -86,11 +86,15 @@ inline namespace v0 {
#define SVS_RUNTIME_CREATE_API_ALIAS(alias_name, version_ns) \
namespace alias_name = svs::runtime::version_ns

/// Helper macro to declare versioned namespaces for API definitions
#define SVS_DECLARE_NAMESPACE_VERSION_IMPL(version) SVS_DECLARE_NAMESPACE_VERSION_##version
#define SVS_DECLARE_NAMESPACE_VERSION(version) SVS_DECLARE_NAMESPACE_VERSION_IMPL(version)

///
/// @brief Version information structure for runtime queries
///
namespace svs::runtime::v0 {

namespace svs::runtime {
SVS_DECLARE_NAMESPACE_VERSION(0) {
struct VersionInfo {
static constexpr int major = SVS_RUNTIME_VERSION_MAJOR;
static constexpr int minor = SVS_RUNTIME_VERSION_MINOR;
Expand All @@ -109,5 +113,5 @@ struct VersionInfo {
return major == requested_major;
}
};

} // namespace svs::runtime::v0
} // SVS_DECLARE_NAMESPACE_VERSION(0)
} // namespace svs::runtime
2 changes: 1 addition & 1 deletion bindings/cpp/src/dynamic_vamana_index.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ struct DynamicVamanaIndexManagerBase : public DynamicVamanaIndex {
});
}

size_t blocksize_bytes() const noexcept { return impl_->blocksize_bytes(); }
size_t blocksize_bytes() const noexcept override { return impl_->blocksize_bytes(); }

Status
remove_selected(size_t* num_removed, const IDFilter& selector) noexcept override {
Expand Down
2 changes: 2 additions & 0 deletions bindings/cpp/src/dynamic_vamana_index_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ class DynamicVamanaIndexImpl {
}
}

virtual ~DynamicVamanaIndexImpl() = default;

size_t size() const { return impl_ ? impl_->size() : 0; }

size_t blocksize_bytes() const { return 1u << dynamic_index_params_.blocksize_exp; }
Expand Down
2 changes: 2 additions & 0 deletions bindings/cpp/src/vamana_index_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ class VamanaIndexImpl {
}
}

virtual ~VamanaIndexImpl() = default;

size_t size() const { return impl_ ? get_impl()->size() : 0; }

size_t dimensions() const { return dim_; }
Expand Down
Loading
Loading