xref: /aosp_15_r20/system/chre/util/include/chre/util/intrusive_list.h (revision 84e339476a462649f82315436d70fd732297a399)
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