# cargopacket.cpp

Go to the documentation of this file.

    00001 /* $Id: cargopacket.cpp 18330 2009-11-28 20:35:25Z rubidium $ */
    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 "stdafx.h"
    00013 #include "core/pool_func.hpp"
    00014 #include "economy_base.h"
    00015
    00016 /* Initialize the cargopacket-pool */
    00017 CargoPacketPool _cargopacket_pool("CargoPacket");
    00018 INSTANTIATE_POOL_METHODS(CargoPacket)
    00019
    00020
    00023 void InitializeCargoPackets()
    00024 {
    00025   _cargopacket_pool.CleanPool();
    00026 }
    00027
    00028 CargoPacket::CargoPacket()
    00029 {
    00030   this->source_type = ST_INDUSTRY;
    00031   this->source_id   = INVALID_SOURCE;
    00032 }
    00033
    00034 /* NOTE: We have to zero memory ourselves here because we are using a 'new'
    00035  * that, in contrary to all other pools, does not memset to 0. */
    00036 CargoPacket::CargoPacket(StationID source, TileIndex source_xy, uint16 count, SourceType source_type, SourceID source_id) :
    00037   feeder_share(0),
    00038   count(count),
    00039   days_in_transit(0),
    00040   source_id(source_id),
    00041   source(source),
    00042   source_xy(source_xy),
    00043   loaded_at_xy(0)
    00044 {
    00045   assert(count != 0);
    00046   this->source_type  = source_type;
    00047 }
    00048
    00049 CargoPacket::CargoPacket(uint16 count, byte days_in_transit, StationID source, TileIndex source_xy, TileIndex loaded_at_xy, Money feeder_share, SourceType source_type, SourceID source_id) :
    00050     feeder_share(feeder_share),
    00051     count(count),
    00052     days_in_transit(days_in_transit),
    00053     source_id(source_id),
    00054     source(source),
    00055     source_xy(source_xy),
    00056     loaded_at_xy(loaded_at_xy)
    00057 {
    00058   assert(count != 0);
    00059   this->source_type = source_type;
    00060 }
    00061
    00067 /* static */ void CargoPacket::InvalidateAllFrom(SourceType src_type, SourceID src)
    00068 {
    00069   CargoPacket *cp;
    00070   FOR_ALL_CARGOPACKETS(cp) {
    00071     if (cp->source_type == src_type && cp->source_id == src) cp->source_id = INVALID_SOURCE;
    00072   }
    00073 }
    00074
    00079 /* static */ void CargoPacket::InvalidateAllFrom(StationID sid)
    00080 {
    00081   CargoPacket *cp;
    00082   FOR_ALL_CARGOPACKETS(cp) {
    00083     if (cp->source == sid) cp->source = INVALID_STATION;
    00084   }
    00085 }
    00086
    00087 /*
    00088  *
    00089  * Cargo list implementation
    00090  *
    00091  */
    00092
    00093 template <class Tinst>
    00094 CargoList<Tinst>::~CargoList()
    00095 {
    00096   for (Iterator it(this->packets.begin()); it != this->packets.end(); ++it) {
    00097     delete *it;
    00098   }
    00099 }
    00100
    00101 template <class Tinst>
    00102 void CargoList<Tinst>::RemoveFromCache(const CargoPacket *cp)
    00103 {
    00104   this->count                 -= cp->count;
    00105   this->cargo_days_in_transit -= cp->days_in_transit * cp->count;
    00106 }
    00107
    00108 template <class Tinst>
    00109 void CargoList<Tinst>::AddToCache(const CargoPacket *cp)
    00110 {
    00111   this->count                 += cp->count;
    00112   this->cargo_days_in_transit += cp->days_in_transit * cp->count;
    00113 }
    00114
    00115 template <class Tinst>
    00116 void CargoList<Tinst>::Append(CargoPacket *cp)
    00117 {
    00118   assert(cp != NULL);
    00119   static_cast<Tinst *>(this)->AddToCache(cp);
    00120
    00121   for (List::reverse_iterator it(this->packets.rbegin()); it != this->packets.rend(); it++) {
    00122     CargoPacket *icp = *it;
    00123     if (Tinst::AreMergable(icp, cp) && icp->count + cp->count <= CargoPacket::MAX_COUNT) {
    00124       icp->count        += cp->count;
    00125       icp->feeder_share += cp->feeder_share;
    00126
    00127       delete cp;
    00128       return;
    00129     }
    00130   }
    00131
    00132   /* The packet could not be merged with another one */
    00133   this->packets.push_back(cp);
    00134 }
    00135
    00136
    00137 template <class Tinst>
    00138 void CargoList<Tinst>::Truncate(uint max_remaining)
    00139 {
    00140   for (Iterator it(packets.begin()); it != packets.end(); /* done during loop*/) {
    00141     CargoPacket *cp = *it;
    00142     if (max_remaining == 0) {
    00143       /* Nothing should remain, just remove the packets. */
    00144       this->packets.erase(it++);
    00145       static_cast<Tinst *>(this)->RemoveFromCache(cp);
    00146       delete cp;
    00147       continue;
    00148     }
    00149
    00150     uint local_count = cp->count;
    00151     if (local_count > max_remaining) {
    00152       uint diff = local_count - max_remaining;
    00153       this->count -= diff;
    00154       this->cargo_days_in_transit -= cp->days_in_transit * diff;
    00155       cp->count = max_remaining;
    00156       max_remaining = 0;
    00157     } else {
    00158       max_remaining -= local_count;
    00159     }
    00160     ++it;
    00161   }
    00162 }
    00163
    00164 template <class Tinst>
    00165 template <class Tother_inst>
    00166 bool CargoList<Tinst>::MoveTo(Tother_inst *dest, uint max_move, MoveToAction mta, CargoPayment *payment, uint data)
    00167 {
    00168   assert(mta == MTA_FINAL_DELIVERY || dest != NULL);
    00169   assert(mta == MTA_UNLOAD || mta == MTA_CARGO_LOAD || payment != NULL);
    00170
    00171   Iterator it(this->packets.begin());
    00172   while (it != this->packets.end() && max_move > 0) {
    00173     CargoPacket *cp = *it;
    00174     if (cp->source == data && mta == MTA_FINAL_DELIVERY) {
    00175       /* Skip cargo that originated from this station. */
    00176       ++it;
    00177       continue;
    00178     }
    00179
    00180     if (cp->count <= max_move) {
    00181       /* Can move the complete packet */
    00182       max_move -= cp->count;
    00183       this->packets.erase(it++);
    00184       static_cast<Tinst *>(this)->RemoveFromCache(cp);
    00185       switch(mta) {
    00186         case MTA_FINAL_DELIVERY:
    00187           payment->PayFinalDelivery(cp, cp->count);
    00188           delete cp;
    00189           continue; // of the loop
    00190
    00191         case MTA_CARGO_LOAD:
    00192           cp->loaded_at_xy = data;
    00193           break;
    00194
    00195         case MTA_TRANSFER:
    00196           cp->feeder_share += payment->PayTransfer(cp, cp->count);
    00197           break;
    00198
    00199         case MTA_UNLOAD:
    00200           break;
    00201       }
    00202       dest->Append(cp);
    00203       continue;
    00204     }
    00205
    00206     /* Can move only part of the packet */
    00207     if (mta == MTA_FINAL_DELIVERY) {
    00208       /* Final delivery doesn't need package splitting. */
    00209       payment->PayFinalDelivery(cp, max_move);
    00210
    00211       /* Remove the delivered data from the cache */
    00212       uint left = cp->count - max_move;
    00213       cp->count = max_move;
    00214       static_cast<Tinst *>(this)->RemoveFromCache(cp);
    00215
    00216       /* Final delivery payment pays the feeder share, so we have to
    00217        * reset that so it is not 'shown' twice for partial unloads. */
    00218       cp->feeder_share = 0;
    00219       cp->count = left;
    00220     } else {
    00221       /* But... the rest needs package splitting. */
    00222       Money fs = cp->feeder_share * max_move / static_cast<uint>(cp->count);
    00223       cp->feeder_share -= fs;
    00224       cp->count -= max_move;
    00225
    00226       CargoPacket *cp_new = new CargoPacket(max_move, cp->days_in_transit, cp->source, cp->source_xy, (mta == MTA_CARGO_LOAD) ? data : cp->loaded_at_xy, fs, cp->source_type, cp->source_id);
    00227       static_cast<Tinst *>(this)->RemoveFromCache(cp_new); // this reflects the changes in cp.
    00228
    00229       if (mta == MTA_TRANSFER) {
    00230         /* Add the feeder share before inserting in dest. */
    00231         cp_new->feeder_share += payment->PayTransfer(cp_new, max_move);
    00232       }
    00233
    00234       dest->Append(cp_new);
    00235     }
    00236
    00237     max_move = 0;
    00238   }
    00239
    00240   return it != packets.end();
    00241 }
    00242
    00243 template <class Tinst>
    00244 void CargoList<Tinst>::InvalidateCache()
    00245 {
    00246   this->count = 0;
    00247   this->cargo_days_in_transit = 0;
    00248
    00249   for (ConstIterator it(this->packets.begin()); it != this->packets.end(); it++) {
    00250     static_cast<Tinst *>(this)->AddToCache(*it);
    00251   }
    00252 }
    00253
    00254
    00255 void VehicleCargoList::RemoveFromCache(const CargoPacket *cp)
    00256 {
    00257   this->feeder_share -= cp->feeder_share;
    00258   this->Parent::RemoveFromCache(cp);
    00259 }
    00260
    00261 void VehicleCargoList::AddToCache(const CargoPacket *cp)
    00262 {
    00263   this->feeder_share += cp->feeder_share;
    00264   this->Parent::AddToCache(cp);
    00265 }
    00266
    00267 void VehicleCargoList::AgeCargo()
    00268 {
    00269   for (ConstIterator it(this->packets.begin()); it != this->packets.end(); it++) {
    00270     CargoPacket *cp = *it;
    00271     /* If we're at the maximum, then we can't increase no more. */
    00272     if (cp->days_in_transit == 0xFF) continue;
    00273
    00274     cp->days_in_transit++;
    00275     this->cargo_days_in_transit += cp->count;
    00276   }
    00277 }
    00278
    00279 void VehicleCargoList::InvalidateCache()
    00280 {
    00281   this->feeder_share = 0;
    00282   this->Parent::InvalidateCache();
    00283 }
    00284
    00285 /*
    00286  * We have to instantiate everything we want to be usable.
    00287  */
    00288 template class CargoList<VehicleCargoList>;
    00289 template class CargoList<StationCargoList>;
    00290
    00292 template bool CargoList<VehicleCargoList>::MoveTo(VehicleCargoList *, uint max_move, MoveToAction mta, CargoPayment *payment, uint data);
    00294 template bool CargoList<VehicleCargoList>::MoveTo(StationCargoList *, uint max_move, MoveToAction mta, CargoPayment *payment, uint data);
    00296 template bool CargoList<StationCargoList>::MoveTo(VehicleCargoList *, uint max_move, MoveToAction mta, CargoPayment *payment, uint data);