1 /*---------------------------------------------------------------------------*
2 * linklist_impl.c *
3 * *
4 * Copyright 2007, 2008 Nuance Communciations, Inc. *
5 * *
6 * Licensed under the Apache License, Version 2.0 (the 'License'); *
7 * you may not use this file except in compliance with the License. *
8 * *
9 * You may obtain a copy of the License at *
10 * http://www.apache.org/licenses/LICENSE-2.0 *
11 * *
12 * Unless required by applicable law or agreed to in writing, software *
13 * distributed under the License is distributed on an 'AS IS' BASIS, *
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
15 * See the License for the specific language governing permissions and *
16 * limitations under the License. *
17 * *
18 *---------------------------------------------------------------------------*/
19
20
21
22 #include <stdlib.h>
23
24 #include "pmemory.h"
25 #include "plog.h"
26
27 #include "linklist.h"
28
29 extern void *lts_alloc(int num, int size);
30
31
32 /* very simple static memory allocation:
33 1. pool of linked list nodes - from static allocated array
34 2. each node is marked "used" when allocated; marked "unused" when deallocated
35 3. since the stress linked lists deal with single words, an array will suffice.
36 */
37
38 #ifdef USE_STATIC_SLTS
39 #define NUM_ALLOC_NODES 30 /* Max 30 syllables per word */
40
41 typedef struct LNodeAllocElement
42 {
43 LNode node;
44 short usedflag;
45 } LNodeAllocElement;
46
47 static LNodeAllocElement g_LNodeAllocArray[NUM_ALLOC_NODES];
48
ClearLNodeArray()49 void ClearLNodeArray()
50 {
51 int i;
52 LNode *n;
53
54 for(i=0; i<NUM_ALLOC_NODES; i++){
55 g_LNodeAllocArray[i].usedflag = 0;
56 n = &(g_LNodeAllocArray[i].node);
57 n->data = 0;
58 n->next = n->prev = 0;
59 }
60 }
61
AllocNode()62 static LNode *AllocNode()
63 {
64 int i;
65
66 /* return first unused element */
67 for(i=0; i<NUM_ALLOC_NODES; i++){
68 if(g_LNodeAllocArray[i].usedflag == 0){
69 g_LNodeAllocArray[i].usedflag = 1;
70
71 /* zero out the node first*/
72 (g_LNodeAllocArray[i].node).data = NULL;
73 (g_LNodeAllocArray[i].node).prev = NULL;
74 (g_LNodeAllocArray[i].node).next = NULL;
75
76 return &(g_LNodeAllocArray[i].node);
77 }
78 }
79 /* ran out of nodes */
80 return NULL;
81 }
82
FreeNode(LNode * n)83 static void FreeNode(LNode *n)
84 {
85 int i;
86 long addr;
87
88 /* compare addresses of pointers */
89 for(i=0; i<NUM_ALLOC_NODES; i++){
90 addr = (long) (&(g_LNodeAllocArray[i].node));
91 if(addr == (long)n){
92 g_LNodeAllocArray[i].usedflag = 0;
93 return;
94 }
95 }
96
97 /* not found. don't do anything */
98 return;
99 }
100
101
102 #else /* !USE_STATIC_SLTS */
103
AllocNode()104 static LNode *AllocNode()
105 {
106 return (LNode *)lts_alloc(1, sizeof(LNode));
107 }
FreeNode(LNode * n)108 static void FreeNode(LNode *n)
109 {
110 FREE(n);
111 }
112
113 #endif
114
115
116
117 /* Inserts after current element
118 At return, current element will be point to newly created node
119
120 handle static allocation later - possibly using a pool of nodes?
121 For now, dynamically allocate a new list node with the data
122 */
Insert(LList * list,void * data)123 LListResult Insert(LList *list, void *data)
124 {
125 LNode *newnode = AllocNode();
126 if(newnode == NULL){
127 return LListResourceAllocError;
128 }
129 newnode->data = data;
130
131 if(list->head == NULL){
132 /* if list is empty, assign to head */
133 list->head = newnode;
134 (list->head)->next = NULL;
135 (list->head)->prev = NULL;
136
137 /* update curr to newly inserted node */
138 list->curr = list->head;
139 list->tail = list->head;
140 return LListSuccess;
141 }
142
143 /* curr not specified, insert from the end */
144 if(list->curr == NULL){
145 list->curr = list->tail;
146 }
147
148 /* in cases with single node, default to insert at end */
149 if(list->curr == list->tail){
150 /* insert at the end */
151 newnode->prev = list->curr;
152 newnode->next = NULL;
153 (list->curr)->next = newnode;
154
155 /* update both curr and end */
156 list->curr = newnode;
157 list->tail = newnode;
158 return LListSuccess;
159
160 }else if(list->curr == list->head){
161 /* insert at head */
162 newnode->next = list->head;
163 newnode->prev = NULL;
164 (list->head)->prev = newnode;
165
166 /* update curr to newly inserted node */
167 list->curr = list->head;
168 list->head = newnode;
169
170 return LListSuccess;
171
172 }else{
173 /* insert somewhere in middle */
174 newnode->prev = list->curr;
175 newnode->next = (list->curr)->next;
176 (list->curr)->next = newnode;
177 (newnode->next)->prev = newnode;
178
179 /* update curr to newly inserted node */
180 list->curr = newnode;
181 return LListSuccess;
182 }
183 }
184
185 /* Deletes at current element
186 At return, current element will point to previous node
187
188 handle static deallocation later - possibly using a pool of nodes?
189 For now, dynamically free a new list node
190 */
191
Delete(LList * list)192 LListResult Delete(LList *list)
193 {
194 LNode *curr;
195
196 if(list->head == NULL){
197 return LListEmpty;
198 }
199
200 /* start deleting from the end if curr not specified */
201 if(list->curr == NULL){
202 list->curr = list->tail;
203 }
204
205 curr = list->curr;
206
207 if(curr == list->head){
208 /* delete from the head */
209 list->head = curr->next;
210
211 if(list->head != NULL){
212 (list->head)->prev = NULL;
213 }
214
215 FreeNode(curr);
216 list->curr = list->head;
217 return LListSuccess;
218
219 }else if(curr == list->tail){
220 /* delete from the end */
221 list->tail = curr->prev;
222
223 if(list->tail != NULL){
224 (list->tail)->next = NULL;
225 }
226
227 FreeNode(curr);
228 list->curr = list->tail;
229 return LListSuccess;
230
231 }else{
232 /* delete somewhere in the middle */
233 list->curr = curr->next;
234
235 /* still check, just in case*/
236 if(curr->next != NULL){
237 (curr->next)->prev = curr->prev;
238 }
239 if(curr->prev != NULL){
240 (curr->prev)->next = curr->next;
241 }
242
243 FreeNode(curr);
244 return LListSuccess;
245 }
246 }
247
248