Skip to content

Commit

Permalink
Optimize ranges::move{,_backward} for vector<bool>::iterator
Browse files Browse the repository at this point in the history
  • Loading branch information
winner245 committed Dec 25, 2024
1 parent 8db7327 commit 544adcf
Show file tree
Hide file tree
Showing 9 changed files with 374 additions and 110 deletions.
10 changes: 10 additions & 0 deletions libcxx/include/__algorithm/move.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@
#ifndef _LIBCPP___ALGORITHM_MOVE_H
#define _LIBCPP___ALGORITHM_MOVE_H

#include <__algorithm/copy.h>
#include <__algorithm/copy_move_common.h>
#include <__algorithm/for_each_segment.h>
#include <__algorithm/iterator_operations.h>
#include <__algorithm/min.h>
#include <__config>
#include <__fwd/bit_reference.h>
#include <__iterator/iterator_traits.h>
#include <__iterator/segmented_iterator.h>
#include <__type_traits/common_type.h>
Expand Down Expand Up @@ -98,6 +100,14 @@ struct __move_impl {
}
}

template <class _Cp, bool _IsConst>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<__bit_iterator<_Cp, _IsConst>, __bit_iterator<_Cp, false> >
operator()(__bit_iterator<_Cp, _IsConst> __first,
__bit_iterator<_Cp, _IsConst> __last,
__bit_iterator<_Cp, false> __result) {
return std::__copy(__first, __last, __result);
}

// At this point, the iterators have been unwrapped so any `contiguous_iterator` has been unwrapped to a pointer.
template <class _In, class _Out, __enable_if_t<__can_lower_move_assignment_to_memmove<_In, _Out>::value, int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_In*, _Out*>
Expand Down
10 changes: 10 additions & 0 deletions libcxx/include/__algorithm/move_backward.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@
#ifndef _LIBCPP___ALGORITHM_MOVE_BACKWARD_H
#define _LIBCPP___ALGORITHM_MOVE_BACKWARD_H

#include <__algorithm/copy_backward.h>
#include <__algorithm/copy_move_common.h>
#include <__algorithm/iterator_operations.h>
#include <__algorithm/min.h>
#include <__config>
#include <__fwd/bit_reference.h>
#include <__iterator/iterator_traits.h>
#include <__iterator/segmented_iterator.h>
#include <__type_traits/common_type.h>
Expand Down Expand Up @@ -107,6 +109,14 @@ struct __move_backward_impl {
}
}

template <class _Cp, bool _IsConst>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<__bit_iterator<_Cp, _IsConst>, __bit_iterator<_Cp, false> >
operator()(__bit_iterator<_Cp, _IsConst> __first,
__bit_iterator<_Cp, _IsConst> __last,
__bit_iterator<_Cp, false> __result) {
return std::__copy_backward<_ClassicAlgPolicy>(__first, __last, __result);
}

// At this point, the iterators have been unwrapped so any `contiguous_iterator` has been unwrapped to a pointer.
template <class _In, class _Out, __enable_if_t<__can_lower_move_assignment_to_memmove<_In, _Out>::value, int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_In*, _Out*>
Expand Down
16 changes: 0 additions & 16 deletions libcxx/include/__bit_reference
Original file line number Diff line number Diff line change
Expand Up @@ -421,22 +421,6 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator<_Cp, f
return std::__copy_backward_unaligned(__first, __last, __result);
}

// move

template <class _Cp, bool _IsConst>
inline _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false>
move(__bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __last, __bit_iterator<_Cp, false> __result) {
return std::copy(__first, __last, __result);
}

// move_backward

template <class _Cp, bool _IsConst>
inline _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> move_backward(
__bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __last, __bit_iterator<_Cp, false> __result) {
return std::copy_backward(__first, __last, __result);
}

// swap_ranges

template <class _Cl, class _Cr>
Expand Down
55 changes: 55 additions & 0 deletions libcxx/test/benchmarks/algorithms/move.bench.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20

