xref: /haiku/src/kits/support/StringList.cpp (revision 6f80a9801fedbe7355c4360bd204ba746ec3ec2d)
1 /*
2  * Copyright 2011-2013, 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 	BString string(_string);
61 		// makes sure the string is shareable
62 	if (string.Length() != _string.Length())
63 		return false;
64 
65 	char* privateData = BString::Private(string).Data();
66 	if (!fStrings.AddItem(privateData, index))
67 		return false;
68 
69 	BString::Private::IncrementDataRefCount(privateData);
70 	return true;
71 }
72 
73 
74 bool
75 BStringList::Add(const BString& _string)
76 {
77 	BString string(_string);
78 		// makes sure the string is shareable
79 	if (string.Length() != _string.Length())
80 		return false;
81 
82 	char* privateData = BString::Private(string).Data();
83 	if (!fStrings.AddItem(privateData))
84 		return false;
85 
86 	BString::Private::IncrementDataRefCount(privateData);
87 	return true;
88 }
89 
90 
91 bool
92 BStringList::Add(const BStringList& list, int32 index)
93 {
94 	if (!fStrings.AddList(&list.fStrings, index))
95 		return false;
96 
97 	list._IncrementRefCounts();
98 	return true;
99 }
100 
101 
102 bool
103 BStringList::Add(const BStringList& list)
104 {
105 	if (!fStrings.AddList(&list.fStrings))
106 		return false;
107 
108 	list._IncrementRefCounts();
109 	return true;
110 }
111 
112 
113 bool
114 BStringList::Remove(const BString& string, bool ignoreCase)
115 {
116 	bool result = false;
117 	int32 count = fStrings.CountItems();
118 
119 	if (ignoreCase) {
120 		int32 length = string.Length();
121 
122 		for (int32 i = count - 1; i >= 0; i--) {
123 			BString element(StringAt(i));
124 			if (length == element.Length() && string.ICompare(element) == 0) {
125 				Remove(i);
126 				result = true;
127 			}
128 		}
129 	} else {
130 		for (int32 i = count - 1; i >= 0; i--) {
131 			if (string == StringAt(i)) {
132 				Remove(i);
133 				result = true;
134 			}
135 		}
136 	}
137 
138 	return result;
139 }
140 
141 
142 bool
143 BStringList::Remove(const BStringList& list, bool ignoreCase)
144 {
145 	bool removedAnything = false;
146 	int32 stringCount = list.CountStrings();
147 	for (int32 i = 0; i < stringCount; i++)
148 		removedAnything |= Remove(list.StringAt(i), ignoreCase);
149 
150 	return removedAnything;
151 }
152 
153 
154 BString
155 BStringList::Remove(int32 index)
156 {
157 	if (index < 0 || index >= fStrings.CountItems())
158 		return BString();
159 
160 	char* privateData = (char*)fStrings.RemoveItem(index);
161 	BString string(BString::Private::StringFromData(privateData));
162 	BString::Private::DecrementDataRefCount(privateData);
163 	return string;
164 }
165 
166 
167 bool
168 BStringList::Remove(int32 index, int32 count)
169 {
170 	int32 stringCount = fStrings.CountItems();
171 	if (index < 0 || index > stringCount)
172 		return false;
173 
174 	int32 end = index + std::min(stringCount - index, count);
175 	for (int32 i = index; i < end; i++)
176 		BString::Private::DecrementDataRefCount((char*)fStrings.ItemAt(i));
177 
178 	fStrings.RemoveItems(index, end - index);
179 	return true;
180 }
181 
182 
183 bool
184 BStringList::Replace(int32 index, const BString& string)
185 {
186 	if (index < 0 || index >= fStrings.CountItems())
187 		return false;
188 
189 	BString::Private::DecrementDataRefCount((char*)fStrings.ItemAt(index));
190 
191 	char* privateData = BString::Private(string).Data();
192 	BString::Private::IncrementDataRefCount(privateData);
193 	fStrings.ReplaceItem(index, privateData);
194 
195 	return true;
196 }
197 
198 
199 void
200 BStringList::MakeEmpty()
201 {
202 	_DecrementRefCounts();
203 	fStrings.MakeEmpty();
204 }
205 
206 
207 void
208 BStringList::Sort(bool ignoreCase)
209 {
210 	fStrings.SortItems(ignoreCase
211 		? compare_private_data_ignore_case : compare_private_data);
212 }
213 
214 
215 bool
216 BStringList::Swap(int32 indexA, int32 indexB)
217 {
218 	return fStrings.SwapItems(indexA, indexB);
219 }
220 
221 
222 bool
223 BStringList::Move(int32 fromIndex, int32 toIndex)
224 {
225 	return fStrings.MoveItem(fromIndex, toIndex);
226 }
227 
228 
229 BString
230 BStringList::StringAt(int32 index) const
231 {
232 	return BString::Private::StringFromData((char*)fStrings.ItemAt(index));
233 }
234 
235 
236 BString
237 BStringList::First() const
238 {
239 	return BString::Private::StringFromData((char*)fStrings.FirstItem());
240 }
241 
242 
243 BString
244 BStringList::Last() const
245 {
246 	return BString::Private::StringFromData((char*)fStrings.LastItem());
247 }
248 
249 
250 int32
251 BStringList::IndexOf(const BString& string, bool ignoreCase) const
252 {
253 	int32 count = fStrings.CountItems();
254 
255 	if (ignoreCase) {
256 		int32 length = string.Length();
257 
258 		for (int32 i = 0; i < count; i++) {
259 			BString element(StringAt(i));
260 			if (length == element.Length() && string.ICompare(element) == 0)
261 				return i;
262 		}
263 	} else {
264 		for (int32 i = 0; i < count; i++) {
265 			if (string == StringAt(i))
266 				return i;
267 		}
268 	}
269 
270 	return -1;
271 }
272 
273 
274 int32
275 BStringList::CountStrings() const
276 {
277 	return fStrings.CountItems();
278 }
279 
280 
281 bool
282 BStringList::IsEmpty() const
283 {
284 	return fStrings.IsEmpty();
285 }
286 
287 
288 BString
289 BStringList::Join(const char* separator, int32 length) const
290 {
291 	return _Join(separator,
292 		length >= 0 ? strnlen(separator, length) : strlen(separator));
293 }
294 
295 
296 void
297 BStringList::DoForEach(bool (*func)(const BString& string))
298 {
299 	bool terminate = false;
300 	int32 count = fStrings.CountItems();
301 	for (int32 i = 0; i < count && !terminate; i++)
302 		terminate = func(StringAt(i));
303 }
304 
305 
306 void
307 BStringList::DoForEach(bool (*func)(const BString& string, void* arg2),
308 	void* arg2)
309 {
310 	bool terminate = false;
311 	int32 count = fStrings.CountItems();
312 	for (int32 i = 0; i < count && !terminate; i++)
313 		terminate = func(StringAt(i), arg2);
314 }
315 
316 
317 BStringList&
318 BStringList::operator=(const BStringList& other)
319 {
320 	if (this != &other) {
321 		_DecrementRefCounts();
322 		fStrings = other.fStrings;
323 		_IncrementRefCounts();
324 	}
325 
326 	return *this;
327 }
328 
329 
330 bool
331 BStringList::operator==(const BStringList& other) const
332 {
333 	if (this == &other)
334 		return true;
335 
336 	int32 count = fStrings.CountItems();
337 	if (count != other.fStrings.CountItems())
338 		return false;
339 
340 	for (int32 i = 0; i < count; i++) {
341 		if (StringAt(i) != other.StringAt(i))
342 			return false;
343 	}
344 
345 	return true;
346 }
347 
348 
349 bool
350 BStringList::IsFixedSize() const
351 {
352 	return false;
353 }
354 
355 
356 type_code
357 BStringList::TypeCode() const
358 {
359 	return B_STRING_LIST_TYPE;
360 }
361 
362 
363 
364 bool
365 BStringList::AllowsTypeCode(type_code code) const
366 {
367 	return code == B_STRING_LIST_TYPE;
368 }
369 
370 
371 ssize_t
372 BStringList::FlattenedSize() const
373 {
374 	ssize_t size = 0;
375 	int32 count = CountStrings();
376 	for (int32 i = 0; i < count; i++)
377 		size += StringAt(i).Length() + 1;
378 
379 	return size;
380 }
381 
382 
383 status_t
384 BStringList::Flatten(void* buf, ssize_t size) const
385 {
386 	const char* buffer = (const char*)buf;
387 
388 	if (size < FlattenedSize())
389 		return B_NO_MEMORY;
390 
391 	int32 count = CountStrings();
392 	for (int32 i = 0; i < count; i++) {
393 		BString item = StringAt(i);
394 		ssize_t storeSize = item.Length() + 1;
395 		memcpy((void*)buffer, (const void*)item.String(), storeSize);
396 		buffer += storeSize;
397 	}
398 
399 	return B_OK;
400 }
401 
402 
403 status_t
404 BStringList::Unflatten(type_code code, const void* buffer, ssize_t size)
405 {
406 	if (code != B_STRING_LIST_TYPE)
407 		return B_ERROR;
408 	const char* bufferStart = (const char*)buffer;
409 
410 	MakeEmpty();
411 
412 	off_t offset = 0;
413 	while (offset < size) {
414 		const char* string = bufferStart + offset;
415 		size_t restSize = size - offset;
416 		size_t read = strnlen(string, restSize);
417 		if (read == restSize)
418 			return B_BAD_VALUE;
419 
420 		if (!Add(string))
421 			return B_NO_MEMORY;
422 		offset += read + 1;
423 	}
424 
425 	return B_OK;
426 }
427 
428 
429 void
430 BStringList::_IncrementRefCounts() const
431 {
432 	int32 count = fStrings.CountItems();
433 	for (int32 i = 0; i < count; i++) {
434 		BString::Private::IncrementDataRefCount((char*)fStrings.ItemAt(i));
435 	}
436 }
437 
438 
439 void
440 BStringList::_DecrementRefCounts() const
441 {
442 	int32 count = fStrings.CountItems();
443 	for (int32 i = 0; i < count; i++)
444 		BString::Private::DecrementDataRefCount((char*)fStrings.ItemAt(i));
445 }
446 
447 
448 BString
449 BStringList::_Join(const char* separator, int32 length) const
450 {
451 	// handle simple cases (0 or 1 element)
452 	int32 count = CountStrings();
453 	if (count == 0)
454 		return BString();
455 	if (count == 1)
456 		return StringAt(0);
457 
458 	// determine the total length
459 	int32 totalLength = length * (count - 1);
460 	for (int32 i = 0; i < count; i++)
461 		totalLength += StringAt(i).Length();
462 
463 	// compose the result string
464 	BString result;
465 	char* buffer = result.LockBuffer(totalLength);
466 	if (buffer == NULL)
467 		return result;
468 
469 	for (int32 i = 0; i < count; i++) {
470 		if (i > 0 && length > 0) {
471 			memcpy(buffer, separator, length);
472 			buffer += length;
473 		}
474 
475 		BString string = StringAt(i);
476 		memcpy(buffer, string.String(), string.Length());
477 		buffer += string.Length();
478 	}
479 
480 	return result.UnlockBuffer(totalLength);
481 }
482