ai_abstractlist.cpp

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

Generated on Sat Dec 26 20:05:58 2009 for OpenTTD by  doxygen 1.5.6