
Fixes #108624 This allows `flat_map::insert(Iter, Iter)` to directly forward to underlying containers' `insert(Iter, Iter)`, instead of inserting one element at a time, when input models "product iterator". atm, `flat_map::iterator` and `zip_view::iterator` are "product iterator"s. This gives about almost 10x speed up in my benchmark with -03 (for both before and after) ```cpp Benchmark Time CPU Time Old Time New CPU Old CPU New ----------------------------------------------------------------------------------------------------------------------------------------------- flat_map::insert_product_iterator_flat_map/32 -0.5028 -0.5320 149 74 149 70 flat_map::insert_product_iterator_flat_map/1024 -0.8617 -0.8618 3113 430 3112 430 flat_map::insert_product_iterator_flat_map/8192 -0.8877 -0.8877 26682 2995 26679 2995 flat_map::insert_product_iterator_flat_map/65536 -0.8769 -0.8769 226235 27844 226221 27841 flat_map::insert_product_iterator_zip/32 -0.5844 -0.5844 162 67 162 67 flat_map::insert_product_iterator_zip/1024 -0.8754 -0.8754 3427 427 3427 427 flat_map::insert_product_iterator_zip/8192 -0.8934 -0.8934 28134 3000 28132 3000 flat_map::insert_product_iterator_zip/65536 -0.8783 -0.8783 229783 27960 229767 27958 OVERALL_GEOMEAN -0.8319 -0.8332 0 0 0 0 ``` --------- Co-authored-by: Louis Dionne <ldionne.2@gmail.com>
219 lines
7.8 KiB
C++
219 lines
7.8 KiB
C++
// -*- C++ -*-
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef _LIBCPP___FLAT_MAP_KEY_VALUE_ITERATOR_H
|
|
#define _LIBCPP___FLAT_MAP_KEY_VALUE_ITERATOR_H
|
|
|
|
#include <__compare/three_way_comparable.h>
|
|
#include <__concepts/convertible_to.h>
|
|
#include <__config>
|
|
#include <__cstddef/size_t.h>
|
|
#include <__iterator/iterator_traits.h>
|
|
#include <__iterator/product_iterator.h>
|
|
#include <__memory/addressof.h>
|
|
#include <__type_traits/conditional.h>
|
|
#include <__utility/forward.h>
|
|
#include <__utility/move.h>
|
|
#include <__utility/pair.h>
|
|
|
|
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
|
# pragma GCC system_header
|
|
#endif
|
|
|
|
_LIBCPP_PUSH_MACROS
|
|
#include <__undef_macros>
|
|
|
|
#if _LIBCPP_STD_VER >= 23
|
|
|
|
_LIBCPP_BEGIN_NAMESPACE_STD
|
|
|
|
/**
|
|
* __key_value_iterator is a proxy iterator which zips the underlying
|
|
* _KeyContainer::iterator and the underlying _MappedContainer::iterator.
|
|
* The two underlying iterators will be incremented/decremented together.
|
|
* And the reference is a pair of the const key reference and the value reference.
|
|
*/
|
|
template <class _Owner, class _KeyContainer, class _MappedContainer, bool _Const>
|
|
struct __key_value_iterator {
|
|
private:
|
|
using __key_iterator _LIBCPP_NODEBUG = typename _KeyContainer::const_iterator;
|
|
using __mapped_iterator _LIBCPP_NODEBUG =
|
|
_If<_Const, typename _MappedContainer::const_iterator, typename _MappedContainer::iterator>;
|
|
using __reference _LIBCPP_NODEBUG = _If<_Const, typename _Owner::const_reference, typename _Owner::reference>;
|
|
|
|
struct __arrow_proxy {
|
|
__reference __ref_;
|
|
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 __reference* operator->() { return std::addressof(__ref_); }
|
|
};
|
|
|
|
__key_iterator __key_iter_;
|
|
__mapped_iterator __mapped_iter_;
|
|
|
|
friend _Owner;
|
|
|
|
template <class, class, class, bool>
|
|
friend struct __key_value_iterator;
|
|
|
|
friend struct __product_iterator_traits<__key_value_iterator>;
|
|
|
|
public:
|
|
using iterator_concept = random_access_iterator_tag;
|
|
// `__key_value_iterator` only satisfy "Cpp17InputIterator" named requirements, because
|
|
// its `reference` is not a reference type.
|
|
// However, to avoid surprising runtime behaviour when it is used with the
|
|
// Cpp17 algorithms or operations, iterator_category is set to random_access_iterator_tag.
|
|
using iterator_category = random_access_iterator_tag;
|
|
using value_type = typename _Owner::value_type;
|
|
using difference_type = typename _Owner::difference_type;
|
|
|
|
_LIBCPP_HIDE_FROM_ABI __key_value_iterator() = default;
|
|
|
|
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26
|
|
__key_value_iterator(__key_value_iterator<_Owner, _KeyContainer, _MappedContainer, !_Const> __i)
|
|
requires _Const && convertible_to<typename _KeyContainer::iterator, __key_iterator> &&
|
|
convertible_to<typename _MappedContainer::iterator, __mapped_iterator>
|
|
: __key_iter_(std::move(__i.__key_iter_)), __mapped_iter_(std::move(__i.__mapped_iter_)) {}
|
|
|
|
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26
|
|
__key_value_iterator(__key_iterator __key_iter, __mapped_iterator __mapped_iter)
|
|
: __key_iter_(std::move(__key_iter)), __mapped_iter_(std::move(__mapped_iter)) {}
|
|
|
|
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 __reference operator*() const {
|
|
return __reference(*__key_iter_, *__mapped_iter_);
|
|
}
|
|
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 __arrow_proxy operator->() const { return __arrow_proxy{**this}; }
|
|
|
|
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 __key_value_iterator& operator++() {
|
|
++__key_iter_;
|
|
++__mapped_iter_;
|
|
return *this;
|
|
}
|
|
|
|
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 __key_value_iterator operator++(int) {
|
|
__key_value_iterator __tmp(*this);
|
|
++*this;
|
|
return __tmp;
|
|
}
|
|
|
|
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 __key_value_iterator& operator--() {
|
|
--__key_iter_;
|
|
--__mapped_iter_;
|
|
return *this;
|
|
}
|
|
|
|
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 __key_value_iterator operator--(int) {
|
|
__key_value_iterator __tmp(*this);
|
|
--*this;
|
|
return __tmp;
|
|
}
|
|
|
|
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 __key_value_iterator& operator+=(difference_type __x) {
|
|
__key_iter_ += __x;
|
|
__mapped_iter_ += __x;
|
|
return *this;
|
|
}
|
|
|
|
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 __key_value_iterator& operator-=(difference_type __x) {
|
|
__key_iter_ -= __x;
|
|
__mapped_iter_ -= __x;
|
|
return *this;
|
|
}
|
|
|
|
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 __reference operator[](difference_type __n) const {
|
|
return *(*this + __n);
|
|
}
|
|
|
|
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 friend bool
|
|
operator==(const __key_value_iterator& __x, const __key_value_iterator& __y) {
|
|
return __x.__key_iter_ == __y.__key_iter_;
|
|
}
|
|
|
|
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 friend bool
|
|
operator<(const __key_value_iterator& __x, const __key_value_iterator& __y) {
|
|
return __x.__key_iter_ < __y.__key_iter_;
|
|
}
|
|
|
|
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 friend bool
|
|
operator>(const __key_value_iterator& __x, const __key_value_iterator& __y) {
|
|
return __y < __x;
|
|
}
|
|
|
|
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 friend bool
|
|
operator<=(const __key_value_iterator& __x, const __key_value_iterator& __y) {
|
|
return !(__y < __x);
|
|
}
|
|
|
|
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 friend bool
|
|
operator>=(const __key_value_iterator& __x, const __key_value_iterator& __y) {
|
|
return !(__x < __y);
|
|
}
|
|
|
|
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 friend auto
|
|
operator<=>(const __key_value_iterator& __x, const __key_value_iterator& __y)
|
|
requires three_way_comparable<__key_iterator>
|
|
{
|
|
return __x.__key_iter_ <=> __y.__key_iter_;
|
|
}
|
|
|
|
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 friend __key_value_iterator
|
|
operator+(const __key_value_iterator& __i, difference_type __n) {
|
|
auto __tmp = __i;
|
|
__tmp += __n;
|
|
return __tmp;
|
|
}
|
|
|
|
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 friend __key_value_iterator
|
|
operator+(difference_type __n, const __key_value_iterator& __i) {
|
|
return __i + __n;
|
|
}
|
|
|
|
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 friend __key_value_iterator
|
|
operator-(const __key_value_iterator& __i, difference_type __n) {
|
|
auto __tmp = __i;
|
|
__tmp -= __n;
|
|
return __tmp;
|
|
}
|
|
|
|
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 friend difference_type
|
|
operator-(const __key_value_iterator& __x, const __key_value_iterator& __y) {
|
|
return difference_type(__x.__key_iter_ - __y.__key_iter_);
|
|
}
|
|
};
|
|
|
|
template <class _Owner, class _KeyContainer, class _MappedContainer, bool _Const>
|
|
struct __product_iterator_traits<__key_value_iterator<_Owner, _KeyContainer, _MappedContainer, _Const>> {
|
|
static constexpr size_t __size = 2;
|
|
|
|
template <size_t _Nth, class _Iter>
|
|
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 static decltype(auto) __get_iterator_element(_Iter&& __it)
|
|
requires(_Nth <= 1)
|
|
{
|
|
if constexpr (_Nth == 0) {
|
|
return std::forward<_Iter>(__it).__key_iter_;
|
|
} else {
|
|
return std::forward<_Iter>(__it).__mapped_iter_;
|
|
}
|
|
}
|
|
|
|
template <class _KeyIter, class _MappedIter>
|
|
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 static auto
|
|
__make_product_iterator(_KeyIter&& __key_iter, _MappedIter&& __mapped_iter) {
|
|
return __key_value_iterator<_Owner, _KeyContainer, _MappedContainer, _Const>(
|
|
std::forward<_KeyIter>(__key_iter), std::forward<_MappedIter>(__mapped_iter));
|
|
}
|
|
};
|
|
|
|
_LIBCPP_END_NAMESPACE_STD
|
|
|
|
#endif // _LIBCPP_STD_VER >= 23
|
|
|
|
_LIBCPP_POP_MACROS
|
|
|
|
#endif // _LIBCPP___FLAT_MAP_KEY_VALUE_ITERATOR_H
|