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