1 | /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ |
2 | // vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4: |
3 | #ident "$Id$" |
4 | /*====== |
5 | This file is part of PerconaFT. |
6 | |
7 | |
8 | Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved. |
9 | |
10 | PerconaFT is free software: you can redistribute it and/or modify |
11 | it under the terms of the GNU General Public License, version 2, |
12 | as published by the Free Software Foundation. |
13 | |
14 | PerconaFT is distributed in the hope that it will be useful, |
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | GNU General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU General Public License |
20 | along with PerconaFT. If not, see <http://www.gnu.org/licenses/>. |
21 | |
22 | ---------------------------------------- |
23 | |
24 | PerconaFT is free software: you can redistribute it and/or modify |
25 | it under the terms of the GNU Affero General Public License, version 3, |
26 | as published by the Free Software Foundation. |
27 | |
28 | PerconaFT is distributed in the hope that it will be useful, |
29 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
30 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
31 | GNU Affero General Public License for more details. |
32 | |
33 | You should have received a copy of the GNU Affero General Public License |
34 | along with PerconaFT. If not, see <http://www.gnu.org/licenses/>. |
35 | ======= */ |
36 | |
37 | #ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved." |
38 | |
39 | #pragma once |
40 | |
41 | //****************************************************************************** |
42 | // |
43 | // Overview: A doubly linked list with elements of type T. |
44 | // Each element that wants to be put into the list provides a |
45 | // LinkedListElement<T> as well as a pointer to the the object of type T. |
46 | // Typically, the user embeds the linked list element into the object itself, |
47 | // for example as |
48 | // struct foo { |
49 | // toku::LinkedListElement<struct foo *> linked_list_elt; |
50 | // ... other elements of foo |
51 | // }; |
52 | // then when inserting foo into a list defined as |
53 | // toku::DoublyLinkedList<struct foo *> list_of_foos; |
54 | // you write |
55 | // struct foo f; |
56 | // list_of_foos->insert(&f->linked_list_elt, &f); |
57 | // |
58 | // Operations: Constructor and deconstructors are provided (they don't |
59 | // need to anything but fill in a field) for the DoublyLinkedList. |
60 | // Operations to insert an element and remove it, as well as to pop |
61 | // an element out of the list. |
62 | // Also a LinkedListElement class is provided with a method to get a |
63 | // pointer to the object of type T. |
64 | //****************************************************************************** |
65 | |
66 | #include <stdbool.h> |
67 | #include <portability/toku_assert.h> |
68 | |
69 | namespace toku { |
70 | |
71 | template<typename T> class DoublyLinkedList; |
72 | |
73 | template<typename T> class LinkedListElement { |
74 | friend class DoublyLinkedList<T>; |
75 | private: |
76 | T container; |
77 | LinkedListElement<T> *prev, *next; |
78 | public: |
79 | T get_container(void) { |
80 | return container; |
81 | } |
82 | }; |
83 | |
84 | template<typename T> class DoublyLinkedList { |
85 | public: |
86 | void init (void); |
87 | // Effect: Initialize a doubly linked list (to be empty). |
88 | |
89 | void insert(LinkedListElement<T> *ll_elt, T container); |
90 | // Effect: Add an item to a linked list. |
91 | // Implementation note: Push the item to the head of the list. |
92 | |
93 | void remove(LinkedListElement<T> *ll_elt); |
94 | // Effect: Remove an item from a linked list. |
95 | // Requires: The item is in the list identified by head. |
96 | |
97 | bool pop(LinkedListElement<T> **ll_eltp); |
98 | // Effect: if the list is empty, return false. |
99 | // Otherwise return true and set *ll_eltp to the first item, and remove that item from the list. |
100 | |
101 | template<typename extra_t> int iterate(int (*fun)(T container, extra_t ), extra_t ); |
102 | // Effect: Call fun(e, extra) on every element of the linked list. If ever fun returns nonzero, then quit early and return that value. |
103 | // If fun always return zero, then this function returns zero. |
104 | |
105 | private: |
106 | LinkedListElement<T> *m_first; |
107 | }; |
108 | |
109 | //****************************************************************************** |
110 | // DoublyLinkedList implementation starts here. |
111 | //****************************************************************************** |
112 | |
113 | #include <stddef.h> |
114 | |
115 | |
116 | |
117 | template<typename T> void DoublyLinkedList<T>::init(void) { |
118 | m_first = NULL; |
119 | } |
120 | |
121 | template<typename T> void DoublyLinkedList<T>::insert(LinkedListElement<T> *ll_elt, T container) { |
122 | LinkedListElement<T> *old_first = m_first; |
123 | ll_elt->container = container; |
124 | ll_elt->next = old_first; |
125 | ll_elt->prev = NULL; |
126 | if (old_first!=NULL) { |
127 | old_first->prev = ll_elt; |
128 | } |
129 | m_first = ll_elt; |
130 | } |
131 | |
132 | template<typename T> void DoublyLinkedList<T>::remove(LinkedListElement<T> *ll_elt) { |
133 | LinkedListElement<T> *old_prev = ll_elt->prev; |
134 | LinkedListElement<T> *old_next = ll_elt->next; |
135 | |
136 | if (old_prev==NULL) { |
137 | m_first = old_next; |
138 | } else { |
139 | old_prev->next = old_next; |
140 | } |
141 | if (old_next==NULL) { |
142 | /* nothing */ |
143 | } else { |
144 | old_next->prev = old_prev; |
145 | } |
146 | } |
147 | |
148 | template<typename T> bool DoublyLinkedList<T>::pop(LinkedListElement<T> **ll_eltp) { |
149 | LinkedListElement<T> *first = m_first; |
150 | if (first) { |
151 | invariant(first->prev==NULL); |
152 | m_first = first->next; |
153 | if (first->next) { |
154 | first->next->prev = NULL; |
155 | } |
156 | first->next=NULL; |
157 | *ll_eltp = first; |
158 | return true; |
159 | } else { |
160 | return false; |
161 | } |
162 | } |
163 | |
164 | template<typename T> |
165 | template<typename extra_t> |
166 | int DoublyLinkedList<T>::iterate(int (*fun)(T container, extra_t ), extra_t ) { |
167 | for (LinkedListElement<T> *le = m_first; le; le=le->next) { |
168 | int r = fun(le->container, extra); |
169 | if (r!=0) return r; |
170 | } |
171 | return 0; |
172 | } |
173 | |
174 | } |
175 | |