1 /***************************************************************************//**
2 * @file
3 * @brief Single Link List
4 *******************************************************************************
5 * # License
6 * <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
7 *******************************************************************************
8 *
9 * SPDX-License-Identifier: Zlib
10 *
11 * The licensor of this software is Silicon Laboratories Inc.
12 *
13 * This software is provided 'as-is', without any express or implied
14 * warranty. In no event will the authors be held liable for any damages
15 * arising from the use of this software.
16 *
17 * Permission is granted to anyone to use this software for any purpose,
18 * including commercial applications, and to alter it and redistribute it
19 * freely, subject to the following restrictions:
20 *
21 * 1. The origin of this software must not be misrepresented; you must not
22 * claim that you wrote the original software. If you use this software
23 * in a product, an acknowledgment in the product documentation would be
24 * appreciated but is not required.
25 * 2. Altered source versions must be plainly marked as such, and must not be
26 * misrepresented as being the original software.
27 * 3. This notice may not be removed or altered from any source distribution.
28 *
29 ******************************************************************************/
30
31 #include "sl_assert.h"
32 #include "sl_slist.h"
33 #include <stdbool.h>
34 #include <stdlib.h>
35 #include <stdint.h>
36
37 /*******************************************************************************
38 ************************** GLOBAL FUNCTIONS *******************************
39 ******************************************************************************/
40
41 /***************************************************************************//**
42 * Initializes a singly-linked list.
43 ******************************************************************************/
sl_slist_init(sl_slist_node_t ** head)44 void sl_slist_init(sl_slist_node_t **head)
45 {
46 *head = 0;
47 }
48
49 /***************************************************************************//**
50 * Add given item at beginning of list.
51 ******************************************************************************/
sl_slist_push(sl_slist_node_t ** head,sl_slist_node_t * item)52 void sl_slist_push(sl_slist_node_t **head,
53 sl_slist_node_t *item)
54 {
55 EFM_ASSERT((item != NULL) && (head != NULL));
56
57 item->node = *head;
58 *head = item;
59 }
60
61 /***************************************************************************//**
62 * Add item at end of list.
63 ******************************************************************************/
sl_slist_push_back(sl_slist_node_t ** head,sl_slist_node_t * item)64 void sl_slist_push_back(sl_slist_node_t **head,
65 sl_slist_node_t *item)
66 {
67 sl_slist_node_t **node_ptr = head;
68
69 EFM_ASSERT((item != NULL) && (head != NULL));
70
71 while (*node_ptr != NULL) {
72 node_ptr = &((*node_ptr)->node);
73 }
74
75 item->node = NULL;
76 *node_ptr = item;
77 }
78
79 /***************************************************************************//**
80 * Removes and returns first element of list.
81 ******************************************************************************/
sl_slist_pop(sl_slist_node_t ** head)82 sl_slist_node_t *sl_slist_pop(sl_slist_node_t **head)
83 {
84 sl_slist_node_t *item;
85
86 EFM_ASSERT(head != NULL);
87
88 item = *head;
89 if (item == NULL) {
90 return (NULL);
91 }
92
93 *head = item->node;
94
95 item->node = NULL;
96
97 return (item);
98 }
99
100 /***************************************************************************//**
101 * Insert item after given item.
102 ******************************************************************************/
sl_slist_insert(sl_slist_node_t * item,sl_slist_node_t * pos)103 void sl_slist_insert(sl_slist_node_t *item,
104 sl_slist_node_t *pos)
105 {
106 EFM_ASSERT((item != NULL) && (pos != NULL));
107
108 item->node = pos->node;
109 pos->node = item;
110 }
111
112 /***************************************************************************//**
113 * Remove item from list.
114 ******************************************************************************/
sl_slist_remove(sl_slist_node_t ** head,sl_slist_node_t * item)115 void sl_slist_remove(sl_slist_node_t **head,
116 sl_slist_node_t *item)
117 {
118 sl_slist_node_t **node_ptr;
119
120 EFM_ASSERT((item != NULL) && (head != NULL));
121
122 for (node_ptr = head; *node_ptr != NULL; node_ptr = &((*node_ptr)->node)) {
123 if (*node_ptr == item) {
124 *node_ptr = item->node;
125 return;
126 }
127 }
128
129 EFM_ASSERT(node_ptr != NULL);
130 }
131
132 /***************************************************************************//**
133 * Sorts list items.
134 ******************************************************************************/
sl_slist_sort(sl_slist_node_t ** head,bool (* cmp_fnct)(sl_slist_node_t * item_l,sl_slist_node_t * item_r))135 void sl_slist_sort(sl_slist_node_t **head,
136 bool (*cmp_fnct)(sl_slist_node_t *item_l,
137 sl_slist_node_t *item_r))
138 {
139 bool swapped;
140 sl_slist_node_t **pp_item_l;
141
142 EFM_ASSERT((head != NULL) && (cmp_fnct != NULL));
143
144 do {
145 swapped = false;
146
147 pp_item_l = head;
148 // Loop until end of list is found.
149 while ((*pp_item_l != NULL) && ((*pp_item_l)->node != NULL)) {
150 sl_slist_node_t *p_item_r = (*pp_item_l)->node;
151 bool ordered;
152
153 // Call provided compare fnct.
154 ordered = cmp_fnct(*pp_item_l, p_item_r);
155 if (ordered == false) {
156 // If order is not correct, swap items.
157 sl_slist_node_t *p_tmp = p_item_r->node;
158
159 // Swap the two items.
160 p_item_r->node = *pp_item_l;
161 (*pp_item_l)->node = p_tmp;
162 *pp_item_l = p_item_r;
163 pp_item_l = &(p_item_r->node);
164 // Indicate a swap has been done.
165 swapped = true;
166 } else {
167 pp_item_l = &((*pp_item_l)->node);
168 }
169 }
170 // Re-loop until no items have been swapped.
171 } while (swapped == true);
172 }
173