xref: /haiku/src/kits/support/StringList.cpp (revision e5d65858f2361fe0552495b61620c84dcee6bc00)
1 /*
2  * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de
3  * Copyright 2011, Clemens Zeidler <haiku@clemens-zeidler.de>
4  *
5  * Distributed under the terms of the MIT License.
6  */
7 
8 
9 #include <StringList.h>
10 
11 #include <algorithm>
12 
13 #include <StringPrivate.h>
14 #include <TypeConstants.h>
15 
16 
17 static int
18 compare_private_data(const void* a, const void* b)
19 {
20 	return BString::Private::StringFromData(*(char**)a).Compare(
21 		BString::Private::StringFromData(*(char**)b));
22 }
23 
24 
25 static int
26 compare_private_data_ignore_case(const void* a, const void* b)
27 {
28 	return BString::Private::StringFromData(*(char**)a).ICompare(
29 		BString::Private::StringFromData(*(char**)b));
30 }
31 
32 
33 // #pragma mark - BStringList
34 
35 
36 BStringList::BStringList(int32 count)
37 	:
38 	fStrings(count)
39 {
40 }
41 
42 
43 BStringList::BStringList(const BStringList& other)
44 	:
45 	fStrings(other.fStrings)
46 {
47 	_IncrementRefCounts();
48 }
49 
50 
51 BStringList::~BStringList()
52 {
53 	_DecrementRefCounts();
54 }
55 
56 
57 bool
58 BStringList::Add(const BString& string, int32 index)
59 {
60 	char* privateData = BString::Private(string).Data();
61 	if (!fStrings.AddItem(privateData, index))
62 		return false;
63 
64 	BString::Private::IncrementDataRefCount(privateData);
65 	return true;
66 }
67 
68 
69 bool
70 BStringList::Add(const BString& string)
71 {
72 	char* privateData = BString::Private(string).Data();
73 	if (!fStrings.AddItem(privateData))
74 		return false;
75 
76 	BString::Private::IncrementDataRefCount(privateData);
77 	return true;
78 }
79 
80 
81 bool
82 BStringList::Add(const BStringList& list, int32 index)
83 {
84 	if (!fStrings.AddList(&list.fStrings, index))
85 		return false;
86 
87 	list._IncrementRefCounts();
88 	return true;
89 }
90 
91 
92 bool
93 BStringList::Add(const BStringList& list)
94 {
95 	if (!fStrings.AddList(&list.fStrings))
96 		return false;
97 
98 	list._IncrementRefCounts();
99 	return true;
100 }
101 
102 
103 bool
104 BStringList::Remove(const BString& string, bool ignoreCase)
105 {
106 	bool result = false;
107 	int32 count = fStrings.CountItems();
108 
109 	if (ignoreCase) {
110 		int32 length = string.Length();
111 
112 		for (int32 i = count - 1; i >= 0; i--) {
113 			BString element(StringAt(i));
114 			if (length == element.Length() && string.ICompare(element) == 0) {
115 				Remove(i);
116 				result = true;
117 			}
118 		}
119 	} else {
120 		for (int32 i = count - 1; i >= 0; i--) {
121 			if (string == StringAt(i)) {
122 				Remove(i);
123 				result = true;
124 			}
125 		}
126 	}
127 
128 	return result;
129 }
130 
131 
132 bool
133 BStringList::Remove(const BStringList& list, bool ignoreCase)
134 {
135 	bool removedAnything = false;
136 	int32 stringCount = list.CountStrings();
137 	for (int32 i = 0; i < stringCount; i++)
138 		removedAnything |= Remove(list.StringAt(i), ignoreCase);
139 
140 	return removedAnything;
141 }
142 
143 
144 BString
145 BStringList::Remove(int32 index)
146 {
147 	if (index < 0 || index >= fStrings.CountItems())
148 		return BString();
149 
150 	char* privateData = (char*)fStrings.RemoveItem(index);
151 	BString string(BString::Private::StringFromData(privateData));
152 	BString::Private::DecrementDataRefCount(privateData);
153 	return string;
154 }
155 
156 
157 bool
158 BStringList::Remove(int32 index, int32 count)
159 {
160 	int32 stringCount = fStrings.CountItems();
161 	if (index < 0 || index > stringCount)
162 		return false;
163 
164 	int32 end = index + std::min(stringCount - index, count);
165 	for (int32 i = index; i < end; i++)
166 		BString::Private::DecrementDataRefCount((char*)fStrings.ItemAt(i));
167 
168 	fStrings.RemoveItems(index, end - index);
169 	return true;
170 }
171 
172 
173 bool
174 BStringList::Replace(int32 index, const BString& string)
175 {
176 	if (index < 0 || index >= fStrings.CountItems())
177 		return false;
178 
179 	BString::Private::DecrementDataRefCount((char*)fStrings.ItemAt(index));
180 
181 	char* privateData = BString::Private(string).Data();
182 	BString::Private::IncrementDataRefCount(privateData);
183 	fStrings.ReplaceItem(index, privateData);
184 
185 	return true;
186 }
187 
188 
189 void
190 BStringList::MakeEmpty()
191 {
192 	_DecrementRefCounts();
193 	fStrings.MakeEmpty();
194 }
195 
196 
197 void
198 BStringList::Sort(bool ignoreCase)
199 {
200 	fStrings.SortItems(ignoreCase
201 		? compare_private_data_ignore_case : compare_private_data);
202 }
203 
204 
205 bool
206 BStringList::Swap(int32 indexA, int32 indexB)
207 {
208 	return fStrings.SwapItems(indexA, indexB);
209 }
210 
211 
212 bool
213 BStringList::Move(int32 fromIndex, int32 toIndex)
214 {
215 	return fStrings.MoveItem(fromIndex, toIndex);
216 }
217 
218 
219 BString
220 BStringList::StringAt(int32 index) const
221 {
222 	return BString::Private::StringFromData((char*)fStrings.ItemAt(index));
223 }
224 
225 
226 BString
227 BStringList::First() const
228 {
229 	return BString::Private::StringFromData((char*)fStrings.FirstItem());
230 }
231 
232 
233 BString
234 BStringList::Last() const
235 {
236 	return BString::Private::StringFromData((char*)fStrings.LastItem());
237 }
238 
239 
240 int32
241 BStringList::IndexOf(const BString& string, bool ignoreCase) const
242 {
243 	int32 count = fStrings.CountItems();
244 
245 	if (ignoreCase) {
246 		int32 length = string.Length();
247 
248 		for (int32 i = 0; i < count; i++) {
249 			BString element(StringAt(i));
250 			if (length == element.Length() && string.ICompare(element) == 0)
251 				return i;
252 		}
253 	} else {
254 		for (int32 i = 0; i < count; i++) {
255 			if (string == StringAt(i))
256 				return i;
257 		}
258 	}
259 
260 	return -1;
261 }
262 
263 
264 int32
265 BStringList::CountStrings() const
266 {
267 	return fStrings.CountItems();
268 }
269 
270 
271 bool
272 BStringList::IsEmpty() const
273 {
274 	return fStrings.IsEmpty();
275 }
276 
277 
278 void
279 BStringList::DoForEach(bool (*func)(const BString& string))
280 {
281 	int32 count = fStrings.CountItems();
282 	for (int32 i = 0; i < count; i++)
283 		func(StringAt(i));
284 }
285 
286 
287 void
288 BStringList::DoForEach(bool (*func)(const BString& string, void* arg2),
289 	void* arg2)
290 {
291 	int32 count = fStrings.CountItems();
292 	for (int32 i = 0; i < count; i++)
293 		func(StringAt(i), arg2);
294 }
295 
296 
297 BStringList&
298 BStringList::operator=(const BStringList& other)
299 {
300 	if (this != &other) {
301 		_DecrementRefCounts();
302 		fStrings = other.fStrings;
303 		_IncrementRefCounts();
304 	}
305 
306 	return *this;
307 }
308 
309 
310 bool
311 BStringList::operator==(const BStringList& other) const
312 {
313 	if (this == &other)
314 		return true;
315 
316 	int32 count = fStrings.CountItems();
317 	if (count != other.fStrings.CountItems())
318 		return false;
319 
320 	for (int32 i = 0; i < count; i++) {
321 		if (StringAt(i) != other.StringAt(i))
322 			return false;
323 	}
324 
325 	return true;
326 }
327 
328 
329 bool
330 BStringList::IsFixedSize() const
331 {
332 	return false;
333 }
334 
335 
336 type_code
337 BStringList::TypeCode() const
338 {
339 	return B_STRING_LIST_TYPE;
340 }
341 
342 
343 
344 bool
345 BStringList::AllowsTypeCode(type_code code) const
346 {
347 	return code == B_STRING_LIST_TYPE;
348 }
349 
350 
351 ssize_t
352 BStringList::FlattenedSize() const
353 {
354 	ssize_t size = 0;
355 	int32 count = CountStrings();
356 	for (int32 i = 0; i < count; i++)
357 		size += StringAt(i).Length() + 1;
358 
359 	return size;
360 }
361 
362 
363 status_t
364 BStringList::Flatten(void* buf, ssize_t size) const
365 {
366 	const char* buffer = (const char*)buf;
367 
368 	if (size < FlattenedSize())
369 		return B_NO_MEMORY;
370 
371 	int32 count = CountStrings();
372 	for (int32 i = 0; i < count; i++) {
373 		BString item = StringAt(i);
374 		ssize_t storeSize = item.Length() + 1;
375 		memcpy((void*)buffer, (const void*)item.String(), storeSize);
376 		buffer += storeSize;
377 	}
378 
379 	return B_OK;
380 }
381 
382 
383 status_t
384 BStringList::Unflatten(type_code code, const void* buffer, ssize_t size)
385 {
386 	if (code != B_STRING_LIST_TYPE)
387 		return B_ERROR;
388 	const char* bufferStart = (const char*)buffer;
389 
390 	MakeEmpty();
391 
392 	off_t offset = 0;
393 	while (offset < size) {
394 		const char* string = bufferStart + offset;
395 		size_t restSize = size - offset;
396 		size_t read = strnlen(string, restSize);
397 		if (read == restSize)
398 			return B_BAD_VALUE;
399 
400 		if (!Add(string))
401 			return B_NO_MEMORY;
402 		offset += read + 1;
403 	}
404 
405 	return B_OK;
406 }
407 
408 
409 void
410 BStringList::_IncrementRefCounts() const
411 {
412 	int32 count = fStrings.CountItems();
413 	for (int32 i = 0; i < count; i++) {
414 		BString::Private::IncrementDataRefCount((char*)fStrings.ItemAt(i));
415 	}
416 }
417 
418 
419 void
420 BStringList::_DecrementRefCounts() const
421 {
422 	int32 count = fStrings.CountItems();
423 	for (int32 i = 0; i < count; i++)
424 		BString::Private::DecrementDataRefCount((char*)fStrings.ItemAt(i));
425 }
426