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
15typedef struct UListNode UListNode;
16struct 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
26struct UList {
27 UListNode *curr;
28 UListNode *head;
29 UListNode *tail;
30
31 int32_t size;
32};
33
34static void ulist_addFirstItem(UList *list, UListNode *newItem);
35
36U_CAPI UList *U_EXPORT2 ulist_createEmptyList(UErrorCode *status) {
37 UList *newList = nullptr;
38
39 if (U_FAILURE(*status)) {
40 return nullptr;
41 }
42
43 newList = (UList *)uprv_malloc(sizeof(UList));
44 if (newList == nullptr) {
45 *status = U_MEMORY_ALLOCATION_ERROR;
46 return nullptr;
47 }
48
49 newList->curr = nullptr;
50 newList->head = nullptr;
51 newList->tail = nullptr;
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 */
61static void ulist_addFirstItem(UList *list, UListNode *newItem) {
62 newItem->next = nullptr;
63 newItem->previous = nullptr;
64 list->head = newItem;
65 list->tail = newItem;
66}
67
68static void ulist_removeItem(UList *list, UListNode *p) {
69 if (p->previous == nullptr) {
70 // p is the list head.
71 list->head = p->next;
72 } else {
73 p->previous->next = p->next;
74 }
75 if (p->next == nullptr) {
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
91U_CAPI void U_EXPORT2 ulist_addItemEndList(UList *list, const void *data, UBool forceDelete, UErrorCode *status) {
92 UListNode *newItem = nullptr;
93
94 if (U_FAILURE(*status) || list == nullptr || data == nullptr) {
95 if (forceDelete) {
96 uprv_free((void *)data);
97 }
98 return;
99 }
100
101 newItem = (UListNode *)uprv_malloc(sizeof(UListNode));
102 if (newItem == nullptr) {
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 = nullptr;
116 newItem->previous = list->tail;
117 list->tail->next = newItem;
118 list->tail = newItem;
119 }
120
121 list->size++;
122}
123
124U_CAPI void U_EXPORT2 ulist_addItemBeginList(UList *list, const void *data, UBool forceDelete, UErrorCode *status) {
125 UListNode *newItem = nullptr;
126
127 if (U_FAILURE(*status) || list == nullptr || data == nullptr) {
128 if (forceDelete) {
129 uprv_free((void *)data);
130 }
131 return;
132 }
133
134 newItem = (UListNode *)uprv_malloc(sizeof(UListNode));
135 if (newItem == nullptr) {
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 = nullptr;
149 newItem->next = list->head;
150 list->head->previous = newItem;
151 list->head = newItem;
152 }
153
154 list->size++;
155}
156
157U_CAPI UBool U_EXPORT2 ulist_containsString(const UList *list, const char *data, int32_t length) {
158 if (list != nullptr) {
159 const UListNode *pointer;
160 for (pointer = list->head; pointer != nullptr; 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
171U_CAPI UBool U_EXPORT2 ulist_removeString(UList *list, const char *data) {
172 if (list != nullptr) {
173 UListNode *pointer;
174 for (pointer = list->head; pointer != nullptr; 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
185U_CAPI void *U_EXPORT2 ulist_getNext(UList *list) {
186 UListNode *curr = nullptr;
187
188 if (list == nullptr || list->curr == nullptr) {
189 return nullptr;
190 }
191
192 curr = list->curr;
193 list->curr = curr->next;
194
195 return curr->data;
196}
197
198U_CAPI int32_t U_EXPORT2 ulist_getListSize(const UList *list) {
199 if (list != nullptr) {
200 return list->size;
201 }
202
203 return -1;
204}
205
206U_CAPI void U_EXPORT2 ulist_resetList(UList *list) {
207 if (list != nullptr) {
208 list->curr = list->head;
209 }
210}
211
212U_CAPI void U_EXPORT2 ulist_deleteList(UList *list) {
213 UListNode *listHead = nullptr;
214
215 if (list != nullptr) {
216 listHead = list->head;
217 while (listHead != nullptr) {
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 = nullptr;
229 }
230}
231
232U_CAPI void U_EXPORT2 ulist_close_keyword_values_iterator(UEnumeration *en) {
233 if (en != nullptr) {
234 ulist_deleteList((UList *)(en->context));
235 uprv_free(en);
236 }
237}
238
239U_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
247U_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 nullptr;
251 }
252
253 s = (const char *)ulist_getNext((UList *)(en->context));
254 if (s != nullptr && resultLength != nullptr) {
255 *resultLength = static_cast<int32_t>(uprv_strlen(s));
256 }
257 return s;
258}
259
260U_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
268U_CAPI UList * U_EXPORT2 ulist_getListFromEnum(UEnumeration *en) {
269 return (UList *)(en->context);
270}
271