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