Skip to content
Open
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
24 changes: 19 additions & 5 deletions clang/include/clang/AST/ASTVector.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,9 +180,21 @@ class ASTVector {
size_t capacity() const { return this->capacity_ptr() - Begin; }

/// append - Add the specified range to the end of the SmallVector.
template<typename in_iter>
template <typename in_iter>
void append(const ASTContext &C, in_iter in_start, in_iter in_end) {
size_type NumInputs = std::distance(in_start, in_end);
using size_type =
typename std::remove_reference_t<decltype(*this)>::size_type;
using iterator_category =
typename std::iterator_traits<in_iter>::iterator_category;

size_t NumInputs = 0;
constexpr bool is_random_access =
std::is_base_of_v<std::random_access_iterator_tag, iterator_category>;

if constexpr (is_random_access)
NumInputs = static_cast<size_type>(in_end - in_start);
else
NumInputs = static_cast<size_type>(std::distance(in_start, in_end));

if (NumInputs == 0)
return;
Expand All @@ -192,9 +204,11 @@ class ASTVector {
this->grow(C, this->size()+NumInputs);

// Copy the new elements over.
// TODO: NEED To compile time dispatch on whether in_iter is a random access
// iterator to use the fast uninitialized_copy.
Comment on lines -195 to -196
Copy link
Contributor

@zwuis zwuis Oct 5, 2025

Choose a reason for hiding this comment

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

Is the comment correct? Can you confirm that std::distance and std::uninitialized_copy do NOT perform compile time dispatch? How is std::uninitialized_copy_n faster here?

Update: I can confirm that the implementation of std::uninitialized_copy doesn't perform compile time dispatch, but I don't see how is std::uninitialized_copy_n faster.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@zwuis,thanks for your review.

std::distance and std::uninitialized_copy both rely on iterator tag dispatch, which determines the implementation at overload resolution time rather than through explicit compile-time branching. While std::distance will use an O(1) path for random access iterators, that dispatch happens inside the library and isn’t guaranteed to inline cleanly into templated call sites like append(). Moreover, std::uninitialized_copy always performs an element-by-element loop regardless of iterator category, offering no benefit when the range size (NumInputs) is already known. Using std::uninitialized_copy_n with a precomputed element count avoids the per-iteration sentinel checks and enables the compiler to generate tighter loops.

std::uninitialized_copy(in_start, in_end, this->end());
if constexpr (is_random_access)
std::uninitialized_copy_n(in_start, NumInputs, this->end());
else
std::uninitialized_copy(in_start, in_end, this->end());

this->setEnd(this->end() + NumInputs);
}

Expand Down