1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 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 17 #ifndef CHRE_UTIL_INTRUSIVE_LIST_H_ 18 #define CHRE_UTIL_INTRUSIVE_LIST_H_ 19 20 #include <type_traits> 21 #include <utility> 22 23 #include "chre/util/intrusive_list_base.h" 24 25 #include "chre/util/container_support.h" 26 27 namespace chre { 28 29 template <typename ElementType> 30 struct ListNode { 31 // Check if the ElementType is appropriate. Inappropriate ElementType 32 // will lead to wrong behavior of the reinterpret_cast between 33 // Node and ListNode that we use the retrieve item. 34 static_assert(std::is_standard_layout<ElementType>::value, 35 "must be std layout to alias"); 36 37 /** 38 * Node that allows the linked list to link data. 39 * This need to be the first member of ListNode or the reinterpret_cast 40 * between Node and ListNode will fail. 41 */ 42 intrusive_list_internal::Node node; 43 44 /** 45 * The data that the user wants to store. 46 */ 47 ElementType item; 48 49 /** 50 * Construct a new List Node object by forwarding the arguments to 51 * the constructor of ElementType. 52 * 53 * This breaks C++ assumptions of which constructor is called (move/copy) when 54 * using assignment operator. However, in this case, it is safe to do so since 55 * ListNode is not copyable (Node is not copyable). 56 */ 57 template <typename... Args> ListNodeListNode58 ListNode(Args &&...args) : item(std::forward<Args>(args)...) {} 59 ~ListNodeListNode60 ~ListNode() { 61 CHRE_ASSERT(node.prev == nullptr && node.next == nullptr); 62 } 63 64 /** 65 * Checks if this list node is linked in a list. 66 * 67 * @return true if the list node is part of a list. 68 */ isLinkedListNode69 bool isLinked() const { 70 return node.prev != nullptr && node.next != nullptr; 71 } 72 }; 73 74 /** 75 * A container for storing data in a linked list. Note that this container does 76 * not allocate any memory, the caller need to manage the memory of the 77 * data/node that it wants to insert. 78 * 79 * Caller need to turn the data into nodes by doing ListNode<ElementType> before 80 * using the linked list to manage data. This approach is preferred over the 81 * more intrusive way to let user create a new node structure that inherits from 82 * Node, since user will not need to worry about handling the extra node type 83 * but focus on interacting with the list. 84 * 85 * Note that although ListNode.node is accessible to client code, user should 86 * not modify them directly without using the linked list. 87 * 88 * Example: 89 * typedef ListNode<int> ListIntNode; 90 * ListIntNode node(10); 91 * IntrusiveList<int> myList; 92 * myList.push_back(node); 93 * 94 * Note that myList is declared after node so that myList will be destructed 95 * before node. 96 * 97 * @tparam ElementType: The data type that wants to be stored using the link 98 * list. 99 */ 100 template <typename ElementType> 101 class IntrusiveList : private intrusive_list_internal::IntrusiveListBase { 102 // Check if the ListNode layout is appropriate. Inappropriate or 103 // ListNode will lead to wrong behavior of the reinterpret_cast between 104 // Node and ListNode that we use the retrieve item. 105 static_assert(offsetof(ListNode<ElementType>, node) == 0, 106 "node must be the first element"); 107 108 public: 109 class Iterator { 110 using Node = ::chre::intrusive_list_internal::Node; 111 112 public: Iterator(Node * node)113 Iterator(Node *node) : mNode(node) {} 114 115 ListNode<ElementType> &operator*() const { 116 return *reinterpret_cast<ListNode<ElementType> *>(mNode); 117 } 118 119 ListNode<ElementType> *operator->() { 120 return reinterpret_cast<ListNode<ElementType> *>(mNode); 121 } 122 123 Iterator &operator++() { 124 mNode = mNode->next; 125 return *this; 126 } 127 128 Iterator &operator--() { 129 mNode = mNode->prev; 130 return *this; 131 } 132 133 bool operator==(Iterator other) const { 134 return mNode == other.mNode; 135 } 136 bool operator!=(Iterator other) const { 137 return mNode != other.mNode; 138 } 139 140 private: 141 Node *mNode; 142 }; 143 144 /** 145 * Default construct a new Intrusive Linked List. 146 */ 147 IntrusiveList() = default; 148 149 /** 150 * Unlink all node when destroy the Intrusive List object. 151 */ 152 ~IntrusiveList(); 153 154 /** 155 * Examines if the linked list is empty. 156 * 157 * @return true if the linked list has no linked node. 158 */ empty()159 bool empty() const { 160 return mSize == 0; 161 } 162 163 /** 164 * Returns the number of nodes stored in this linked list. 165 * 166 * @return The number of nodes in the linked list. 167 */ size()168 size_t size() const { 169 return mSize; 170 } 171 172 /** 173 * Link a new node to the front of the linked list. 174 * 175 * @param newNode: the node to push to the front of the linked list. 176 */ 177 void link_front(ListNode<ElementType> *newNode); 178 179 /** 180 * Link a new node to the end of the linked list. 181 * 182 * @param newNode: the node to push to the back of the linked list. 183 */ 184 void link_back(ListNode<ElementType> *newNode); 185 186 /** 187 * Returns a reference to the first node of the linked list. 188 * It is not allowed to call this on a empty list. 189 * 190 * @return The first node of the linked list 191 */ 192 ListNode<ElementType> &front(); 193 const ListNode<ElementType> &front() const; 194 195 /** 196 * Unlink the first node from the list. 197 * It is not allowed to call this on a empty list. 198 * Note that this function does not free the memory of the node. 199 */ 200 void unlink_front(); 201 202 /** 203 * Returns a reference to the last node of the linked list. 204 * It is not allowed to call this on a empty list. 205 * 206 * @return The last node of the linked list 207 */ 208 ListNode<ElementType> &back(); 209 const ListNode<ElementType> &back() const; 210 211 /** 212 * Unlink the last node from the list. 213 * It is not allowed to call this on a empty list. 214 * Note that this function does not free the memory of the node. 215 */ 216 void unlink_back(); 217 218 /** 219 * Remove a node from its list. 220 * 221 * @param node: Node that need to be unlinked. 222 */ 223 void unlink_node(ListNode<ElementType> *node); 224 225 /** 226 * Link a node after a given node. 227 * 228 * @param frontNode the old node that will be in front of the new node. 229 * @param newNode the new node that will be link to the list. 230 */ 231 void link_after(ListNode<ElementType> *frontNode, 232 ListNode<ElementType> *newNode); 233 234 /** 235 * @return Iterator from the beginning of the linked list. 236 */ begin()237 Iterator begin() { 238 return mSentinelNode.next; 239 } 240 241 /** 242 * @return Iterator from the end of the linked list. 243 */ end()244 Iterator end() { 245 return &mSentinelNode; 246 } 247 }; 248 249 } // namespace chre 250 251 #include "chre/util/intrusive_list_impl.h" // IWYU pragma: export 252 253 #endif // CHRE_UTIL_INTRUSIVE_LIST_H_ 254