#include <algorithm>
#include <benchmark/benchmark.h>
#include <vector>

static void bm_ranges_move(benchmark::State& state, bool aligned) {
auto n = state.range();
std::vector<bool> in(n, true);
std::vector<bool> out(aligned ? n : n + 8);
benchmark::DoNotOptimize(&in);
auto dst = aligned ? out.begin() : out.begin() + 4;
for (auto _ : state) {
benchmark::DoNotOptimize(std::ranges::move(in, dst));
benchmark::DoNotOptimize(&out);
}
}

static void bm_move(benchmark::State& state, bool aligned) {
auto n = state.range();
std::vector<bool> in(n, true);
std::vector<bool> out(aligned ? n : n + 8);
benchmark::DoNotOptimize(&in);
auto beg = in.begin();
auto end = in.end();
auto dst = aligned ? out.begin() : out.begin() + 4;
for (auto _ : state) {
benchmark::DoNotOptimize(std::move(beg, end, dst));
benchmark::DoNotOptimize(&out);
}
}

static void bm_ranges_move_aligned(benchmark::State& state) { bm_ranges_move(state, true); }
static void bm_ranges_move_unaligned(benchmark::State& state) { bm_ranges_move(state, false); }

static void bm_move_aligned(benchmark::State& state) { bm_move(state, true); }
static void bm_move_unaligned(benchmark::State& state) { bm_move(state, false); }

// Test std::ranges::move for vector<bool>::iterator
BENCHMARK(bm_ranges_move_aligned)->Range(8, 1 << 20);
BENCHMARK(bm_ranges_move_unaligned)->Range(8, 1 << 20);

// Test std::move for vector<bool>::iterator
BENCHMARK(bm_move_aligned)->Range(8, 1 << 20);
BENCHMARK(bm_move_unaligned)->Range(8, 1 << 20);

BENCHMARK_MAIN();
55 changes: 55 additions & 0 deletions libcxx/test/benchmarks/algorithms/move_backward.bench.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20

#include <algorithm>
#include <benchmark/benchmark.h>
#include <vector>

static void bm_ranges_move_backward(benchmark::State& state, bool aligned) {
auto n = state.range();
std::vector<bool> in(n, true);
std::vector<bool> out(aligned ? n : n + 8);
benchmark::DoNotOptimize(&in);
auto dst = aligned ? out.end() : out.end() - 4;
for (auto _ : state) {
benchmark::DoNotOptimize(std::ranges::move_backward(in, dst));
benchmark::DoNotOptimize(&out);
}
}

static void bm_move_backward(benchmark::State& state, bool aligned) {
auto n = state.range();
std::vector<bool> in(n, true);
std::vector<bool> out(aligned ? n : n + 8);
benchmark::DoNotOptimize(&in);
auto beg = in.begin();
auto end = in.end();
auto dst = aligned ? out.end() : out.end() - 4;
for (auto _ : state) {
benchmark::DoNotOptimize(std::move_backward(beg, end, dst));
benchmark::DoNotOptimize(&out);
}
}

static void bm_ranges_move_backward_aligned(benchmark::State& state) { bm_ranges_move_backward(state, true); }
static void bm_ranges_move_backward_unaligned(benchmark::State& state) { bm_ranges_move_backward(state, false); }

static void bm_move_backward_aligned(benchmark::State& state) { bm_move_backward(state, true); }
static void bm_move_backward_unaligned(benchmark::State& state) { bm_move_backward(state, false); }

// Test std::ranges::move_backward for vector<bool>::iterator
BENCHMARK(bm_ranges_move_backward_aligned)->Range(8, 1 << 20);
BENCHMARK(bm_ranges_move_backward_unaligned)->Range(8, 1 << 20);

// Test std::move_backward for vector<bool>::iterator
BENCHMARK(bm_move_backward_aligned)->Range(8, 1 << 20);
BENCHMARK(bm_move_backward_unaligned)->Range(8, 1 << 20);

