Skip to content

Add a range constructor to vecsim_stl::vector - #1008

Open
dor-forer wants to merge 1 commit into
mainfrom
vecsim-stl-vector-range-ctor
Open

Add a range constructor to vecsim_stl::vector#1008
dor-forer wants to merge 1 commit into
mainfrom
vecsim-stl-vector-range-ctor

Conversation

@dor-forer

@dor-forer dor-forer commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

Describe the changes in the pull request

vecsim_stl::vector exposes only three constructors: empty, sized, and sized-with-fill-value. Building one from an existing range therefore means constructing it empty and copying the elements in by hand.

This adds the missing iterator-pair constructor, forwarding to the underlying std::vector and keeping the allocator as the trailing argument like the existing constructors:

template <std::input_iterator Iter>
explicit vector(Iter first, Iter last, const std::shared_ptr<VecSimAllocator> &alloc)
    : VecsimBaseObject(alloc), std::vector<T, VecsimSTLAllocator<T>>(first, last, alloc) {}

<iterator> is now included explicitly rather than relied upon transitively.

Why the std::input_iterator constraint: for a call like vecsim_stl::vector<size_t> v(10, 5, alloc) an unconstrained template would win overload resolution against the (count, value, alloc) constructor, since Iter = int is an exact match for both arguments while the fill constructor needs an int to size_t conversion, and conversion-sequence ranking is applied before the prefer-non-template tiebreak. In practice libstdc++ recovers (its own range constructor is SFINAE-guarded, so the forwarded (int, int, alloc) call lands back on its fill constructor), but relying on that is fragile and produces confusing diagnostics for genuinely bad calls. Constraining on std::input_iterator is the same idiom std::vector itself uses, keeps resolution correct at our own signature, and is free. No behaviour change for any existing call site.

Which issues this PR fixes

None. No MOD ticket: this came out of noticing the missing constructor. Happy to attach one if the convention requires it.

Main objects this PR modified

  1. vecsim_stl::vector (src/VecSim/utils/vecsim_stl.h) - added the range constructor.
  2. AllocatorTest (tests/unit/test_allocator.cpp) - new test_vector_range_constructor.

Mark if applicable

  • This PR introduces API changes
  • This PR introduces serialization changes

Neither box applies: the addition is internal C++ (not the extern "C" API in vec_sim.h), purely additive, and touches no serialized state.

Testing

New AllocatorTest.test_vector_range_constructor covers:

  • a random access iterator range, asserting the data is allocated through VecSimAllocator in a single allocation of the exact size, and released on destruction
  • a range taken from another vecsim_stl::vector
  • a std::list range (non-contiguous iterators, size not known upfront)
  • that vector<size_t>(10, 5, alloc) still resolves to the fill constructor

Verified on an Intel Xeon Platinum 8375C box (gcc 13.3, AVX512, SVS enabled):

  • full make build clean, zero errors
  • full make unit_test: 2607/2607 passed (the 8 reported as skipped are the pre-existing SVS quantization / dynamic-info-iterator cases, unrelated to this change)
  • targeted run after adding the test: ctest -R Allocator 8/8 passed, including the new case
  • make check-format clean

Note on scope

Nothing in src/ calls the new constructor yet. The nearest existing use is hnsw.h:915 in mutuallyConnectNewElement, where a fresh candidatesList is immediately filled by insert(end(), top_candidates.begin(), top_candidates.end()); converting it is a one-line readability change with identical allocation behaviour, and I left it out of this PR to keep a hot path out of scope. The first real consumer is likely the SQ8-with-norm path, whose QuantPreprocessor constructor already takes a const vecsim_stl::vector<float> &mean_vec that no src/ caller builds yet.

🤖 Generated with Claude Code

vecsim_stl::vector could only be built empty, with a size, or with a size
and a fill value, so building one from an existing range meant constructing
it empty and then copying elements in by hand.

Add an iterator-pair constructor that forwards to the underlying
std::vector, keeping the allocator as the trailing argument like the other
constructors. It is constrained to std::input_iterator (the same idiom
std::vector uses) so that calls such as vector<size_t>(10, 5, alloc) keep
resolving to the (count, value) constructor instead of being deduced as a
range of ints.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Aug 5, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.15%. Comparing base (efd63da) to head (abb18bf).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #1008   +/-   ##
=======================================
  Coverage   97.15%   97.15%           
=======================================
  Files         141      141           
  Lines        8328     8330    +2     
=======================================
+ Hits         8091     8093    +2     
  Misses        237      237           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant