[libcxx-commits] [libcxx] [libc++][ranges] implement `ranges::shift_left` (PR #83231)

Xiaoyang Liu via libcxx-commits libcxx-commits at lists.llvm.org
Mon Mar 4 23:01:53 PST 2024


xiaoyang-sde wrote:

I attempt to explain how the `__shift_left` function works in this comment. The idea is to perform operations with linear complexity on the range at most twice – first when finding `__m` and then when actually moving the elements. Overall, all execution-flow involves at most two linear operations on the range.

```cpp
template <class _AlgPolicy, class _Iter, class _Sent>
_LIBCPP_HIDE_FROM_ABI constexpr pair<_Iter, _Iter>
__shift_left(_Iter __first, _Sent __last, typename _IterOps<_AlgPolicy>::template __difference_type<_Iter> __n) {
  _LIBCPP_ASSERT_UNCATEGORIZED(__n >= 0, "__n must be greater than or equal to 0");

  if (__n == 0) {
    _Iter __end = _IterOps<_AlgPolicy>::next(__first, __last); // This operation is either constant or linear
    return {std::move(__first), std::move(__end)};
  }

  _Iter __m = __first;
  if constexpr (sized_sentinel_for<_Sent, _Iter>) {
    auto __size = _IterOps<_AlgPolicy>::distance(__first, __last); // This operation is constant
    if (__n >= __size) {
      return {std::move(__first), std::move(__first)};
    }
    _IterOps<_AlgPolicy>::advance(__m, __n);  // This operation is either constant or linear
  } else {
    // This for-loop is linear
    for (; __n > 0; --__n) {
      if (__m == __last) {
        return {std::move(__first), std::move(__first)};
      }
      ++__m;
    }
  }

  _Iter __result = std::__move<_AlgPolicy>(__m, __last, __first).second; // This operation is linear
  return {std::move(__first), std::move(__result)};
}
```

https://github.com/llvm/llvm-project/pull/83231


More information about the libcxx-commits mailing list