1 // Copyright (C) 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 ******************************************************************************
5 * Copyright (C) 2009-2016, International Business Machines
6 * Corporation and others. All Rights Reserved.
7 ******************************************************************************
8 */
9
10 #include "ulist.h"
11 #include "cmemory.h"
12 #include "cstring.h"
13 #include "uenumimp.h"
14
15 typedef struct UListNode UListNode;
16 struct UListNode {
17 void *data;
18
19 UListNode *next;
20 UListNode *previous;
21
22 /* When data is created with uprv_malloc, needs to be freed during deleteList function. */
23 UBool forceDelete;
24 };
25
26 struct UList {
27 UListNode *curr;
28 UListNode *head;
29 UListNode *tail;
30
31 int32_t size;
32 int32_t currentIndex;
33 };
34
35 static void ulist_addFirstItem(UList *list, UListNode *newItem);
36
ulist_createEmptyList(UErrorCode * status)37 U_CAPI UList *U_EXPORT2 ulist_createEmptyList(UErrorCode *status) {
38 UList *newList = NULL;
39
40 if (U_FAILURE(*status)) {
41 return NULL;
42 }
43
44 newList = (UList *)uprv_malloc(sizeof(UList));
45 if (newList == NULL) {
46 *status = U_MEMORY_ALLOCATION_ERROR;
47 return NULL;
48 }
49
50 newList->curr = NULL;
51 newList->head = NULL;
52 newList->tail = NULL;
53 newList->size = 0;
54 newList->currentIndex = -1;
55
56 return newList;
57 }
58
59 /*
60 * Function called by addItemEndList or addItemBeginList when the first item is added to the list.
61 * This function properly sets the pointers for the first item added.
62 */
ulist_addFirstItem(UList * list,UListNode * newItem)63 static void ulist_addFirstItem(UList *list, UListNode *newItem) {
64 newItem->next = NULL;
65 newItem->previous = NULL;
66 list->head = newItem;
67 list->tail = newItem;
68 }
69
ulist_removeItem(UList * list,UListNode * p)70 static void ulist_removeItem(UList *list, UListNode *p) {
71 if (p->previous == NULL) {
72 // p is the list head.
73 list->head = p->next;
74 } else {
75 p->previous->next = p->next;
76 }
77 if (p->next == NULL) {
78 // p is the list tail.
79 list->tail = p->previous;
80 } else {
81 p->next->previous = p->previous;
82 }
83 list->curr = NULL;
84 list->currentIndex = 0;
85 --list->size;
86 if (p->forceDelete) {
87 uprv_free(p->data);
88 }
89 uprv_free(p);
90 }
91
ulist_addItemEndList(UList * list,const void * data,UBool forceDelete,UErrorCode * status)92 U_CAPI void U_EXPORT2 ulist_addItemEndList(UList *list, const void *data, UBool forceDelete, UErrorCode *status) {
93 UListNode *newItem = NULL;
94
95 if (U_FAILURE(*status) || list == NULL || data == NULL) {
96 if (forceDelete) {
97 uprv_free((void *)data);
98 }
99 return;
100 }
101
102 newItem = (UListNode *)uprv_malloc(sizeof(UListNode));
103 if (newItem == NULL) {
104 if (forceDelete) {
105 uprv_free((void *)data);
106 }
107 *status = U_MEMORY_ALLOCATION_ERROR;
108 return;
109 }
110 newItem->data = (void *)(data);
111 newItem->forceDelete = forceDelete;
112
113 if (list->size == 0) {
114 ulist_addFirstItem(list, newItem);
115 } else {
116 newItem->next = NULL;
117 newItem->previous = list->tail;
118 list->tail->next = newItem;
119 list->tail = newItem;
120 }
121
122 list->size++;
123 }
124
ulist_addItemBeginList(UList * list,const void * data,UBool forceDelete,UErrorCode * status)125 U_CAPI void U_EXPORT2 ulist_addItemBeginList(UList *list, const void *data, UBool forceDelete, UErrorCode *status) {
126 UListNode *newItem = NULL;
127
128 if (U_FAILURE(*status) || list == NULL || data == NULL) {
129 if (forceDelete) {
130 uprv_free((void *)data);
131 }
132 return;
133 }
134
135 newItem = (UListNode *)uprv_malloc(sizeof(UListNode));
136 if (newItem == NULL) {
137 if (forceDelete) {
138 uprv_free((void *)data);
139 }
140 *status = U_MEMORY_ALLOCATION_ERROR;
141 return;
142 }
143 newItem->data = (void *)(data);
144 newItem->forceDelete = forceDelete;
145
146 if (list->size == 0) {
147 ulist_addFirstItem(list, newItem);
148 } else {
149 newItem->previous = NULL;
150 newItem->next = list->head;
151 list->head->previous = newItem;
152 list->head = newItem;
153 list->currentIndex++;
154 }
155
156 list->size++;
157 }
158
ulist_containsString(const UList * list,const char * data,int32_t length)159 U_CAPI UBool U_EXPORT2 ulist_containsString(const UList *list, const char *data, int32_t length) {
160 if (list != NULL) {
161 const UListNode *pointer;
162 for (pointer = list->head; pointer != NULL; pointer = pointer->next) {
163 if (length == uprv_strlen(pointer->data)) {
164 if (uprv_memcmp(data, pointer->data, length) == 0) {
165 return TRUE;
166 }
167 }
168 }
169 }
170 return FALSE;
171 }
172
ulist_removeString(UList * list,const char * data)173 U_CAPI UBool U_EXPORT2 ulist_removeString(UList *list, const char *data) {
174 if (list != NULL) {
175 UListNode *pointer;
176 for (pointer = list->head; pointer != NULL; pointer = pointer->next) {
177 if (uprv_strcmp(data, pointer->data) == 0) {
178 ulist_removeItem(list, pointer);
179 // Remove only the first occurrence, like Java LinkedList.remove(Object).
180 return TRUE;
181 }
182 }
183 }
184 return FALSE;
185 }
186
ulist_getNext(UList * list)187 U_CAPI void *U_EXPORT2 ulist_getNext(UList *list) {
188 UListNode *curr = NULL;
189
190 if (list == NULL || list->curr == NULL) {
191 return NULL;
192 }
193
194 curr = list->curr;
195 list->curr = curr->next;
196 list->currentIndex++;
197
198 return curr->data;
199 }
200
ulist_getListSize(const UList * list)201 U_CAPI int32_t U_EXPORT2 ulist_getListSize(const UList *list) {
202 if (list != NULL) {
203 return list->size;
204 }
205
206 return -1;
207 }
208
ulist_resetList(UList * list)209 U_CAPI void U_EXPORT2 ulist_resetList(UList *list) {
210 if (list != NULL) {
211 list->curr = list->head;
212 list->currentIndex = 0;
213 }
214 }
215
ulist_deleteList(UList * list)216 U_CAPI void U_EXPORT2 ulist_deleteList(UList *list) {
217 UListNode *listHead = NULL;
218
219 if (list != NULL) {
220 listHead = list->head;
221 while (listHead != NULL) {
222 UListNode *listPointer = listHead->next;
223
224 if (listHead->forceDelete) {
225 uprv_free(listHead->data);
226 }
227
228 uprv_free(listHead);
229 listHead = listPointer;
230 }
231 uprv_free(list);
232 list = NULL;
233 }
234 }
235
ulist_close_keyword_values_iterator(UEnumeration * en)236 U_CAPI void U_EXPORT2 ulist_close_keyword_values_iterator(UEnumeration *en) {
237 if (en != NULL) {
238 ulist_deleteList((UList *)(en->context));
239 uprv_free(en);
240 }
241 }
242
ulist_count_keyword_values(UEnumeration * en,UErrorCode * status)243 U_CAPI int32_t U_EXPORT2 ulist_count_keyword_values(UEnumeration *en, UErrorCode *status) {
244 if (U_FAILURE(*status)) {
245 return -1;
246 }
247
248 return ulist_getListSize((UList *)(en->context));
249 }
250
ulist_next_keyword_value(UEnumeration * en,int32_t * resultLength,UErrorCode * status)251 U_CAPI const char * U_EXPORT2 ulist_next_keyword_value(UEnumeration *en, int32_t *resultLength, UErrorCode *status) {
252 const char *s;
253 if (U_FAILURE(*status)) {
254 return NULL;
255 }
256
257 s = (const char *)ulist_getNext((UList *)(en->context));
258 if (s != NULL && resultLength != NULL) {
259 *resultLength = uprv_strlen(s);
260 }
261 return s;
262 }
263
ulist_reset_keyword_values_iterator(UEnumeration * en,UErrorCode * status)264 U_CAPI void U_EXPORT2 ulist_reset_keyword_values_iterator(UEnumeration *en, UErrorCode *status) {
265 if (U_FAILURE(*status)) {
266 return ;
267 }
268
269 ulist_resetList((UList *)(en->context));
270 }
271
ulist_getListFromEnum(UEnumeration * en)272 U_CAPI UList * U_EXPORT2 ulist_getListFromEnum(UEnumeration *en) {
273 return (UList *)(en->context);
274 }
275
276