Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[libc++] Introduce a concept for "product" iterators #108624

Open
ldionne opened this issue Sep 13, 2024 · 0 comments
Open

[libc++] Introduce a concept for "product" iterators #108624

ldionne opened this issue Sep 13, 2024 · 0 comments
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.

Comments

@ldionne
Copy link
Member

ldionne commented Sep 13, 2024

Here we materialize the iterator's value_type and we insert the elements one by one. If we had some kind of "protocol" that allows us to detect that an iterator is in fact a product of other iterators, we could decompose it to get the underlying iterators in the product and pass that directly to the containers. That way, we could call the underlying container's range-based insert method instead of inserting elements one-by-one.

This would apply to e.g. a zip view over two vectors, or when inserting into a flat_map from another flat_map. And given that we have significant optimizations in e.g. std::vector::insert(first, last) for contiguous iterators, this could end up making a big difference.

Example idea:

template <class _InputIterator, class _Sentinel>
  requires __is_product_iterator<_InputIterator>
_LIBCPP_HIDE_FROM_ABI size_type __append_no_check(_InputIterator __first, _Sentinel __last) {
  auto __first1 = std::__get_product_iterator_element<0>(__first);
  auto __first2 = std::__get_product_iterator_element<1>(__first);

  auto __last1 = std::__get_product_iterator_element<0>(__last);
  auto __last2 = std::__get_product_iterator_element<1>(__last);

  size_type __before = __containers_.keys.size();
  __containers_.keys.insert(__containers_.keys.end(), __first1, __last1);
  size_type __after = __containers_.keys.size();
  __containers_.values.insert(__containers_.values.end(), __first2, __last2);

  size_type __num_of_appended = __after - __before; // can we do better than that?

  // We could also have some kind of check like this, but we'd need to do that without making
  // the assumption that __first & __last are random access.
  _LIBCPP_ASSERT_INTERNAL((__last1 - __first1) == (__last2 - __first2), "something went horribly wrong");

  return __num_of_appended;
}

This makes me think about segmented iterator. It's not a category by itself, but it provides a (very useful) side channel to provide additional information to various places in the library. We don't have to implement this optimization day one (in fact we probably shouldn't for simplicity), but I think we really should consider doing it as a follow-up.

CC @philnik777 since this is the kind of stuff you generally like

Originally posted by @ldionne in #98643 (comment)

@github-actions github-actions bot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Sep 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

No branches or pull requests

1 participant