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