1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef ds_SinglyLinkedList_h
8 #define ds_SinglyLinkedList_h
10 #include "mozilla/Assertions.h"
17 * Circular singly linked list that requires only one word per element and for
20 * Requires T has field |T::next| for the link pointer.
23 class SinglyLinkedList
{
28 static_assert(std::is_same_v
<decltype(T::next
), T
*>,
29 "SinglyLinkedList requires T has a next field of type T*");
30 MOZ_ASSERT(isEmpty());
33 SinglyLinkedList(T
* first
, T
* last
) : last_(last
) {
34 MOZ_ASSERT(!last_
->next
);
38 // It's not possible for elements to be present in more than one list, so copy
39 // operations are not provided.
40 SinglyLinkedList(const SinglyLinkedList
& other
) = delete;
41 SinglyLinkedList
& operator=(const SinglyLinkedList
& other
) = delete;
43 SinglyLinkedList(SinglyLinkedList
&& other
) {
44 std::swap(last_
, other
.last_
);
45 MOZ_ASSERT(other
.isEmpty());
47 SinglyLinkedList
& operator=(SinglyLinkedList
&& other
) {
48 MOZ_ASSERT(isEmpty());
49 return *new (this) SinglyLinkedList(std::move(other
));
52 ~SinglyLinkedList() { MOZ_ASSERT(isEmpty()); }
54 bool isEmpty() const { return !last_
; }
56 // These return nullptr if the list is empty.
61 T
* element
= last_
->next
;
65 T
* last() const { return last_
; }
68 MOZ_ASSERT(!isEmpty());
70 T
* element
= last_
->next
;
72 if (element
== last_
) {
75 last_
->next
= element
->next
;
78 element
->next
= nullptr;
81 // popBack cannot be implemented in constant time for a singly linked list.
83 void pushFront(T
* element
) {
84 MOZ_ASSERT(!element
->next
);
86 element
->next
= element
;
91 element
->next
= last_
->next
;
92 last_
->next
= element
;
94 void pushBack(T
* element
) {
98 void moveFrontToBack() {
99 MOZ_ASSERT(!isEmpty());
103 void append(SinglyLinkedList
&& other
) {
104 if (other
.isEmpty()) {
109 new (this) SinglyLinkedList(std::move(other
));
113 T
* firstElement
= first();
114 last()->next
= other
.first();
115 other
.last()->next
= firstElement
;
116 last_
= other
.last();
117 other
.last_
= nullptr;
120 // template <typename T>
126 explicit Iterator(const SinglyLinkedList
& list
)
127 : i(list
.first()), last(list
.last()) {}
128 bool done() const { return !i
; }
131 i
= i
== last
? nullptr : i
->next
;
138 T
& operator*() const { return *get(); }
139 T
* operator->() const { return get(); }
142 Iterator
iter() const { return Iterator(*this); }
144 // Extracts a non-circular linked list and clears this object.
151 MOZ_ASSERT(last_
->next
);
152 last_
->next
= nullptr;
160 #endif /* ds_SinglyLinkedList_h */