1 /* 2 * Copyright (c) 2024 NVIDIA Corporation 3 * 4 * Licensed under the Apache License Version 2.0 with LLVM Exceptions 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * https://llvm.org/LICENSE.txt 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #pragma once 17 18 #include "__config.hpp" 19 20 #include <cstddef> 21 #include <cassert> 22 #include <iterator> 23 #include <utility> 24 25 namespace stdexec { 26 namespace __slist { 27 template <auto _Next> 28 class __intrusive_slist; 29 30 template <class _Item, _Item* _Item::* _Next> 31 class __intrusive_slist<_Next> { 32 public: 33 __intrusive_slist() noexcept = default; 34 __intrusive_slist(__intrusive_slist && __other)35 __intrusive_slist(__intrusive_slist&& __other) noexcept 36 : __head_(std::exchange(__other.__head_, nullptr)) { 37 } 38 __intrusive_slist(_Item * __head)39 __intrusive_slist(_Item* __head) noexcept 40 : __head_(__head) { 41 } 42 swap(__intrusive_slist & __other)43 auto swap(__intrusive_slist& __other) noexcept -> void { 44 std::swap(__head_, __other.__head_); 45 } 46 operator =(__intrusive_slist __other)47 auto operator=(__intrusive_slist __other) noexcept -> __intrusive_slist& { 48 swap(__other); 49 return *this; 50 } 51 52 [[nodiscard]] empty() const53 auto empty() const noexcept -> bool { 54 return __head_ == nullptr; 55 } 56 front() const57 auto front() const noexcept -> _Item* { 58 return __head_; 59 } 60 clear()61 void clear() noexcept { 62 __head_ = nullptr; 63 } 64 65 [[nodiscard]] pop_front()66 auto pop_front() noexcept -> _Item* { 67 STDEXEC_ASSERT(!empty()); 68 return std::exchange(__head_, __head_->*_Next); 69 } 70 push_front(_Item * __item)71 void push_front(_Item* __item) noexcept { 72 STDEXEC_ASSERT(__item != nullptr); 73 __item->*_Next = std::exchange(__head_, __item); 74 } 75 76 [[nodiscard]] remove(_Item * __item)77 auto remove(_Item* __item) noexcept -> _Item* { 78 STDEXEC_ASSERT(__item != nullptr); 79 if (__head_ == __item) { 80 return pop_front(); 81 } 82 83 for (_Item* __current: *this) { 84 if (__current->*_Next == __item) { 85 __current->*_Next = __item->*_Next; 86 return __item; 87 } 88 } 89 90 return nullptr; 91 } 92 93 struct iterator { 94 using iterator_category = std::forward_iterator_tag; 95 using difference_type = std::ptrdiff_t; 96 using value_type = _Item*; 97 using reference = _Item*; 98 using pointer = _Item**; 99 100 _Item* __item_ = nullptr; 101 102 iterator() noexcept = default; 103 iteratorstdexec::__slist::__intrusive_slist::iterator104 explicit iterator(_Item* __item) noexcept 105 : __item_(__item) { 106 } 107 108 [[nodiscard]] operator *stdexec::__slist::__intrusive_slist::iterator109 auto operator*() const noexcept -> _Item* { 110 STDEXEC_ASSERT(__item_ != nullptr); 111 return __item_; 112 } 113 114 [[nodiscard]] operator ->stdexec::__slist::__intrusive_slist::iterator115 auto operator->() const noexcept -> _Item** { 116 STDEXEC_ASSERT(__item_ != nullptr); 117 return &__item_; 118 } 119 operator ++stdexec::__slist::__intrusive_slist::iterator120 auto operator++() noexcept -> iterator& { 121 STDEXEC_ASSERT(__item_ != nullptr); 122 __item_ = __item_->*_Next; 123 return *this; 124 } 125 operator ++stdexec::__slist::__intrusive_slist::iterator126 auto operator++(int) noexcept -> iterator { 127 iterator __result = *this; 128 ++*this; 129 return __result; 130 } 131 132 auto operator==(const iterator&) const noexcept -> bool = default; 133 }; 134 135 [[nodiscard]] begin() const136 auto begin() const noexcept -> iterator { 137 return iterator(__head_); 138 } 139 140 [[nodiscard]] end() const141 auto end() const noexcept -> iterator { 142 return iterator(nullptr); 143 } 144 145 private: 146 _Item* __head_ = nullptr; 147 }; 148 } // namespace __slist 149 150 using __slist::__intrusive_slist; 151 152 } // namespace stdexec 153