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
17static int
18compare_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
25static int
26compare_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
36BStringList::BStringList(int32 count)
37	:
38	fStrings(count)
39{
40}
41
42
43BStringList::BStringList(const BStringList& other)
44	:
45	fStrings(other.fStrings)
46{
47	_IncrementRefCounts();
48}
49
50
51BStringList::~BStringList()
52{
53	_DecrementRefCounts();
54}
55
56
57bool
58BStringList::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
69bool
70BStringList::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
81bool
82BStringList::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
92bool
93BStringList::Add(const BStringList& list)
94{
95	if (!fStrings.AddList(&list.fStrings))
96		return false;
97
98	list._IncrementRefCounts();
99	return true;
100}
101
102
103bool
104BStringList::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
132bool
133BStringList::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
144BString
145BStringList::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
157bool
158BStringList::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
173bool
174BStringList::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
189void
190BStringList::MakeEmpty()
191{
192	_DecrementRefCounts();
193	fStrings.MakeEmpty();
194}
195
196
197void
198BStringList::Sort(bool ignoreCase)
199{
200	fStrings.SortItems(ignoreCase
201		? compare_private_data_ignore_case : compare_private_data);
202}
203
204
205bool
206BStringList::Swap(int32 indexA, int32 indexB)
207{
208	return fStrings.SwapItems(indexA, indexB);
209}
210
211
212bool
213BStringList::Move(int32 fromIndex, int32 toIndex)
214{
215	return fStrings.MoveItem(fromIndex, toIndex);
216}
217
218
219BString
220BStringList::StringAt(int32 index) const
221{
222	return BString::Private::StringFromData((char*)fStrings.ItemAt(index));
223}
224
225
226BString
227BStringList::First() const
228{
229	return BString::Private::StringFromData((char*)fStrings.FirstItem());
230}
231
232
233BString
234BStringList::Last() const
235{
236	return BString::Private::StringFromData((char*)fStrings.LastItem());
237}
238
239
240int32
241BStringList::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
264int32
265BStringList::CountStrings() const
266{
267	return fStrings.CountItems();
268}
269
270
271bool
272BStringList::IsEmpty() const
273{
274	return fStrings.IsEmpty();
275}
276
277
278void
279BStringList::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
287void
288BStringList::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
297BStringList&
298BStringList::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
310bool
311BStringList::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
329bool
330BStringList::IsFixedSize() const
331{
332	return false;
333}
334
335
336type_code
337BStringList::TypeCode() const
338{
339	return B_STRING_LIST_TYPE;
340}
341
342
343
344bool
345BStringList::AllowsTypeCode(type_code code) const
346{
347	return code == B_STRING_LIST_TYPE;
348}
349
350
351ssize_t
352BStringList::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
363status_t
364BStringList::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
383status_t
384BStringList::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
409void
410BStringList::_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
419void
420BStringList::_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