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