(svn r18776) -Codechange: Use SmallVector to collect refit options.

This commit is contained in:
frosch 2010-01-10 21:45:32 +00:00
parent 3ebec78900
commit d5fa74369a

View File

@ -222,37 +222,43 @@ byte GetBestFittingSubType(Vehicle *v_from, Vehicle *v_for)
return ret_refit_cyc; return ret_refit_cyc;
} }
/** Option to refit a vehicle chain */
struct RefitOption { struct RefitOption {
CargoID cargo; CargoID cargo; ///< Cargo to refit to
byte subtype; byte subtype; ///< Subcargo to use
uint16 value; uint16 value; ///< GRF-local String to display for the cargo
EngineID engine; EngineID engine; ///< Engine for which to resolve #value
FORCEINLINE bool operator != (const RefitOption &other) const
{
return other.cargo != this->cargo || other.subtype != this->subtype;
}
}; };
struct RefitList { typedef SmallVector<RefitOption, 32> RefitList;
uint num_lines; ///< Number of #items.
RefitOption *items;
};
static RefitList *BuildRefitList(const Vehicle *v) /**
* Collects all (cargo, subcargo) refit-options of a vehicle chain
* @param v front vehicle
* @param refit_list container to store result
*/
static void BuildRefitList(const Vehicle *v, RefitList *refit_list)
{ {
uint max_lines = 256; refit_list->Clear();
RefitOption *refit = CallocT<RefitOption>(max_lines);
RefitList *list = CallocT<RefitList>(1);
Vehicle *u = const_cast<Vehicle *>(v); Vehicle *u = const_cast<Vehicle *>(v);
uint num_lines = 0;
uint i;
do { do {
const Engine *e = Engine::Get(u->engine_type); const Engine *e = Engine::Get(u->engine_type);
uint32 cmask = e->info.refit_mask; uint32 cmask = e->info.refit_mask;
byte callback_mask = e->info.callback_mask; byte callback_mask = e->info.callback_mask;
/* Skip this engine if it has no capacity */ /* Skip this engine if it does not carry anything */
if (u->cargo_cap == 0) continue; if (!e->CanCarryCargo()) continue;
/* Loop through all cargos in the refit mask */ /* Loop through all cargos in the refit mask */
for (CargoID cid = 0; cid < NUM_CARGO && num_lines < max_lines; cid++) { const CargoSpec *cs;
FOR_ALL_CARGOSPECS(cs) {
CargoID cid = cs->Index();
/* Skip cargo type if it's not listed */ /* Skip cargo type if it's not listed */
if (!HasBit(cmask, cid)) continue; if (!HasBit(cmask, cid)) continue;
@ -265,32 +271,23 @@ static RefitList *BuildRefitList(const Vehicle *v)
u->cargo_type = cid; u->cargo_type = cid;
for (uint refit_cyc = 0; refit_cyc < MAX_REFIT_CYCLE && num_lines < max_lines; refit_cyc++) { for (uint refit_cyc = 0; refit_cyc < MAX_REFIT_CYCLE; refit_cyc++) {
bool duplicate = false;
uint16 callback;
u->cargo_subtype = refit_cyc; u->cargo_subtype = refit_cyc;
/* Make sure we don't pick up anything cached. */ /* Make sure we don't pick up anything cached. */
u->First()->InvalidateNewGRFCache(); u->First()->InvalidateNewGRFCache();
u->InvalidateNewGRFCache(); u->InvalidateNewGRFCache();
callback = GetVehicleCallback(CBID_VEHICLE_CARGO_SUFFIX, 0, 0, u->engine_type, u); uint16 callback = GetVehicleCallback(CBID_VEHICLE_CARGO_SUFFIX, 0, 0, u->engine_type, u);
if (callback == 0xFF) callback = CALLBACK_FAILED; if (callback == 0xFF) callback = CALLBACK_FAILED;
if (refit_cyc != 0 && callback == CALLBACK_FAILED) break; if (refit_cyc != 0 && callback == CALLBACK_FAILED) break;
/* Check if this cargo and subtype combination are listed */ RefitOption option;
for (i = 0; i < num_lines && !duplicate; i++) { option.cargo = cid;
if (refit[i].cargo == cid && refit[i].value == callback) duplicate = true; option.subtype = refit_cyc;
} option.value = callback;
option.engine = u->engine_type;
if (duplicate) continue; refit_list->Include(option);
refit[num_lines].cargo = cid;
refit[num_lines].subtype = refit_cyc;
refit[num_lines].value = callback;
refit[num_lines].engine = u->engine_type;
num_lines++;
} }
/* Reset the vehicle's cargo type */ /* Reset the vehicle's cargo type */
@ -302,27 +299,15 @@ static RefitList *BuildRefitList(const Vehicle *v)
u->InvalidateNewGRFCache(); u->InvalidateNewGRFCache();
} else { } else {
/* No cargo suffix callback -- use no subtype */ /* No cargo suffix callback -- use no subtype */
bool duplicate = false; RefitOption option;
option.cargo = cid;
for (i = 0; i < num_lines && !duplicate; i++) { option.subtype = 0;
if (refit[i].cargo == cid && refit[i].value == CALLBACK_FAILED) duplicate = true; option.value = CALLBACK_FAILED;
} option.engine = INVALID_ENGINE;
refit_list->Include(option);
if (!duplicate) {
refit[num_lines].cargo = cid;
refit[num_lines].subtype = 0;
refit[num_lines].value = CALLBACK_FAILED;
refit[num_lines].engine = INVALID_ENGINE;
num_lines++;
} }
} }
} } while ((v->type == VEH_TRAIN || v->type == VEH_ROAD) && (u = u->Next()) != NULL);
} while ((v->type == VEH_TRAIN || v->type == VEH_ROAD) && (u = u->Next()) != NULL && num_lines < max_lines);
list->num_lines = num_lines;
list->items = refit;
return list;
} }
/** Draw the list of available refit options for a consist and highlight the selected refit option (if any). /** Draw the list of available refit options for a consist and highlight the selected refit option (if any).
@ -333,13 +318,13 @@ static RefitList *BuildRefitList(const Vehicle *v)
* @param delta Step height in caller window * @param delta Step height in caller window
* @param r Rectangle of the matrix widget. * @param r Rectangle of the matrix widget.
*/ */
static void DrawVehicleRefitWindow(const RefitList *list, int sel, uint pos, uint rows, uint delta, const Rect &r) static void DrawVehicleRefitWindow(const RefitList &list, int sel, uint pos, uint rows, uint delta, const Rect &r)
{ {
uint y = r.top + WD_MATRIX_TOP; uint y = r.top + WD_MATRIX_TOP;
/* Draw the list, and find the selected cargo (by its position in list) */ /* Draw the list, and find the selected cargo (by its position in list) */
for (uint i = pos; i < pos + rows && i < list->num_lines; i++) { for (uint i = pos; i < pos + rows && i < list.Length(); i++) {
TextColour colour = (sel == (int)i) ? TC_WHITE : TC_BLACK; TextColour colour = (sel == (int)i) ? TC_WHITE : TC_BLACK;
RefitOption *refit = &list->items[i]; const RefitOption *refit = &list[i];
/* Get the cargo name */ /* Get the cargo name */
SetDParam(0, CargoSpec::Get(refit->cargo)->name); SetDParam(0, CargoSpec::Get(refit->cargo)->name);
@ -370,7 +355,7 @@ enum VehicleRefitWidgets {
struct RefitWindow : public Window { struct RefitWindow : public Window {
int sel; ///< Index in refit options, \c -1 if nothing is selected. int sel; ///< Index in refit options, \c -1 if nothing is selected.
RefitOption *cargo; ///< Refit option selected by \v sel. RefitOption *cargo; ///< Refit option selected by \v sel.
RefitList *list; ///< List of cargo types available for refitting. RefitList list; ///< List of cargo types available for refitting.
uint length; ///< For trains, the number of vehicles. uint length; ///< For trains, the number of vehicles.
VehicleOrderID order; ///< If not #INVALID_VEH_ORDER_ID, selection is part of a refit order (rather than execute directly). VehicleOrderID order; ///< If not #INVALID_VEH_ORDER_ID, selection is part of a refit order (rather than execute directly).
@ -389,15 +374,9 @@ struct RefitWindow : public Window {
this->order = order; this->order = order;
this->sel = -1; this->sel = -1;
this->list = BuildRefitList(v); BuildRefitList(v, &this->list);
if (v->type == VEH_TRAIN) this->length = CountVehiclesInChain(v); if (v->type == VEH_TRAIN) this->length = CountVehiclesInChain(v);
this->vscroll.SetCount(this->list->num_lines); this->vscroll.SetCount(this->list.Length());
}
~RefitWindow()
{
free(this->list->items);
free(this->list);
} }
virtual void OnPaint() virtual void OnPaint()
@ -409,16 +388,14 @@ struct RefitWindow : public Window {
if (length != this->length) { if (length != this->length) {
/* Consist length has changed, so rebuild the refit list */ /* Consist length has changed, so rebuild the refit list */
free(this->list->items); BuildRefitList(v, &this->list);
free(this->list);
this->list = BuildRefitList(v);
this->length = length; this->length = length;
} }
} }
this->vscroll.SetCount(this->list->num_lines); this->vscroll.SetCount(this->list.Length());
this->cargo = (this->sel >= 0 && this->sel < (int)this->list->num_lines) ? &this->list->items[this->sel] : NULL; this->cargo = (this->sel >= 0 && this->sel < (int)this->list.Length()) ? &this->list[this->sel] : NULL;
this->DrawWidgets(); this->DrawWidgets();
} }