1230557Sjimharris/*-
2230557Sjimharris * This file is provided under a dual BSD/GPLv2 license.  When using or
3230557Sjimharris * redistributing this file, you may do so under either license.
4230557Sjimharris *
5230557Sjimharris * GPL LICENSE SUMMARY
6230557Sjimharris *
7230557Sjimharris * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
8230557Sjimharris *
9230557Sjimharris * This program is free software; you can redistribute it and/or modify
10230557Sjimharris * it under the terms of version 2 of the GNU General Public License as
11230557Sjimharris * published by the Free Software Foundation.
12230557Sjimharris *
13230557Sjimharris * This program is distributed in the hope that it will be useful, but
14230557Sjimharris * WITHOUT ANY WARRANTY; without even the implied warranty of
15230557Sjimharris * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16230557Sjimharris * General Public License for more details.
17230557Sjimharris *
18230557Sjimharris * You should have received a copy of the GNU General Public License
19230557Sjimharris * along with this program; if not, write to the Free Software
20230557Sjimharris * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
21230557Sjimharris * The full GNU General Public License is included in this distribution
22230557Sjimharris * in the file called LICENSE.GPL.
23230557Sjimharris *
24230557Sjimharris * BSD LICENSE
25230557Sjimharris *
26230557Sjimharris * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
27230557Sjimharris * All rights reserved.
28230557Sjimharris *
29230557Sjimharris * Redistribution and use in source and binary forms, with or without
30230557Sjimharris * modification, are permitted provided that the following conditions
31230557Sjimharris * are met:
32230557Sjimharris *
33230557Sjimharris *   * Redistributions of source code must retain the above copyright
34230557Sjimharris *     notice, this list of conditions and the following disclaimer.
35230557Sjimharris *   * Redistributions in binary form must reproduce the above copyright
36230557Sjimharris *     notice, this list of conditions and the following disclaimer in
37230557Sjimharris *     the documentation and/or other materials provided with the
38230557Sjimharris *     distribution.
39230557Sjimharris *
40230557Sjimharris * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
41230557Sjimharris * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
42230557Sjimharris * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
43230557Sjimharris * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
44230557Sjimharris * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45230557Sjimharris * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
46230557Sjimharris * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
47230557Sjimharris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
48230557Sjimharris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
49230557Sjimharris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
50230557Sjimharris * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51230557Sjimharris *
52230557Sjimharris * $FreeBSD$
53230557Sjimharris */
54230557Sjimharris#ifndef _SCI_SIMPLE_LIST_HEADER_
55230557Sjimharris#define _SCI_SIMPLE_LIST_HEADER_
56230557Sjimharris
57230557Sjimharris/**
58230557Sjimharris * @file
59230557Sjimharris *
60230557Sjimharris * @brief This header file contains simple linked list manipulation macros.
61230557Sjimharris *        These macros differ from the SCI_FAST_LIST in that deletion of
62230557Sjimharris *        an element from the list is O(n).
63230557Sjimharris *        The reason for using this implementation over the SCI_FAST_LIST
64230557Sjimharris *        is
65230557Sjimharris *           1) space savings as there is only a single link element instead
66230557Sjimharris *              of the 2 link elements used in the SCI_FAST_LIST and
67230557Sjimharris *           2) it is possible to detach the entire list from its anchor
68230557Sjimharris *              element for processing.
69230557Sjimharris *
70230557Sjimharris * @note Do not use the SCI_SIMPLE_LIST if you need to remove elements from
71230557Sjimharris *       random locations within the list use instead the SCI_FAST_LIST.
72230557Sjimharris */
73230557Sjimharris
74230557Sjimharris
75230557Sjimharris//******************************************************************************
76230557Sjimharris//*
77230557Sjimharris//*     P U B L I C    M E T H O D S
78230557Sjimharris//*
79230557Sjimharris//******************************************************************************
80230557Sjimharris
81230557Sjimharris/**
82230557Sjimharris * Initialize the singely linked list anchor.  The other macros require the
83230557Sjimharris * list anchor to be properly initialized.
84230557Sjimharris */
85230557Sjimharris#define sci_simple_list_init(anchor) \
86230557Sjimharris{ \
87230557Sjimharris   (anchor)->list_head = NULL; \
88230557Sjimharris   (anchor)->list_tail = NULL; \
89230557Sjimharris   (anchor)->list_count = 0; \
90230557Sjimharris}
91230557Sjimharris
92230557Sjimharris/**
93230557Sjimharris * Initialze the singely linked list element. The other macros require the
94230557Sjimharris * list element to be properly initialized.
95230557Sjimharris */
96230557Sjimharris#define sci_simple_list_element_init(list_object, element) \
97230557Sjimharris{ \
98230557Sjimharris   (element)->next = NULL; \
99230557Sjimharris   (element)->object = (list_object); \
100230557Sjimharris}
101230557Sjimharris
102230557Sjimharris/**
103230557Sjimharris * See if there are any list elements on this list.
104230557Sjimharris */
105230557Sjimharris#define sci_simple_list_is_empty(anchor)  ((anchor)->list_head == NULL)
106230557Sjimharris
107230557Sjimharris/**
108230557Sjimharris * Return a pointer to the list element at the head of the list.  The list
109230557Sjimharris * element is not removed from the list.
110230557Sjimharris */
111230557Sjimharris#define sci_simple_list_get_head(anchor) ((anchor)->list_head)
112230557Sjimharris
113230557Sjimharris/**
114230557Sjimharris * Retuen a pointer to the lsit element at the tail of the list.  The list
115230557Sjimharris * element is not removed from the list.
116230557Sjimharris */
117230557Sjimharris#define sci_simple_list_get_tail(anchor) ((anchor)->list_tail)
118230557Sjimharris
119230557Sjimharris/**
120230557Sjimharris * Return the count of the number of elements in this list.
121230557Sjimharris */
122230557Sjimharris#define sci_simple_list_get_count(anchor) ((anchor)->list_count)
123230557Sjimharris
124230557Sjimharris/**
125230557Sjimharris * Return a pointer to the list element following this list element.
126230557Sjimharris * If this is the last element in the list then NULL is returned.
127230557Sjimharris */
128230557Sjimharris#define sci_simple_list_get_next(element) ((element)->next)
129230557Sjimharris
130230557Sjimharris/**
131230557Sjimharris * Return the object represented by the list element.
132230557Sjimharris */
133230557Sjimharris#define sci_simple_list_get_object(element) ((element)->object)
134230557Sjimharris
135230557Sjimharris
136230557Sjimharris//******************************************************************************
137230557Sjimharris//*
138230557Sjimharris//*     T Y P E S
139230557Sjimharris//*
140230557Sjimharris//******************************************************************************
141230557Sjimharris
142230557Sjimharris/**
143230557Sjimharris * @struct
144230557Sjimharris *
145230557Sjimharris * @brief This structure defines the list owner for singely linked list.
146230557Sjimharris */
147230557Sjimharristypedef struct SCI_SIMPLE_LIST
148230557Sjimharris{
149230557Sjimharris   struct SCI_SIMPLE_LIST_ELEMENT *list_head;
150230557Sjimharris   struct SCI_SIMPLE_LIST_ELEMENT *list_tail;
151230557Sjimharris   U32                             list_count;
152230557Sjimharris} SCI_SIMPLE_LIST_T;
153230557Sjimharris
154230557Sjimharris/**
155230557Sjimharris * @struct SCI_SIMPLE_LIST_ELEMENT
156230557Sjimharris *
157230557Sjimharris * @brief This structure defines what a singely linked list element contains.
158230557Sjimharris */
159230557Sjimharristypedef struct SCI_SIMPLE_LIST_ELEMENT
160230557Sjimharris{
161230557Sjimharris   struct SCI_SIMPLE_LIST_ELEMENT *next;
162230557Sjimharris   void                           *object;
163230557Sjimharris} SCI_SIMPLE_LIST_ELEMENT_T;
164230557Sjimharris
165230557Sjimharris/**
166230557Sjimharris * This method will insert the list element to the head of the list contained
167230557Sjimharris * by the anchor.
168230557Sjimharris *
169230557Sjimharris * @note Pushing new elements onto a list is more efficient than inserting
170230557Sjimharris *       them to the tail of the list though both are O(1) operations.
171230557Sjimharris */
172230557SjimharrisINLINE
173230557Sjimharrisstatic void sci_simple_list_insert_head(
174230557Sjimharris   SCI_SIMPLE_LIST_T * anchor,
175230557Sjimharris   SCI_SIMPLE_LIST_ELEMENT_T *element
176230557Sjimharris)
177230557Sjimharris{
178230557Sjimharris   if (anchor->list_tail == NULL)
179230557Sjimharris   {
180230557Sjimharris      anchor->list_tail = element;
181230557Sjimharris   }
182230557Sjimharris
183230557Sjimharris   element->next = anchor->list_head;
184230557Sjimharris   anchor->list_head = element;
185230557Sjimharris   anchor->list_count++;
186230557Sjimharris}
187230557Sjimharris
188230557Sjimharris/**
189230557Sjimharris * This methos will insert the list element to the tail of the list contained
190230557Sjimharris * by the anchor.
191230557Sjimharris *
192230557Sjimharris * @param[in, out] anchor this is the list into which the element is to be
193230557Sjimharris *                 inserted
194230557Sjimharris * @param[in] element this is the element which to insert into the list.
195230557Sjimharris *
196230557Sjimharris * @note Pushing new elements onto a list is more efficient than inserting
197230557Sjimharris *       them to the tail of the list though both are O(1) operations.
198230557Sjimharris */
199230557SjimharrisINLINE
200230557Sjimharrisstatic void sci_simple_list_insert_tail(
201230557Sjimharris   SCI_SIMPLE_LIST_T * anchor,
202230557Sjimharris   SCI_SIMPLE_LIST_ELEMENT_T *element
203230557Sjimharris)
204230557Sjimharris{
205230557Sjimharris   if (anchor->list_tail == NULL)
206230557Sjimharris   {
207230557Sjimharris      anchor->list_head = element;
208230557Sjimharris   }
209230557Sjimharris   else
210230557Sjimharris   {
211230557Sjimharris      anchor->list_tail->next = element;
212230557Sjimharris   }
213230557Sjimharris
214230557Sjimharris   anchor->list_tail = element;
215230557Sjimharris   anchor->list_count++;
216230557Sjimharris}
217230557Sjimharris
218230557Sjimharris/**
219230557Sjimharris * This method will remove the list element from the anchor and return the
220230557Sjimharris * object pointed to by that list element.
221230557Sjimharris *
222230557Sjimharris * @param[in, out] anchor this is the list into which the element is to be
223230557Sjimharris *                 inserted
224230557Sjimharris *
225230557Sjimharris * @return the list element at the head of the list.
226230557Sjimharris */
227230557SjimharrisINLINE
228230557Sjimharrisstatic void * sci_simple_list_remove_head(
229230557Sjimharris   SCI_SIMPLE_LIST_T * anchor
230230557Sjimharris)
231230557Sjimharris{
232230557Sjimharris   void * object = NULL;
233230557Sjimharris
234230557Sjimharris   if (anchor->list_head != NULL)
235230557Sjimharris   {
236230557Sjimharris      object = anchor->list_head->object;
237230557Sjimharris
238230557Sjimharris      anchor->list_head = anchor->list_head->next;
239230557Sjimharris
240230557Sjimharris      if (anchor->list_head == NULL)
241230557Sjimharris      {
242230557Sjimharris         anchor->list_tail = NULL;
243230557Sjimharris      }
244230557Sjimharris
245230557Sjimharris      anchor->list_count--;
246230557Sjimharris   }
247230557Sjimharris
248230557Sjimharris   return object;
249230557Sjimharris}
250230557Sjimharris
251230557Sjimharris/**
252230557Sjimharris * Move all the list elements from source anchor to the dest anchor.
253230557Sjimharris * The source anchor will have all of its elements removed making it
254230557Sjimharris * an empty list and the dest anchor will contain all of the source
255230557Sjimharris * and dest list elements.
256230557Sjimharris *
257230557Sjimharris * @param[in, out] dest_anchor this is the list into which all elements from
258230557Sjimharris *                 the source list are to be moved.
259230557Sjimharris * @param[in, out] source_anchor this is the list which is to be moved to the
260230557Sjimharris *                 destination list.  This list will be empty on return.
261230557Sjimharris *
262230557Sjimharris * @return the list element at the head of the list.
263230557Sjimharris * @note If the destination has list elements use the insert at head
264230557Sjimharris *       or tail routines instead.
265230557Sjimharris */
266230557SjimharrisINLINE
267230557Sjimharrisstatic void sci_simple_list_move_list(
268230557Sjimharris   SCI_SIMPLE_LIST_T * dest_anchor,
269230557Sjimharris   SCI_SIMPLE_LIST_T * source_anchor
270230557Sjimharris)
271230557Sjimharris{
272230557Sjimharris   *dest_anchor = *source_anchor;
273230557Sjimharris
274230557Sjimharris   sci_simple_list_init(source_anchor);
275230557Sjimharris}
276230557Sjimharris
277230557Sjimharris/**
278230557Sjimharris * This method will insert the list elements from the source anchor to the
279230557Sjimharris * destination list before all previous elements on the destination list.
280230557Sjimharris *
281230557Sjimharris * @param[in, out] dest_anchor this is the list into which all elements from
282230557Sjimharris *                 the source list are to be moved. The destination list will
283230557Sjimharris *                 now contain both sets of list elements.
284230557Sjimharris * @param[in, out] source_anchor this is the list which is to be moved to the
285230557Sjimharris *                 destination list.  This list will be empty on return.
286230557Sjimharris */
287230557SjimharrisINLINE
288230557Sjimharrisstatic void sci_simple_list_insert_list_at_head(
289230557Sjimharris   SCI_SIMPLE_LIST_T * dest_anchor,
290230557Sjimharris   SCI_SIMPLE_LIST_T * source_anchor
291230557Sjimharris)
292230557Sjimharris{
293230557Sjimharris   if (!sci_simple_list_is_empty(source_anchor))
294230557Sjimharris   {
295230557Sjimharris      if (sci_simple_list_is_empty(dest_anchor))
296230557Sjimharris      {
297230557Sjimharris         // Destination is empty just copy the source on over
298230557Sjimharris         *dest_anchor = *source_anchor;
299230557Sjimharris      }
300230557Sjimharris      else
301230557Sjimharris      {
302230557Sjimharris         source_anchor->list_tail->next = dest_anchor->list_head;
303230557Sjimharris         dest_anchor->list_head = source_anchor->list_head;
304230557Sjimharris         dest_anchor->list_count += source_anchor->list_count;
305230557Sjimharris      }
306230557Sjimharris
307230557Sjimharris      // Wipe the source list to make sure the list elements can not be accessed
308230557Sjimharris      // from two seperate lists at the same time.
309230557Sjimharris      sci_simple_list_init(source_anchor);
310230557Sjimharris   }
311230557Sjimharris}
312230557Sjimharris
313230557Sjimharris/**
314230557Sjimharris * This method will insert the list elements from the source anchor to the
315230557Sjimharris * destination anchor after all list elements on the destination anchor.
316230557Sjimharris *
317230557Sjimharris * @param[in, out] dest_anchor this is the list into which all elements from
318230557Sjimharris *                 the source list are to be moved. The destination list will
319230557Sjimharris *                 contain both the source and destination list elements.
320230557Sjimharris * @param[in, out] source_anchor this is the list which is to be moved to the
321230557Sjimharris *                 destination list.  This list will be empty on return.
322230557Sjimharris */
323230557SjimharrisINLINE
324230557Sjimharrisstatic void sci_simple_list_insert_list_at_tail(
325230557Sjimharris   SCI_SIMPLE_LIST_T * dest_anchor,
326230557Sjimharris   SCI_SIMPLE_LIST_T * source_anchor
327230557Sjimharris)
328230557Sjimharris{
329230557Sjimharris   if (!sci_simple_list_is_empty(source_anchor))
330230557Sjimharris   {
331230557Sjimharris      if (sci_simple_list_is_empty(dest_anchor))
332230557Sjimharris      {
333230557Sjimharris         // Destination is empty just copy the source on over
334230557Sjimharris         *dest_anchor = *source_anchor;
335230557Sjimharris      }
336230557Sjimharris      else
337230557Sjimharris      {
338230557Sjimharris         // If the source list is empty the desination list is the result.
339230557Sjimharris         dest_anchor->list_tail->next = source_anchor->list_head;
340230557Sjimharris         dest_anchor->list_tail = source_anchor->list_tail;
341230557Sjimharris         dest_anchor->list_count += source_anchor->list_count;
342230557Sjimharris      }
343230557Sjimharris
344230557Sjimharris      // Wipe the source list to make sure the list elements can not be accessed
345230557Sjimharris      // from two seperate lists at the same time.
346230557Sjimharris      sci_simple_list_init(source_anchor);
347230557Sjimharris   }
348230557Sjimharris}
349230557Sjimharris
350230557Sjimharris#endif // _SCI_SIMPLE_LIST_HEADER_
351