1 /* 2 ** Copyright 2003-2004, Stefano Ceccherini (burton666@libero.it). All rights reserved. 3 ** 2004, Michael Pfeiffer (laplace@users.sourceforge.net). 4 ** Distributed under the terms of the Haiku License. 5 ** 6 ** History 7 ** 2003-2004 Initial implementation by Stefano Ceccerini. 8 ** 2004/08/03 Testing, bug fixing and implementation of quick sort, refactoring 9 ** by Michael Pfeiffer. 10 */ 11 12 // TODO: 13 // - Rewrite to use STL 14 // - Include ObjectList.h 15 // - Test if building with jam works 16 17 // Note: Method Owning() is inlined in header file ObjectList.h 18 19 #include <stl.h> 20 21 #include <assert.h> 22 #include <List.h> 23 24 // If USE_STL is 1 binary search and sort are used from STL. 25 // The implementation of _PointerList_ should be completely rewritten to 26 // use STL in a more efficent way! 27 #define USE_STL 1 28 29 // Declaration of class _PointerList_ is inlined to be independent of the 30 // header file ObjectList.h 31 32 #ifndef __OBJECT_LIST__ 33 class _PointerList_ : public BList { 34 public: 35 _PointerList_(const _PointerList_ &list); 36 _PointerList_(int32 itemsPerBlock = 20, bool owning = false); 37 ~_PointerList_(); 38 39 typedef void *(* GenericEachFunction)(void *item, void *arg); 40 typedef int (* GenericCompareFunction)(const void *key, const void *item); 41 typedef int (* GenericCompareFunctionWithState)(const void *key, const void *item, 42 void *state); 43 typedef int (* UnaryPredicateGlue)(const void *item, void *key); 44 45 void *EachElement(GenericEachFunction, void *arg); 46 void SortItems(GenericCompareFunction); 47 void SortItems(GenericCompareFunctionWithState, void *state); 48 void HSortItems(GenericCompareFunction); 49 void HSortItems(GenericCompareFunctionWithState, void *state); 50 51 void *BinarySearch(const void *key, GenericCompareFunction) const; 52 void *BinarySearch(const void *key, GenericCompareFunctionWithState, void *state) const; 53 54 int32 BinarySearchIndex(const void *key, GenericCompareFunction) const; 55 int32 BinarySearchIndex(const void *key, GenericCompareFunctionWithState, void *state) const; 56 int32 BinarySearchIndexByPredicate(const void *arg, UnaryPredicateGlue) const; 57 58 bool Owning() const; 59 bool ReplaceItem(int32, void *); 60 61 protected: 62 bool owning; 63 64 }; 65 #endif 66 67 struct comparator; 68 69 class AbstractPointerListHelper { 70 public: 71 AbstractPointerListHelper() {}; 72 73 /** 74 Returns the index of the item that matches key or 75 a negative number. Then -(index+1) is the insert position 76 of the item not in list. 77 */ 78 int32 BinarySearchIndex(const void *key, const BList *list); 79 /** 80 Returns the item that matches key or NULL if the item could 81 not be found in the list. 82 */ 83 void* BinarySearch(const void *key, const BList *list); 84 /** 85 Sorts the items in list. 86 */ 87 void SortItems(BList *list); 88 /** 89 Removes the first item in list and appends it at the bottom of 90 the list and sorts all items but the last item. 91 */ 92 void HSortItems(BList *list); 93 94 #if USE_STL 95 friend struct comparator; 96 #endif 97 98 private: 99 enum { 100 // Use insertion sort if number of elements in list is less than 101 // kQuickSortThreshold. 102 kQuickSortThreshold = 11, 103 // Use simple pivot element computation if number of elements in 104 // list is less than kPivotThreshold. 105 kPivotThreshold = 5, 106 }; 107 108 // Methods that do the actual work: 109 inline void Swap(void **items, int32 i, int32 j); 110 111 void* BinarySearch(const void *key, const void **items, int32 numItems, int32 &index); 112 #if !USE_STL 113 void InsertionSort(void **items, int32 numItems); 114 inline void InsertionSort(void **items, int32 low, int32 high); 115 int32 ChoosePivot(void **items, int32 low, int32 high); 116 int32 Partition(void **items, int32 low, int32 high, bool &isSorted); 117 #endif 118 void QuickSort(void **items, int32 low, int32 high); 119 120 // Method to be implemented by sub classes 121 int virtual Compare(const void *key, const void* item) = 0; 122 }; 123 124 #if USE_STL 125 struct comparator : public binary_function<const void*, const void*, bool> 126 { 127 comparator(AbstractPointerListHelper* helper) : helper(helper) {} 128 129 bool operator()(const void* a, const void* b) { 130 return helper->Compare(b, a) > 0; 131 } 132 133 AbstractPointerListHelper* helper; 134 }; 135 #endif 136 137 void 138 AbstractPointerListHelper::Swap(void **items, int32 i, int32 j) 139 { 140 void *swap = items[i]; 141 items[i] = items[j]; 142 items[j] = swap; 143 } 144 145 146 int32 147 AbstractPointerListHelper::BinarySearchIndex(const void *key, const BList *list) 148 { 149 int32 index; 150 const void **items = static_cast<const void**>(list->Items()); 151 BinarySearch(key, items, list->CountItems(), index); 152 return index; 153 } 154 155 156 void * 157 AbstractPointerListHelper::BinarySearch(const void *key, const BList *list) 158 { 159 int32 index; 160 const void **items = static_cast<const void**>(list->Items()); 161 return BinarySearch(key, items, list->CountItems(), index); 162 } 163 164 165 void 166 AbstractPointerListHelper::SortItems(BList *list) 167 { 168 void **items = static_cast<void**>(list->Items()); 169 QuickSort(items, 0, list->CountItems()-1); 170 } 171 172 173 void 174 AbstractPointerListHelper::HSortItems(BList *list) 175 { 176 void **items = static_cast<void**>(list->Items()); 177 int32 numItems = list->CountItems(); 178 if (numItems > 1) { 179 // swap last with first item 180 Swap(items, 0, numItems-1); 181 } 182 // sort all items but last item 183 QuickSort(items, 0, numItems-2); 184 } 185 186 187 void * 188 AbstractPointerListHelper::BinarySearch(const void *key, const void **items, int32 numItems, int32 &index) 189 { 190 #if USE_STL 191 const void** end = &items[numItems]; 192 const void** found = lower_bound(items, end, key, comparator(this)); 193 index = found - items; 194 if (index != numItems && Compare(key, *found) == 0) { 195 return const_cast<void*>(*found); 196 } else { 197 index = -(index + 1); 198 return NULL; 199 } 200 #else 201 int32 low = 0; 202 int32 high = numItems-1; 203 int result = 0; 204 index = 0; 205 206 while (low <= high) { 207 index = (low + high) / 2; 208 const void *item = items[index]; 209 result = Compare(key, item); 210 if (result < 0) { 211 // key < item 212 high = index - 1; 213 } else if (result > 0) { 214 // key > item 215 low = index + 1; 216 } else { 217 // key == item 218 return const_cast<void *>(item); 219 } 220 } 221 // item not found 222 if (result > 0) { 223 // key > last item (= items[index]) 224 // insert position for key is after last item 225 index ++; 226 } 227 228 index = -(index+1); 229 return NULL; 230 #endif 231 } 232 233 #if !USE_STL 234 int32 235 AbstractPointerListHelper::ChoosePivot(void **items, int32 low, int32 high) 236 { 237 if (kPivotThreshold <= kQuickSortThreshold 238 || high - low > kPivotThreshold) { 239 assert(high - low > kPivotThreshold); 240 // choose the middle item of three items 241 int32 mid = (low + high) / 2; 242 243 void* first = items[low]; 244 void* middle = items[mid]; 245 void* last = items[high]; 246 247 if (Compare(first, middle) <= 0) { 248 // first <= middle 249 if (Compare(middle, last) <= 0) { 250 // first <= middle <= last 251 return mid; 252 } 253 // first <= middle and last < middle 254 if (Compare(first, last) <= 0) { 255 // first <= last < middle 256 return high; 257 } 258 // last < first <= middle 259 return low; 260 } 261 // middle < first 262 if (Compare(first, last) <= 0) { 263 // middle < first <= last 264 return low; 265 } 266 // middle < first and last < first 267 if (Compare(middle, last) <= 0) { 268 // middle <= last < first 269 return high; 270 } 271 // last < middle < first 272 return mid; 273 } else { 274 // choose the middle element to avoid O(n^2) for an already sorted list 275 return (low + high) / 2; 276 } 277 } 278 279 280 int32 281 AbstractPointerListHelper::Partition(void **items, int32 low, int32 high, bool &isSorted) 282 { 283 assert(low < high); 284 int32 left = low; 285 int32 right = high; 286 int32 pivot = ChoosePivot(items, low, high); 287 void *pivotItem = items[pivot]; 288 289 // Optimization: Check if all items are equal. We get this almost for free. 290 // Searching the first item that does not belong to the left list has to 291 // be done anyway. 292 int32 result; 293 isSorted = true; 294 // Search first item in left part that does not belong to this part 295 // (where item > pivotItem) 296 while (left < right && (result = Compare(items[left], pivotItem)) <= 0) { 297 left ++; 298 if (result != 0) { 299 isSorted = false; 300 break; 301 } 302 } 303 if (isSorted && left == right && Compare(items[right], pivotItem) == 0) { 304 return low; 305 } 306 // End of optimization 307 isSorted = false; 308 309 // pivot element has to be first element in list 310 if (low != pivot) 311 Swap(items, low, pivot); 312 313 // now partion the array in a left part where item <= pivotItem 314 // and a right part where item > pivotItem 315 do { 316 // search first item in left part that does not belong to this part 317 // (where item > pivotItem) 318 while (left < right && Compare(items[left], pivotItem) <= 0) { 319 left ++; 320 } 321 // search first item (from right to left) in right part that does not belong 322 // to this part (where item <= pivotItem). This holds at least for pivot 323 // element at top of list! No array bounds check needed! 324 while (Compare(items[right], pivotItem) > 0) { 325 right --; 326 } 327 if (left < right) { 328 // now swap the items to the proper part 329 Swap(items, left, right); 330 } 331 } while (left < right); 332 // place pivotItem between left and right part 333 items[low] = items[right]; 334 items[right] = pivotItem; 335 return right; 336 } 337 338 339 void 340 AbstractPointerListHelper::InsertionSort(void **items, int32 numItems) 341 { 342 for (int32 i = 1; i < numItems; i ++) { 343 // treat list[0 .. i-1] as sorted 344 void* item = items[i]; 345 // insert item at right place in list[0..i] 346 int32 j = i; 347 void* prev = items[j-1]; 348 while (Compare(prev, item) > 0) { 349 items[j] = prev; 350 j --; 351 if (j <= 0) break; 352 prev = items[j-1]; 353 } 354 items[j] = item; 355 } 356 } 357 358 359 void 360 AbstractPointerListHelper::InsertionSort(void **items, int32 low, int32 high) 361 { 362 InsertionSort(&items[low], high - low + 1); 363 } 364 #endif 365 366 void 367 AbstractPointerListHelper::QuickSort(void **items, int32 low, int32 high) 368 { 369 #if USE_STL 370 if (low <= high) { 371 sort(&items[low], &items[high+1], comparator(this)); 372 } 373 #else 374 if (low < high) { 375 if (high - low < kQuickSortThreshold) { 376 InsertionSort(items, low, high); 377 } else { 378 bool isSorted; 379 int pivot = Partition(items, low, high, isSorted); 380 if (isSorted) return; 381 382 QuickSort(items, low, pivot - 1); 383 QuickSort(items, pivot + 1, high); 384 } 385 } 386 #endif 387 } 388 389 390 class PointerListHelper : public AbstractPointerListHelper { 391 public: 392 PointerListHelper(_PointerList_::GenericCompareFunction compareFunc) 393 : fCompareFunc(compareFunc) 394 { 395 // nothing to do 396 } 397 398 int Compare(const void *a, const void *b) 399 { 400 return fCompareFunc(a, b); 401 } 402 403 private: 404 _PointerList_::GenericCompareFunction fCompareFunc; 405 }; 406 407 408 class PointerListHelperWithState : public AbstractPointerListHelper 409 { 410 public: 411 PointerListHelperWithState( 412 _PointerList_::GenericCompareFunctionWithState compareFunc, 413 void* state) 414 : fCompareFunc(compareFunc) 415 , fState(state) 416 { 417 // nothing to do 418 } 419 420 int Compare(const void *a, const void *b) 421 { 422 return fCompareFunc(a, b, fState); 423 } 424 425 private: 426 _PointerList_::GenericCompareFunctionWithState fCompareFunc; 427 void* fState; 428 }; 429 430 431 class PointerListHelperUsePredicate : public AbstractPointerListHelper 432 { 433 public: 434 PointerListHelperUsePredicate( 435 _PointerList_::UnaryPredicateGlue predicate) 436 : fPredicate(predicate) 437 { 438 // nothing to do 439 } 440 441 int Compare(const void *arg, const void *item) 442 { 443 // need to adapt arguments and return value 444 return -fPredicate(item, const_cast<void *>(arg)); 445 } 446 447 private: 448 _PointerList_::UnaryPredicateGlue fPredicate; 449 }; 450 451 452 // Implementation of class _PointerList_ 453 454 _PointerList_::_PointerList_(int32 itemsPerBlock, bool own) 455 : 456 BList(itemsPerBlock), 457 owning(own) 458 { 459 460 } 461 462 463 _PointerList_::_PointerList_(const _PointerList_ &list) 464 : 465 BList(list), 466 owning(list.owning) 467 { 468 } 469 470 471 _PointerList_::~_PointerList_() 472 { 473 // This is empty by design, the "owning" variable 474 // is used by the BObjectList subclass 475 } 476 477 478 // Note: function pointers must not be NULL!!! 479 480 void * 481 _PointerList_::EachElement(GenericEachFunction function, void *arg) 482 { 483 int32 numItems = CountItems(); 484 void *result = NULL; 485 486 for (int32 index = 0; index < numItems; index++) { 487 result = function(ItemAtFast(index), arg); 488 if (result != NULL) 489 break; 490 } 491 492 return result; 493 } 494 495 496 void 497 _PointerList_::SortItems(GenericCompareFunction compareFunc) 498 { 499 PointerListHelper helper(compareFunc); 500 helper.SortItems(this); 501 } 502 503 504 void 505 _PointerList_::SortItems(GenericCompareFunctionWithState compareFunc, void *state) 506 { 507 PointerListHelperWithState helper(compareFunc, state); 508 helper.SortItems(this); 509 } 510 511 512 void 513 _PointerList_::HSortItems(GenericCompareFunction compareFunc) 514 { 515 PointerListHelper helper(compareFunc); 516 helper.HSortItems(this); 517 } 518 519 520 void 521 _PointerList_::HSortItems(GenericCompareFunctionWithState compareFunc, void *state) 522 { 523 PointerListHelperWithState helper(compareFunc, state); 524 helper.HSortItems(this); 525 } 526 527 528 void * 529 _PointerList_::BinarySearch(const void *key, GenericCompareFunction compareFunc) const 530 { 531 PointerListHelper helper(compareFunc); 532 return helper.BinarySearch(key, this); 533 } 534 535 536 void * 537 _PointerList_::BinarySearch(const void *key, 538 GenericCompareFunctionWithState compareFunc, void *state) const 539 { 540 PointerListHelperWithState helper(compareFunc, state); 541 return helper.BinarySearch(key, this); 542 } 543 544 545 int32 546 _PointerList_::BinarySearchIndex(const void *key, GenericCompareFunction compareFunc) const 547 { 548 PointerListHelper helper(compareFunc); 549 return helper.BinarySearchIndex(key, this); 550 } 551 552 553 int32 554 _PointerList_::BinarySearchIndex(const void *key, 555 GenericCompareFunctionWithState compareFunc, void *state) const 556 { 557 PointerListHelperWithState helper(compareFunc, state); 558 return helper.BinarySearchIndex(key, this); 559 } 560 561 562 int32 563 _PointerList_::BinarySearchIndexByPredicate(const void *key, UnaryPredicateGlue predicate) const 564 { 565 PointerListHelperUsePredicate helper(predicate); 566 return helper.BinarySearchIndex(key, this); 567 } 568 569 bool 570 _PointerList_::ReplaceItem(int32 index, void *newItem) 571 { 572 if (index < 0 || index >= CountItems()) 573 return false; 574 575 void **items = static_cast<void **>(Items()); 576 items[index] = newItem; 577 578 return true; 579 } 580 581