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