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
compare_private_data(const void * a,const void * b)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
compare_private_data_ignore_case(const void * a,const void * b)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
BStringList(int32 count)36 BStringList::BStringList(int32 count)
37 :
38 fStrings(count)
39 {
40 }
41
42
BStringList(const BStringList & other)43 BStringList::BStringList(const BStringList& other)
44 :
45 fStrings(other.fStrings)
46 {
47 _IncrementRefCounts();
48 }
49
50
~BStringList()51 BStringList::~BStringList()
52 {
53 _DecrementRefCounts();
54 }
55
56
57 bool
Add(const BString & _string,int32 index)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
Add(const BString & _string)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
Add(const BStringList & list,int32 index)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
Add(const BStringList & list)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
Remove(const BString & string,bool ignoreCase)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
Remove(const BStringList & list,bool ignoreCase)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
Remove(int32 index)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
Remove(int32 index,int32 count)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
Replace(int32 index,const BString & string)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
MakeEmpty()200 BStringList::MakeEmpty()
201 {
202 _DecrementRefCounts();
203 fStrings.MakeEmpty();
204 }
205
206
207 void
Sort(bool ignoreCase)208 BStringList::Sort(bool ignoreCase)
209 {
210 fStrings.SortItems(ignoreCase
211 ? compare_private_data_ignore_case : compare_private_data);
212 }
213
214
215 bool
Swap(int32 indexA,int32 indexB)216 BStringList::Swap(int32 indexA, int32 indexB)
217 {
218 return fStrings.SwapItems(indexA, indexB);
219 }
220
221
222 bool
Move(int32 fromIndex,int32 toIndex)223 BStringList::Move(int32 fromIndex, int32 toIndex)
224 {
225 return fStrings.MoveItem(fromIndex, toIndex);
226 }
227
228
229 BString
StringAt(int32 index) const230 BStringList::StringAt(int32 index) const
231 {
232 return BString::Private::StringFromData((char*)fStrings.ItemAt(index));
233 }
234
235
236 BString
First() const237 BStringList::First() const
238 {
239 return BString::Private::StringFromData((char*)fStrings.FirstItem());
240 }
241
242
243 BString
Last() const244 BStringList::Last() const
245 {
246 return BString::Private::StringFromData((char*)fStrings.LastItem());
247 }
248
249
250 int32
IndexOf(const BString & string,bool ignoreCase) const251 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
CountStrings() const275 BStringList::CountStrings() const
276 {
277 return fStrings.CountItems();
278 }
279
280
281 bool
IsEmpty() const282 BStringList::IsEmpty() const
283 {
284 return fStrings.IsEmpty();
285 }
286
287
288 BString
Join(const char * separator,int32 length) const289 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
DoForEach(bool (* func)(const BString & string))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
DoForEach(bool (* func)(const BString & string,void * arg2),void * arg2)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&
operator =(const BStringList & other)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
operator ==(const BStringList & other) const331 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
IsFixedSize() const350 BStringList::IsFixedSize() const
351 {
352 return false;
353 }
354
355
356 type_code
TypeCode() const357 BStringList::TypeCode() const
358 {
359 return B_STRING_LIST_TYPE;
360 }
361
362
363
364 bool
AllowsTypeCode(type_code code) const365 BStringList::AllowsTypeCode(type_code code) const
366 {
367 return code == B_STRING_LIST_TYPE;
368 }
369
370
371 ssize_t
FlattenedSize() const372 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
Flatten(void * buf,ssize_t size) const384 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
Unflatten(type_code code,const void * buffer,ssize_t size)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
_IncrementRefCounts() const430 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
_DecrementRefCounts() const440 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
_Join(const char * separator,int32 length) const449 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