| 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 | |