[libcxx-commits] [libcxx] Optimize input iterator overload of `std::vector::assign(first, last)` (PR #113852)
Nikolas Klauser via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Nov 15 06:38:59 PST 2024
================
@@ -48,6 +48,76 @@ void BM_Assignment(benchmark::State& st, Container) {
}
}
+// Wrap any Iterator into an input iterator
+template <typename Iterator>
+class InputIterator {
+ using iter_traits = std::iterator_traits<Iterator>;
+
+public:
+ using iterator_category = std::input_iterator_tag;
+ using value_type = typename iter_traits::value_type;
+ using difference_type = typename iter_traits::difference_type;
+ using pointer = typename iter_traits::pointer;
+ using reference = typename iter_traits::reference;
+
+ InputIterator(Iterator it) : current_(it) {}
+
+ reference operator*() { return *current_; }
+ InputIterator& operator++() {
+ ++current_;
+ return *this;
+ }
+ InputIterator operator++(int) {
+ InputIterator tmp = *this;
+ ++(*this);
+ return tmp;
+ }
+
+ friend bool operator==(const InputIterator& lhs, const InputIterator& rhs) { return lhs.current_ == rhs.current_; }
+ friend bool operator!=(const InputIterator& lhs, const InputIterator& rhs) { return !(lhs == rhs); }
+
+private:
+ Iterator current_;
+};
+
+template <typename Iterator>
+InputIterator<Iterator> make_input_iterator(Iterator it) {
+ return InputIterator<Iterator>(it);
+}
+
+template <class Container,
+ class GenInputs,
+ typename std::enable_if<std::is_trivial<typename Container::value_type>::value>::type* = nullptr>
+void BM_AssignInputIterIter(benchmark::State& st, Container c, GenInputs gen) {
+ auto in = gen(st.range(1));
+ benchmark::DoNotOptimize(&in);
+ for (auto _ : st) {
+ st.PauseTiming();
+ c.resize(st.range(0));
+ benchmark::DoNotOptimize(&c);
+ st.ResumeTiming();
----------------
philnik777 wrote:
You are right, the vector doesn't grow. I was mentally at `insert` for some reason.
Generally though, it's fine to add extra operations into a benchmark as long as you do so consistently. Sizing down the vector again to avoid allocations is most likely much less costly than `PauseTiming()` and `ResumeTiming()`. You just have to make sure that the optimizer isn't able to figure out what you're doing, so any resizing should be followed by a `DoNotOptimize`. As long as the `resize()` operations isn't changed we're still measuring the changes we're making to the operation we care about.
https://github.com/llvm/llvm-project/pull/113852
More information about the libcxx-commits
mailing list