1 /* 2 * Copyright 2001-2009, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * The Storage kit Team 7 * Isaac Yonemoto 8 * Rene Gollent 9 * Stephan Aßmus 10 */ 11 12 //! BList class provides storage for pointers. Not thread safe. 13 14 15 #include <List.h> 16 17 #include <stdio.h> 18 #include <stdlib.h> 19 #include <string.h> 20 21 22 // helper function 23 static inline void 24 move_items(void** items, int32 offset, int32 count) 25 { 26 if (count > 0 && offset != 0) 27 memmove(items + offset, items, count * sizeof(void*)); 28 } 29 30 31 BList::BList(int32 count) 32 : 33 fObjectList(NULL), 34 fPhysicalSize(0), 35 fItemCount(0), 36 fBlockSize(count), 37 fResizeThreshold(0) 38 { 39 if (fBlockSize <= 0) 40 fBlockSize = 1; 41 _ResizeArray(fItemCount); 42 } 43 44 45 BList::BList(const BList& anotherList) 46 : 47 fObjectList(NULL), 48 fPhysicalSize(0), 49 fItemCount(0), 50 fBlockSize(anotherList.fBlockSize) 51 { 52 *this = anotherList; 53 } 54 55 56 BList::~BList() 57 { 58 free(fObjectList); 59 } 60 61 62 BList& 63 BList::operator=(const BList& list) 64 { 65 if (&list != this) { 66 fBlockSize = list.fBlockSize; 67 if (_ResizeArray(list.fItemCount)) { 68 fItemCount = list.fItemCount; 69 memcpy(fObjectList, list.fObjectList, fItemCount * sizeof(void*)); 70 } 71 } 72 73 return *this; 74 } 75 76 77 bool 78 BList::operator==(const BList& list) const 79 { 80 if (&list == this) 81 return true; 82 83 if (list.fItemCount != fItemCount) 84 return false; 85 86 if (fItemCount > 0) { 87 return memcmp(fObjectList, list.fObjectList, 88 fItemCount * sizeof(void*)) == 0; 89 } 90 91 return true; 92 } 93 94 95 bool 96 BList::operator!=(const BList& list) const 97 { 98 return !(*this == list); 99 } 100 101 102 bool 103 BList::AddItem(void* item, int32 index) 104 { 105 if (index < 0 || index > fItemCount) 106 return false; 107 108 bool result = true; 109 110 if (fItemCount + 1 > fPhysicalSize) 111 result = _ResizeArray(fItemCount + 1); 112 if (result) { 113 ++fItemCount; 114 move_items(fObjectList + index, 1, fItemCount - index - 1); 115 fObjectList[index] = item; 116 } 117 return result; 118 } 119 120 121 bool 122 BList::AddItem(void* item) 123 { 124 bool result = true; 125 if (fPhysicalSize > fItemCount) { 126 fObjectList[fItemCount] = item; 127 ++fItemCount; 128 } else { 129 if ((result = _ResizeArray(fItemCount + 1))) { 130 fObjectList[fItemCount] = item; 131 ++fItemCount; 132 } 133 } 134 return result; 135 } 136 137 138 bool 139 BList::AddList(const BList* list, int32 index) 140 { 141 bool result = (list && index >= 0 && index <= fItemCount); 142 if (result && list->fItemCount > 0) { 143 int32 count = list->fItemCount; 144 if (fItemCount + count > fPhysicalSize) 145 result = _ResizeArray(fItemCount + count); 146 if (result) { 147 fItemCount += count; 148 move_items(fObjectList + index, count, fItemCount - index - count); 149 memcpy(fObjectList + index, list->fObjectList, 150 list->fItemCount * sizeof(void*)); 151 } 152 } 153 return result; 154 } 155 156 157 bool 158 BList::AddList(const BList* list) 159 { 160 bool result = (list != NULL); 161 if (result && list->fItemCount > 0) { 162 int32 index = fItemCount; 163 int32 count = list->fItemCount; 164 if (fItemCount + count > fPhysicalSize) 165 result = _ResizeArray(fItemCount + count); 166 if (result) { 167 fItemCount += count; 168 memcpy(fObjectList + index, list->fObjectList, 169 list->fItemCount * sizeof(void*)); 170 } 171 } 172 return result; 173 } 174 175 176 bool 177 BList::RemoveItem(void* item) 178 { 179 int32 index = IndexOf(item); 180 bool result = (index >= 0); 181 if (result) 182 RemoveItem(index); 183 return result; 184 } 185 186 187 void* 188 BList::RemoveItem(int32 index) 189 { 190 void* item = NULL; 191 if (index >= 0 && index < fItemCount) { 192 item = fObjectList[index]; 193 move_items(fObjectList + index + 1, -1, fItemCount - index - 1); 194 --fItemCount; 195 if (fItemCount <= fResizeThreshold) 196 _ResizeArray(fItemCount); 197 } 198 return item; 199 } 200 201 202 bool 203 BList::RemoveItems(int32 index, int32 count) 204 { 205 bool result = (index >= 0 && index <= fItemCount); 206 if (result) { 207 if (index + count > fItemCount) 208 count = fItemCount - index; 209 if (count > 0) { 210 move_items(fObjectList + index + count, -count, 211 fItemCount - index - count); 212 fItemCount -= count; 213 if (fItemCount <= fResizeThreshold) 214 _ResizeArray(fItemCount); 215 } else 216 result = false; 217 } 218 return result; 219 } 220 221 222 bool 223 BList::ReplaceItem(int32 index, void* newItem) 224 { 225 bool result = false; 226 227 if (index >= 0 && index < fItemCount) { 228 fObjectList[index] = newItem; 229 result = true; 230 } 231 return result; 232 } 233 234 235 void 236 BList::MakeEmpty() 237 { 238 fItemCount = 0; 239 _ResizeArray(0); 240 } 241 242 243 // #pragma mark - Reordering items. 244 245 246 void 247 BList::SortItems(int (*compareFunc)(const void*, const void*)) 248 { 249 if (compareFunc) 250 qsort(fObjectList, fItemCount, sizeof(void*), compareFunc); 251 } 252 253 254 bool 255 BList::SwapItems(int32 indexA, int32 indexB) 256 { 257 bool result = false; 258 259 if (indexA >= 0 && indexA < fItemCount 260 && indexB >= 0 && indexB < fItemCount) { 261 262 void* tmpItem = fObjectList[indexA]; 263 fObjectList[indexA] = fObjectList[indexB]; 264 fObjectList[indexB] = tmpItem; 265 266 result = true; 267 } 268 269 return result; 270 } 271 272 273 /*! This moves a list item from posititon a to position b, moving the 274 appropriate block of list elements to make up for the move. For example, 275 in the array: 276 A B C D E F G H I J 277 Moveing 1(B)->6(G) would result in this: 278 A C D E F G B H I J 279 */ 280 bool 281 BList::MoveItem(int32 fromIndex, int32 toIndex) 282 { 283 if ((fromIndex >= fItemCount) || (toIndex >= fItemCount) || (fromIndex < 0) 284 || (toIndex < 0)) { 285 return false; 286 } 287 288 void* tmpMover = fObjectList[fromIndex]; 289 if (fromIndex < toIndex) { 290 memmove(fObjectList + fromIndex, fObjectList + fromIndex + 1, 291 (toIndex - fromIndex) * sizeof(void*)); 292 } else if (fromIndex > toIndex) { 293 memmove(fObjectList + toIndex + 1, fObjectList + toIndex, 294 (fromIndex - toIndex) * sizeof(void*)); 295 }; 296 fObjectList[toIndex] = tmpMover; 297 298 return true; 299 } 300 301 302 // #pragma mark - Retrieving items. 303 304 305 void* 306 BList::ItemAt(int32 index) const 307 { 308 void *item = NULL; 309 if (index >= 0 && index < fItemCount) 310 item = fObjectList[index]; 311 return item; 312 } 313 314 315 void* 316 BList::FirstItem() const 317 { 318 void *item = NULL; 319 if (fItemCount > 0) 320 item = fObjectList[0]; 321 return item; 322 } 323 324 325 void* 326 BList::ItemAtFast(int32 index) const 327 { 328 return fObjectList[index]; 329 } 330 331 332 void* 333 BList::Items() const 334 { 335 return fObjectList; 336 } 337 338 339 void* 340 BList::LastItem() const 341 { 342 void* item = NULL; 343 if (fItemCount > 0) 344 item = fObjectList[fItemCount - 1]; 345 return item; 346 } 347 348 349 // #pragma mark - Querying the list. 350 351 352 bool 353 BList::HasItem(void* item) const 354 { 355 return (IndexOf(item) >= 0); 356 } 357 358 359 bool 360 BList::HasItem(const void* item) const 361 { 362 return (IndexOf(item) >= 0); 363 } 364 365 366 int32 367 BList::IndexOf(void* item) const 368 { 369 for (int32 i = 0; i < fItemCount; i++) { 370 if (fObjectList[i] == item) 371 return i; 372 } 373 return -1; 374 } 375 376 377 int32 378 BList::IndexOf(const void* item) const 379 { 380 for (int32 i = 0; i < fItemCount; i++) { 381 if (fObjectList[i] == item) 382 return i; 383 } 384 return -1; 385 } 386 387 388 int32 389 BList::CountItems() const 390 { 391 return fItemCount; 392 } 393 394 395 bool 396 BList::IsEmpty() const 397 { 398 return fItemCount == 0; 399 } 400 401 402 // #pragma mark - Iterating over the list. 403 404 /*! Iterate a function over the whole list. If the function outputs a true 405 value, then the process is terminated. 406 */ 407 void 408 BList::DoForEach(bool (*func)(void*)) 409 { 410 if (func == NULL) 411 return; 412 413 bool terminate = false; 414 int32 index = 0; 415 416 while ((!terminate) && (index < fItemCount)) { 417 terminate = func(fObjectList[index]); 418 index++; 419 } 420 } 421 422 423 /*! Iterate a function over the whole list. If the function outputs a true 424 value, then the process is terminated. This version takes an additional 425 argument which is passed to the function. 426 */ 427 void 428 BList::DoForEach(bool (*func)(void*, void*), void* arg) 429 { 430 if (func == NULL) 431 return; 432 433 bool terminate = false; int32 index = 0; 434 while ((!terminate) && (index < fItemCount)) { 435 terminate = func(fObjectList[index], arg); 436 index++; 437 } 438 } 439 440 441 #if (__GNUC__ == 2) 442 443 // This is somewhat of a hack for backwards compatibility - 444 // the reason these functions are defined this way rather than simply 445 // being made private members is that if they are included, then whenever 446 // gcc encounters someone calling AddList() with a non-const BList pointer, 447 // it will try to use the private version and fail with a compiler error. 448 449 // obsolete AddList(BList* list, int32 index) and AddList(BList* list) 450 // AddList 451 extern "C" bool 452 AddList__5BListP5BListl(BList* self, BList* list, int32 index) 453 { 454 return self->AddList((const BList*)list, index); 455 } 456 457 // AddList 458 extern "C" bool 459 AddList__5BListP5BList(BList* self, BList* list) 460 { 461 return self->AddList((const BList*)list); 462 } 463 #endif 464 465 // FBC 466 void BList::_ReservedList1() {} 467 void BList::_ReservedList2() {} 468 469 470 /*! Resizes fObjectList to be large enough to contain count items. 471 */ 472 bool 473 BList::_ResizeArray(int32 count) 474 { 475 bool result = true; 476 // calculate the new physical size 477 // by doubling the existing size 478 // until we can hold at least count items 479 int32 newSize = fPhysicalSize > 0 ? fPhysicalSize : fBlockSize; 480 int32 targetSize = count; 481 if (targetSize <= 0) 482 targetSize = fBlockSize; 483 if (targetSize > fPhysicalSize) { 484 while (newSize < targetSize) 485 newSize <<= 1; 486 } else if (targetSize <= fResizeThreshold) { 487 newSize = fResizeThreshold; 488 } 489 490 // resize if necessary 491 if (newSize != fPhysicalSize) { 492 void** newObjectList 493 = (void**)realloc(fObjectList, newSize * sizeof(void*)); 494 if (newObjectList) { 495 fObjectList = newObjectList; 496 fPhysicalSize = newSize; 497 // set our lower bound to either 1/4 498 //of the current physical size, or 0 499 fResizeThreshold = fPhysicalSize >> 2 >= fBlockSize 500 ? fPhysicalSize >> 2 : 0; 501 } else 502 result = false; 503 } 504 return result; 505 } 506 507