ai_abstractlist.cpp

Go to the documentation of this file.
00001 /* $Id: ai_abstractlist.cpp 17197 2009-08-15 22:06:51Z rubidium $ */
00002 
00005 #include <squirrel.h>
00006 #include "ai_abstractlist.hpp"
00007 #include "../../debug.h"
00008 #include "../../core/alloc_func.hpp"
00009 #include "../../script/squirrel.hpp"
00010 
00014 class AIAbstractListSorter {
00015 protected:
00016   AIAbstractList *list;
00017 
00018 public:
00022   virtual ~AIAbstractListSorter() { }
00023 
00027   virtual int32 Begin() = 0;
00028 
00032   virtual void End() = 0;
00033 
00037   virtual int32 Next() = 0;
00038 
00042   virtual bool HasNext() = 0;
00043 
00047   virtual void Remove(int item) = 0;
00048 };
00049 
00053 class AIAbstractListSorterValueAscending : public AIAbstractListSorter {
00054 private:
00055   AIAbstractList::AIAbstractListBucket::iterator bucket_iter;
00056   AIAbstractList::AIItemList *bucket_list;
00057   AIAbstractList::AIItemList::iterator bucket_list_iter;
00058   bool has_no_more_items;
00059   int32 item_next;
00060 
00061 public:
00062   AIAbstractListSorterValueAscending(AIAbstractList *list)
00063   {
00064     this->list = list;
00065     this->End();
00066   }
00067 
00068   int32 Begin()
00069   {
00070     if (this->list->buckets.empty()) return 0;
00071     this->has_no_more_items = false;
00072 
00073     this->bucket_iter = this->list->buckets.begin();
00074     this->bucket_list = &(*this->bucket_iter).second;
00075     this->bucket_list_iter = this->bucket_list->begin();
00076     this->item_next = *this->bucket_list_iter;
00077 
00078     int32 item_current = this->item_next;
00079     FindNext();
00080     return item_current;
00081   }
00082 
00083   void End()
00084   {
00085     this->bucket_list = NULL;
00086     this->has_no_more_items = true;
00087     this->item_next = 0;
00088   }
00089 
00090   void FindNext()
00091   {
00092     if (this->bucket_list == NULL) {
00093       this->has_no_more_items = true;
00094       return;
00095     }
00096 
00097     this->bucket_list_iter++;
00098     if (this->bucket_list_iter == this->bucket_list->end()) {
00099       this->bucket_iter++;
00100       if (this->bucket_iter == this->list->buckets.end()) {
00101         this->bucket_list = NULL;
00102         return;
00103       }
00104       this->bucket_list = &(*this->bucket_iter).second;
00105       this->bucket_list_iter = this->bucket_list->begin();
00106     }
00107     this->item_next = *this->bucket_list_iter;
00108   }
00109 
00110   int32 Next()
00111   {
00112     if (!this->HasNext()) return 0;
00113 
00114     int32 item_current = this->item_next;
00115     FindNext();
00116     return item_current;
00117   }
00118 
00119   void Remove(int item)
00120   {
00121     if (!this->HasNext()) return;
00122 
00123     /* If we remove the 'next' item, skip to the next */
00124     if (item == this->item_next) {
00125       FindNext();
00126       return;
00127     }
00128   }
00129 
00130   bool HasNext()
00131   {
00132     return !(this->list->buckets.empty() || this->has_no_more_items);
00133   }
00134 };
00135 
00139 class AIAbstractListSorterValueDescending : public AIAbstractListSorter {
00140 private:
00141   AIAbstractList::AIAbstractListBucket::iterator bucket_iter;
00142   AIAbstractList::AIItemList *bucket_list;
00143   AIAbstractList::AIItemList::iterator bucket_list_iter;
00144   bool has_no_more_items;
00145   int32 item_next;
00146 
00147 public:
00148   AIAbstractListSorterValueDescending(AIAbstractList *list)
00149   {
00150     this->list = list;
00151     this->End();
00152   }
00153 
00154   int32 Begin()
00155   {
00156     if (this->list->buckets.empty()) return 0;
00157     this->has_no_more_items = false;
00158 
00159     /* Go to the end of the bucket-list */
00160     this->bucket_iter = this->list->buckets.begin();
00161     for (size_t i = this->list->buckets.size(); i > 1; i--) this->bucket_iter++;
00162     this->bucket_list = &(*this->bucket_iter).second;
00163 
00164     /* Go to the end of the items in the bucket */
00165     this->bucket_list_iter = this->bucket_list->begin();
00166     for (size_t i = this->bucket_list->size(); i > 1; i--) this->bucket_list_iter++;
00167     this->item_next = *this->bucket_list_iter;
00168 
00169     int32 item_current = this->item_next;
00170     FindNext();
00171     return item_current;
00172   }
00173 
00174   void End() {
00175     this->bucket_list = NULL;
00176     this->has_no_more_items = true;
00177     this->item_next = 0;
00178   }
00179 
00180   void FindNext()
00181   {
00182     if (this->bucket_list == NULL) {
00183       this->has_no_more_items = true;
00184       return;
00185     }
00186 
00187     if (this->bucket_list_iter == this->bucket_list->begin()) {
00188       if (this->bucket_iter == this->list->buckets.begin()) {
00189         this->bucket_list = NULL;
00190         return;
00191       }
00192       this->bucket_iter--;
00193       this->bucket_list = &(*this->bucket_iter).second;
00194       /* Go to the end of the items in the bucket */
00195       this->bucket_list_iter = this->bucket_list->begin();
00196       for (size_t i = this->bucket_list->size(); i > 1; i--) this->bucket_list_iter++;
00197     } else {
00198       this->bucket_list_iter--;
00199     }
00200     this->item_next = *this->bucket_list_iter;
00201   }
00202 
00203   int32 Next()
00204   {
00205     if (!this->HasNext()) return 0;
00206 
00207     int32 item_current = this->item_next;
00208     FindNext();
00209     return item_current;
00210   }
00211 
00212   void Remove(int item)
00213   {
00214     if (!this->HasNext()) return;
00215 
00216     /* If we remove the 'next' item, skip to the next */
00217     if (item == this->item_next) {
00218       FindNext();
00219       return;
00220     }
00221   }
00222 
00223   bool HasNext()
00224   {
00225     return !(this->list->buckets.empty() || this->has_no_more_items);
00226   }
00227 };
00228 
00232 class AIAbstractListSorterItemAscending : public AIAbstractListSorter {
00233 private:
00234   AIAbstractList::AIAbstractListMap::iterator item_iter;
00235   bool has_no_more_items;
00236   int32 item_next;
00237 
00238 public:
00239   AIAbstractListSorterItemAscending(AIAbstractList *list)
00240   {
00241     this->list = list;
00242     this->End();
00243   }
00244 
00245   int32 Begin()
00246   {
00247     if (this->list->items.empty()) return 0;
00248     this->has_no_more_items = false;
00249 
00250     this->item_iter = this->list->items.begin();
00251     this->item_next = (*this->item_iter).first;
00252 
00253     int32 item_current = this->item_next;
00254     FindNext();
00255     return item_current;
00256   }
00257 
00258   void End()
00259   {
00260     this->has_no_more_items = true;
00261   }
00262 
00263   void FindNext()
00264   {
00265     if (this->item_iter == this->list->items.end()) {
00266       this->has_no_more_items = true;
00267       return;
00268     }
00269     this->item_iter++;
00270     if (this->item_iter != this->list->items.end()) item_next = (*this->item_iter).first;
00271   }
00272 
00273   int32 Next()
00274   {
00275     if (!this->HasNext()) return 0;
00276 
00277     int32 item_current = this->item_next;
00278     FindNext();
00279     return item_current;
00280   }
00281 
00282   void Remove(int item) {
00283     if (!this->HasNext()) return;
00284 
00285     /* If we remove the 'next' item, skip to the next */
00286     if (item == this->item_next) {
00287       FindNext();
00288       return;
00289     }
00290   }
00291 
00292   bool HasNext()
00293   {
00294     return !(this->list->items.empty() || this->has_no_more_items);
00295   }
00296 };
00297 
00301 class AIAbstractListSorterItemDescending : public AIAbstractListSorter {
00302 private:
00303   AIAbstractList::AIAbstractListMap::iterator item_iter;
00304   bool has_no_more_items;
00305   int32 item_next;
00306 
00307 public:
00308   AIAbstractListSorterItemDescending(AIAbstractList *list)
00309   {
00310     this->list = list;
00311     this->End();
00312   }
00313 
00314   int32 Begin()
00315   {
00316     if (this->list->items.empty()) return 0;
00317     this->has_no_more_items = false;
00318 
00319     this->item_iter = this->list->items.begin();
00320     for (size_t i = this->list->items.size(); i > 1; i--) this->item_iter++;
00321     this->item_next = (*this->item_iter).first;
00322 
00323     int32 item_current = this->item_next;
00324     FindNext();
00325     return item_current;
00326   }
00327 
00328   void End()
00329   {
00330     this->has_no_more_items = true;
00331   }
00332 
00333   void FindNext()
00334   {
00335     if (this->item_iter == this->list->items.end()) {
00336       this->has_no_more_items = true;
00337       return;
00338     }
00339     this->item_iter--;
00340     if (this->item_iter != this->list->items.end()) item_next = (*this->item_iter).first;
00341   }
00342 
00343   int32 Next()
00344   {
00345     if (!this->HasNext()) return 0;
00346 
00347     int32 item_current = this->item_next;
00348     FindNext();
00349     return item_current;
00350   }
00351 
00352   void Remove(int item)
00353   {
00354     if (!this->HasNext()) return;
00355 
00356     /* If we remove the 'next' item, skip to the next */
00357     if (item == this->item_next) {
00358       FindNext();
00359       return;
00360     }
00361   }
00362 
00363   bool HasNext()
00364   {
00365     return !(this->list->items.empty() || this->has_no_more_items);
00366   }
00367 };
00368 
00369 
00370 
00371 AIAbstractList::AIAbstractList()
00372 {
00373   /* Default sorter */
00374   this->sorter         = new AIAbstractListSorterValueDescending(this);
00375   this->sorter_type    = SORT_BY_VALUE;
00376   this->sort_ascending = false;
00377   this->initialized    = false;
00378   this->modifications  = 0;
00379 }
00380 
00381 AIAbstractList::~AIAbstractList()
00382 {
00383   delete this->sorter;
00384 }
00385 
00386 bool AIAbstractList::HasItem(int32 item)
00387 {
00388   return this->items.count(item) == 1;
00389 }
00390 
00391 void AIAbstractList::Clear()
00392 {
00393   this->modifications++;
00394 
00395   this->items.clear();
00396   this->buckets.clear();
00397   this->sorter->End();
00398 }
00399 
00400 void AIAbstractList::AddItem(int32 item)
00401 {
00402   this->modifications++;
00403 
00404   if (this->HasItem(item)) return;
00405 
00406   this->items[item] = 0;
00407   this->buckets[0].insert(item);
00408 }
00409 
00410 void AIAbstractList::RemoveItem(int32 item)
00411 {
00412   this->modifications++;
00413 
00414   if (!this->HasItem(item)) return;
00415 
00416   int32 value = this->GetValue(item);
00417 
00418   this->sorter->Remove(item);
00419   this->buckets[value].erase(item);
00420   if (this->buckets[value].empty()) this->buckets.erase(value);
00421   this->items.erase(item);
00422 }
00423 
00424 int32 AIAbstractList::Begin()
00425 {
00426   this->initialized = true;
00427   return this->sorter->Begin();
00428 }
00429 
00430 int32 AIAbstractList::Next()
00431 {
00432   if (this->initialized == false) {
00433     DEBUG(ai, 0, "ERROR: Next() is invalid as Begin() is never called");
00434     return false;
00435   }
00436   return this->sorter->Next();
00437 }
00438 
00439 bool AIAbstractList::IsEmpty()
00440 {
00441   return this->items.empty();
00442 }
00443 
00444 bool AIAbstractList::HasNext()
00445 {
00446   if (this->initialized == false) {
00447     DEBUG(ai, 0, "ERROR: HasNext() is invalid as Begin() is never called");
00448     return false;
00449   }
00450   return this->sorter->HasNext();
00451 }
00452 
00453 int32 AIAbstractList::Count()
00454 {
00455   return (int32)this->items.size();
00456 }
00457 
00458 int32 AIAbstractList::GetValue(int32 item)
00459 {
00460   if (!this->HasItem(item)) return 0;
00461 
00462   return this->items[item];
00463 }
00464 
00465 bool AIAbstractList::SetValue(int32 item, int32 value)
00466 {
00467   this->modifications++;
00468 
00469   if (!this->HasItem(item)) return false;
00470 
00471   int32 value_old = this->GetValue(item);
00472 
00473   this->sorter->Remove(item);
00474   this->buckets[value_old].erase(item);
00475   if (this->buckets[value_old].empty()) this->buckets.erase(value_old);
00476   this->items[item] = value;
00477   this->buckets[value].insert(item);
00478 
00479   return true;
00480 }
00481 
00482 void AIAbstractList::Sort(SorterType sorter, bool ascending)
00483 {
00484   this->modifications++;
00485 
00486   if (sorter != SORT_BY_VALUE && sorter != SORT_BY_ITEM) return;
00487   if (sorter == this->sorter_type && ascending == this->sort_ascending) return;
00488 
00489   delete this->sorter;
00490   switch (sorter) {
00491     case SORT_BY_ITEM:
00492       if (ascending) this->sorter = new AIAbstractListSorterItemAscending(this);
00493       else           this->sorter = new AIAbstractListSorterItemDescending(this);
00494       break;
00495 
00496     case SORT_BY_VALUE:
00497       if (ascending) this->sorter = new AIAbstractListSorterValueAscending(this);
00498       else           this->sorter = new AIAbstractListSorterValueDescending(this);
00499       break;
00500 
00501     default:
00502       this->Sort(SORT_BY_ITEM, false);
00503       return;
00504   }
00505   this->sorter_type    = sorter;
00506   this->sort_ascending = ascending;
00507 }
00508 
00509 void AIAbstractList::AddList(AIAbstractList *list)
00510 {
00511   AIAbstractListMap *list_items = &list->items;
00512   for (AIAbstractListMap::iterator iter = list_items->begin(); iter != list_items->end(); iter++) {
00513     this->AddItem((*iter).first);
00514     this->SetValue((*iter).first, (*iter).second);
00515   }
00516 }
00517 
00518 void AIAbstractList::RemoveAboveValue(int32 value)
00519 {
00520   this->modifications++;
00521 
00522   for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
00523     next_iter = iter; next_iter++;
00524     if ((*iter).second > value) this->items.erase(iter);
00525   }
00526 
00527   for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) {
00528     next_iter = iter; next_iter++;
00529     if ((*iter).first > value) this->buckets.erase(iter);
00530   }
00531 }
00532 
00533 void AIAbstractList::RemoveBelowValue(int32 value)
00534 {
00535   this->modifications++;
00536 
00537   for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
00538     next_iter = iter; next_iter++;
00539     if ((*iter).second < value) this->items.erase(iter);
00540   }
00541 
00542   for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) {
00543     next_iter = iter; next_iter++;
00544     if ((*iter).first < value) this->buckets.erase(iter);
00545   }
00546 }
00547 
00548 void AIAbstractList::RemoveBetweenValue(int32 start, int32 end)
00549 {
00550   this->modifications++;
00551 
00552   for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
00553     next_iter = iter; next_iter++;
00554     if ((*iter).second > start && (*iter).second < end) this->items.erase(iter);
00555   }
00556 
00557   for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) {
00558     next_iter = iter; next_iter++;
00559     if ((*iter).first > start && (*iter).first < end) this->buckets.erase(iter);
00560   }
00561 }
00562 
00563 void AIAbstractList::RemoveValue(int32 value)
00564 {
00565   this->modifications++;
00566 
00567   for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
00568     next_iter = iter; next_iter++;
00569     if ((*iter).second == value) this->items.erase(iter);
00570   }
00571 
00572   for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) {
00573     next_iter = iter; next_iter++;
00574     if ((*iter).first == value) this->buckets.erase(iter);
00575   }
00576 }
00577 
00578 void AIAbstractList::RemoveTop(int32 count)
00579 {
00580   this->modifications++;
00581 
00582   if (!this->sort_ascending) {
00583     this->Sort(this->sorter_type, !this->sort_ascending);
00584     this->RemoveBottom(count);
00585     this->Sort(this->sorter_type, !this->sort_ascending);
00586     return;
00587   }
00588 
00589   switch (this->sorter_type) {
00590     default: NOT_REACHED();
00591     case SORT_BY_VALUE:
00592       for (AIAbstractListBucket::iterator iter = this->buckets.begin(); iter != this->buckets.end(); iter = this->buckets.begin()) {
00593         AIItemList *items = &(*iter).second;
00594         size_t size = items->size();
00595         for (AIItemList::iterator iter = items->begin(); iter != items->end(); iter = items->begin()) {
00596           if (--count < 0) return;
00597           this->RemoveItem(*iter);
00598           /* When the last item is removed from the bucket, the bucket itself is removed.
00599            * This means that the iterators can be invalid after a call to RemoveItem.
00600            */
00601           if (--size == 0) break;
00602         }
00603       }
00604       break;
00605 
00606     case SORT_BY_ITEM:
00607       for (AIAbstractListMap::iterator iter = this->items.begin(); iter != this->items.end(); iter = this->items.begin()) {
00608         if (--count < 0) return;
00609         this->RemoveItem((*iter).first);
00610       }
00611       break;
00612   }
00613 }
00614 
00615 void AIAbstractList::RemoveBottom(int32 count)
00616 {
00617   this->modifications++;
00618 
00619   if (!this->sort_ascending) {
00620     this->Sort(this->sorter_type, !this->sort_ascending);
00621     this->RemoveTop(count);
00622     this->Sort(this->sorter_type, !this->sort_ascending);
00623     return;
00624   }
00625 
00626   switch (this->sorter_type) {
00627     default: NOT_REACHED();
00628     case SORT_BY_VALUE:
00629       for (AIAbstractListBucket::reverse_iterator iter = this->buckets.rbegin(); iter != this->buckets.rend(); iter = this->buckets.rbegin()) {
00630         AIItemList *items = &(*iter).second;
00631         size_t size = items->size();
00632         for (AIItemList::reverse_iterator iter = items->rbegin(); iter != items->rend(); iter = items->rbegin()) {
00633           if (--count < 0) return;
00634           this->RemoveItem(*iter);
00635           /* When the last item is removed from the bucket, the bucket itself is removed.
00636            * This means that the iterators can be invalid after a call to RemoveItem.
00637            */
00638           if (--size == 0) break;
00639         }
00640       }
00641 
00642     case SORT_BY_ITEM:
00643       for (AIAbstractListMap::reverse_iterator iter = this->items.rbegin(); iter != this->items.rend(); iter = this->items.rbegin()) {
00644         if (--count < 0) return;
00645         this->RemoveItem((*iter).first);
00646       }
00647       break;
00648   }
00649 }
00650 
00651 void AIAbstractList::RemoveList(AIAbstractList *list)
00652 {
00653   this->modifications++;
00654 
00655   AIAbstractListMap *list_items = &list->items;
00656   for (AIAbstractListMap::iterator iter = list_items->begin(); iter != list_items->end(); iter++) {
00657     this->RemoveItem((*iter).first);
00658   }
00659 }
00660 
00661 void AIAbstractList::KeepAboveValue(int32 value)
00662 {
00663   this->modifications++;
00664 
00665   for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
00666     next_iter = iter; next_iter++;
00667     if ((*iter).second <= value) this->items.erase(iter);
00668   }
00669 
00670   for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) {
00671     next_iter = iter; next_iter++;
00672     if ((*iter).first <= value) this->buckets.erase(iter);
00673   }
00674 }
00675 
00676 void AIAbstractList::KeepBelowValue(int32 value)
00677 {
00678   this->modifications++;
00679 
00680   for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
00681     next_iter = iter; next_iter++;
00682     if ((*iter).second >= value) this->items.erase(iter);
00683   }
00684 
00685   for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) {
00686     next_iter = iter; next_iter++;
00687     if ((*iter).first >= value) this->buckets.erase(iter);
00688   }
00689 }
00690 
00691 void AIAbstractList::KeepBetweenValue(int32 start, int32 end)
00692 {
00693   this->modifications++;
00694 
00695   for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
00696     next_iter = iter; next_iter++;
00697     if ((*iter).second <= start || (*iter).second >= end) this->items.erase(iter);
00698   }
00699 
00700   for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) {
00701     next_iter = iter; next_iter++;
00702     if ((*iter).first <= start || (*iter).first >= end) this->buckets.erase(iter);
00703   }
00704 }
00705 
00706 void AIAbstractList::KeepValue(int32 value)
00707 {
00708   this->modifications++;
00709 
00710   for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
00711     next_iter = iter; next_iter++;
00712     if ((*iter).second != value) this->items.erase(iter);
00713   }
00714 
00715   for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) {
00716     next_iter = iter; next_iter++;
00717     if ((*iter).first != value) this->buckets.erase(iter);
00718   }
00719 }
00720 
00721 void AIAbstractList::KeepTop(int32 count)
00722 {
00723   this->modifications++;
00724 
00725   this->RemoveBottom(this->Count() - count);
00726 }
00727 
00728 void AIAbstractList::KeepBottom(int32 count)
00729 {
00730   this->modifications++;
00731 
00732   this->RemoveTop(this->Count() - count);
00733 }
00734 
00735 void AIAbstractList::KeepList(AIAbstractList *list)
00736 {
00737   this->modifications++;
00738 
00739   AIAbstractList tmp;
00740   for (AIAbstractListMap::iterator iter = this->items.begin(); iter != this->items.end(); iter++) {
00741     tmp.AddItem((*iter).first);
00742     tmp.SetValue((*iter).first, (*iter).second);
00743   }
00744 
00745   tmp.RemoveList(list);
00746   this->RemoveList(&tmp);
00747 }
00748 
00749 SQInteger AIAbstractList::_get(HSQUIRRELVM vm)
00750 {
00751   if (sq_gettype(vm, 2) != OT_INTEGER) return SQ_ERROR;
00752 
00753   SQInteger idx;
00754   sq_getinteger(vm, 2, &idx);
00755 
00756   if (!this->HasItem(idx)) return SQ_ERROR;
00757 
00758   sq_pushinteger(vm, this->GetValue(idx));
00759   return 1;
00760 }
00761 
00762 SQInteger AIAbstractList::_nexti(HSQUIRRELVM vm)
00763 {
00764   if (sq_gettype(vm, 2) == OT_NULL) {
00765     if (this->IsEmpty()) {
00766       sq_pushnull(vm);
00767       return 1;
00768     }
00769     sq_pushinteger(vm, this->Begin());
00770     return 1;
00771   }
00772 
00773   SQInteger idx;
00774   sq_getinteger(vm, 2, &idx);
00775 
00776   int val = this->Next();
00777   if (!this->HasNext()) {
00778     sq_pushnull(vm);
00779     return 1;
00780   }
00781 
00782   sq_pushinteger(vm, val);
00783   return 1;
00784 }
00785 
00786 SQInteger AIAbstractList::Valuate(HSQUIRRELVM vm)
00787 {
00788   this->modifications++;
00789 
00790   /* The first parameter is the instance of AIAbstractList. */
00791   int nparam = sq_gettop(vm) - 1;
00792 
00793   if (nparam < 1) {
00794     return sq_throwerror(vm, _SC("You need to give a least a Valuator as parameter to AIAbstractList::Valuate"));
00795   }
00796 
00797   /* Make sure the valuator function is really a function, and not any
00798    * other type. It's parameter 2 for us, but for the user it's the
00799    * first parameter they give. */
00800   SQObjectType valuator_type = sq_gettype(vm, 2);
00801   if (valuator_type != OT_CLOSURE && valuator_type != OT_NATIVECLOSURE) {
00802     return sq_throwerror(vm, _SC("parameter 1 has an invalid type (expected function)"));
00803   }
00804 
00805   /* Don't allow docommand from a Valuator, as we can't resume in
00806    * mid C++-code. */
00807   bool backup_allow = AIObject::GetAllowDoCommand();
00808   AIObject::SetAllowDoCommand(false);
00809 
00810   /* Push the function to call */
00811   sq_push(vm, 2);
00812 
00813   /* Walk all items, and query the result */
00814   this->buckets.clear();
00815 
00816   /* Check for changing of items. */
00817   int begin_modification_count = this->modifications;
00818 
00819   for (AIAbstractListMap::iterator iter = this->items.begin(); iter != this->items.end(); iter++) {
00820     /* Push the root table as instance object, this is what squirrel does for meta-functions. */
00821     sq_pushroottable(vm);
00822     /* Push all arguments for the valuator function. */
00823     sq_pushinteger(vm, (*iter).first);
00824     for (int i = 0; i < nparam - 1; i++) {
00825       sq_push(vm, i + 3);
00826     }
00827 
00828     /* Call the function. Squirrel pops all parameters and pushes the return value. */
00829     if (SQ_FAILED(sq_call(vm, nparam + 1, SQTrue, SQTrue))) {
00830       AIObject::SetAllowDoCommand(backup_allow);
00831       return SQ_ERROR;
00832     }
00833 
00834     /* Retreive the return value */
00835     SQInteger value;
00836     switch (sq_gettype(vm, -1)) {
00837       case OT_INTEGER: {
00838         sq_getinteger(vm, -1, &value);
00839       } break;
00840 
00841       case OT_BOOL: {
00842         SQBool v;
00843         sq_getbool(vm, -1, &v);
00844         value = v ? 1 : 0;
00845       } break;
00846 
00847       default: {
00848         /* See below for explanation. The extra pop is the return value. */
00849         sq_pop(vm, nparam + 4);
00850 
00851         AIObject::SetAllowDoCommand(backup_allow);
00852         return sq_throwerror(vm, _SC("return value of valuator is not valid (not integer/bool)"));
00853       }
00854     }
00855 
00856     /* Was something changed? */
00857     if (begin_modification_count != this->modifications) {
00858       /* See below for explanation. The extra pop is the return value. */
00859       sq_pop(vm, nparam + 4);
00860 
00861       AIObject::SetAllowDoCommand(backup_allow);
00862       return sq_throwerror(vm, _SC("modifying valuated list outside of valuator function"));
00863     }
00864 
00865     (*iter).second = (int32)value;
00866     this->buckets[(int32)value].insert((*iter).first);
00867 
00868     /* Pop the return value. */
00869     sq_poptop(vm);
00870 
00871     Squirrel::DecreaseOps(vm, 5);
00872   }
00873   /* Pop from the squirrel stack:
00874    * 1. The root stable (as instance object).
00875    * 2. The valuator function.
00876    * 3. The parameters given to this function.
00877    * 4. The AIAbstractList instance object. */
00878   sq_pop(vm, nparam + 3);
00879 
00880   AIObject::SetAllowDoCommand(backup_allow);
00881   return 0;
00882 }

Generated on Sun Sep 13 08:19:13 2009 for OpenTTD by  doxygen 1.5.6