BENCHMARK_MAIN();
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <cassert>
#include <iterator>
#include <memory>
#include <vector>

#include "MoveOnly.h"
#include "test_iterators.h"
Expand All @@ -45,15 +46,15 @@ struct Test {
template <class OutIter>
TEST_CONSTEXPR_CXX20 void operator()() {
const unsigned N = 1000;
int ia[N] = {};
int ia[N] = {};
for (unsigned i = 0; i < N; ++i)
ia[i] = i;
ia[i] = i;
int ib[N] = {0};

OutIter r = std::move(InIter(ia), InIter(ia+N), OutIter(ib));
assert(base(r) == ib+N);
OutIter r = std::move(InIter(ia), InIter(ia + N), OutIter(ib));
assert(base(r) == ib + N);
for (unsigned i = 0; i < N; ++i)
assert(ia[i] == ib[i]);
assert(ia[i] == ib[i]);
}
};

Expand All @@ -73,13 +74,13 @@ struct Test1 {
const unsigned N = 100;
std::unique_ptr<int> ia[N];
for (unsigned i = 0; i < N; ++i)
ia[i].reset(new int(i));
ia[i].reset(new int(i));
std::unique_ptr<int> ib[N];

OutIter r = std::move(InIter(ia), InIter(ia+N), OutIter(ib));
assert(base(r) == ib+N);
OutIter r = std::move(InIter(ia), InIter(ia + N), OutIter(ib));
assert(base(r) == ib + N);
for (unsigned i = 0; i < N; ++i)
assert(*ib[i] == static_cast<int>(i));
assert(*ib[i] == static_cast<int>(i));
}
};

Expand All @@ -92,6 +93,28 @@ struct Test1OutIters {
}
};

template <std::size_t N>
struct TestBitIter {
std::vector<bool> in;
TEST_CONSTEXPR_CXX20 TestBitIter() : in(N, false) {
for (std::size_t i = 0; i < N; i += 2)
in[i] = true;
}
TEST_CONSTEXPR_CXX20 void operator()() {
{ // Test move with aligned bytes
std::vector<bool> out(N);
std::move(in.begin(), in.end(), out.begin());
assert(in == out);
}
{ // Test move with unaligned bytes
std::vector<bool> out(N + 8);
std::move(in.begin(), in.end(), out.begin() + 4);
for (std::size_t i = 0; i < N; ++i)
assert(out[i + 4] == in[i]);
}
}
};

TEST_CONSTEXPR_CXX20 bool test() {
types::for_each(types::cpp17_input_iterator_list<int*>(), TestOutIters());
if (TEST_STD_AT_LEAST_23_OR_RUNTIME_EVALUATED)
Expand All @@ -118,7 +141,7 @@ TEST_CONSTEXPR_CXX20 bool test() {
// When non-trivial
{
MoveOnly from[3] = {1, 2, 3};
MoveOnly to[3] = {};
MoveOnly to[3] = {};
std::move(std::begin(from), std::end(from), std::begin(to));
assert(to[0] == MoveOnly(1));
assert(to[1] == MoveOnly(2));
Expand All @@ -127,14 +150,22 @@ TEST_CONSTEXPR_CXX20 bool test() {
// When trivial
{
TrivialMoveOnly from[3] = {1, 2, 3};
TrivialMoveOnly to[3] = {};
TrivialMoveOnly to[3] = {};
std::move(std::begin(from), std::end(from), std::begin(to));
assert(to[0] == TrivialMoveOnly(1));
assert(to[1] == TrivialMoveOnly(2));
assert(to[2] == TrivialMoveOnly(3));
}
}

{ // Test vector<bool>::iterator optimization
TestBitIter<8>()();
TestBitIter<16>()();
TestBitIter<32>()();
TestBitIter<64>()();
TestBitIter<1024>()();
}

return true;
}

Expand Down
Loading

0 comments on commit 544adcf

Please sign in to comment.