(svn r11312) -Codechange: implement a overflow safe integer and use that for money and don't misuses CommandCost to have a overflow safe integer. Based on a patch by Noldo.

This commit is contained in:
rubidium 2007-10-20 14:51:09 +00:00
parent 54369cba0f
commit 8212088c03
12 changed files with 164 additions and 39 deletions

View File

@ -954,7 +954,7 @@ static void AiNew_State_VerifyRoute(Player *p)
// Check if we have enough money for it!
if (p->ainew.new_cost > p->player_money - AI_MINIMUM_MONEY) {
// Too bad..
DEBUG(ai, 1, "Insufficient funds to build route (%d)", p->ainew.new_cost);
DEBUG(ai, 1, "Insufficient funds to build route (%" OTTD_PRINTF64 "d)", (int64)p->ainew.new_cost);
p->ainew.state = AI_STATE_NOTHING;
return;
}
@ -1086,7 +1086,7 @@ static void AiNew_State_BuildPath(Player *p)
}
}
DEBUG(ai, 1, "Finished building path, cost: %d", p->ainew.new_cost);
DEBUG(ai, 1, "Finished building path, cost: %" OTTD_PRINTF64 "d", (int64)p->ainew.new_cost);
p->ainew.state = AI_STATE_BUILD_DEPOT;
}
}

View File

@ -226,8 +226,8 @@ static int CDECL TrainEnginePowerVsRunningCostSorter(const void *a, const void *
* Because of this, the return value have to be reversed as well and we return b - a instead of a - b.
* Another thing is that both power and running costs should be doubled for multiheaded engines.
* Since it would be multipling with 2 in both numerator and denumerator, it will even themselves out and we skip checking for multiheaded. */
Money va = (rvi_a->running_cost_base * _price.running_rail[rvi_a->running_cost_class]) / max((uint16)1, rvi_a->power);
Money vb = (rvi_b->running_cost_base * _price.running_rail[rvi_b->running_cost_class]) / max((uint16)1, rvi_b->power);
Money va = (rvi_a->running_cost_base * _price.running_rail[rvi_a->running_cost_class]) / max(1U, (uint)rvi_a->power);
Money vb = (rvi_b->running_cost_base * _price.running_rail[rvi_b->running_cost_class]) / max(1U, (uint)rvi_b->power);
int r = ClampToI32(vb - va);
return _internal_sort_order ? -r : r;

View File

@ -677,25 +677,13 @@ CommandCost CommandCost::AddCost(CommandCost ret)
CommandCost CommandCost::AddCost(Money cost)
{
/* Overflow protection */
if (cost < 0 && (this->cost + cost) > this->cost) {
this->cost = INT64_MIN;
} else if (cost > 0 && (this->cost + cost) < this->cost) {
this->cost = INT64_MAX;
} else {
this->cost += cost;
}
this->cost += cost;
return *this;
}
CommandCost CommandCost::MultiplyCost(int factor)
{
/* Overflow protection */
if (factor != 0 && (INT64_MAX / myabs(factor)) < myabs(this->cost)) {
this->cost = (this->cost < 0 == factor < 0) ? INT64_MAX : INT64_MIN;
} else {
this->cost *= factor;
}
this->cost *= factor;
return *this;
}

View File

@ -1249,7 +1249,7 @@ DEF_CONSOLE_CMD(ConPlayers)
GetString(buffer, STR_00D1_DARK_BLUE + _player_colors[p->index], lastof(buffer));
IConsolePrintF(8, "#:%d(%s) Company Name: '%s' Year Founded: %d Money: %" OTTD_PRINTF64 "d Loan: %" OTTD_PRINTF64 "d Value: %" OTTD_PRINTF64 "d (T:%d, R:%d, P:%d, S:%d) %sprotected",
p->index + 1, buffer, npi->company_name, p->inaugurated_year, p->player_money, p->current_loan, CalculateCompanyValue(p),
p->index + 1, buffer, npi->company_name, p->inaugurated_year, (int64)p->player_money, (int64)p->current_loan, (int64)CalculateCompanyValue(p),
/* trains */ npi->num_vehicle[0],
/* lorry + bus */ npi->num_vehicle[1] + npi->num_vehicle[2],
/* planes */ npi->num_vehicle[3],

View File

@ -95,7 +95,7 @@ Money CalculateCompanyValue(const Player* p)
value.AddCost(-p->current_loan);
value.AddCost(p->player_money);
return max(value.GetCost(), 1LL);
return max(value.GetCost(), (Money)1);
}
/** if update is set to true, the economy is updated with this score

View File

@ -120,7 +120,7 @@ void ShowEnginePreviewWindow(EngineID engine)
static void DrawTrainEngineInfo(EngineID engine, int x, int y, int maxw)
{
const RailVehicleInfo *rvi = RailVehInfo(engine);
uint multihead = (rvi->railveh_type == RAILVEH_MULTIHEAD) ? 1 : 0;
int multihead = (rvi->railveh_type == RAILVEH_MULTIHEAD) ? 1 : 0;
SetDParam(0, (_price.build_railvehicle >> 3) * rvi->base_cost >> 5);
SetDParam(2, rvi->max_speed * 10 / 16);

View File

@ -41,8 +41,8 @@ enum {
};
/* Apparently these don't play well with enums. */
static const int64 INVALID_DATAPOINT = INT64_MAX; // Value used for a datapoint that shouldn't be drawn.
static const uint INVALID_DATAPOINT_POS = UINT_MAX; // Used to determine if the previous point was drawn.
static const OverflowSafeInt64 INVALID_DATAPOINT = INT64_MAX; // Value used for a datapoint that shouldn't be drawn.
static const uint INVALID_DATAPOINT_POS = UINT_MAX; // Used to determine if the previous point was drawn.
struct GraphDrawer {
uint excluded_data; ///< bitmask of the datasets that shouldn't be displayed.
@ -70,9 +70,9 @@ struct GraphDrawer {
static void DrawGraph(const GraphDrawer *gw)
{
uint x, y; ///< Reused whenever x and y coordinates are needed.
int64 highest_value; ///< Highest value to be drawn.
int x_axis_offset; ///< Distance from the top of the graph to the x axis.
uint x, y; ///< Reused whenever x and y coordinates are needed.
OverflowSafeInt64 highest_value; ///< Highest value to be drawn.
int x_axis_offset; ///< Distance from the top of the graph to the x axis.
/* the colors and cost array of GraphDrawer must accomodate
* both values for cargo and players. So if any are higher, quit */
@ -515,7 +515,7 @@ static void DeliveredCargoGraphWndProc(Window *w, WindowEvent *e)
if (p->is_active) {
gd.colors[numd] = _colour_gradient[p->player_color][6];
for (int j = gd.num_on_x_axis, i = 0; --j >= 0;) {
gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_DATAPOINT : p->old_economy[j].delivered_cargo;
gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_DATAPOINT : (OverflowSafeInt64)p->old_economy[j].delivered_cargo;
i++;
}
}
@ -582,7 +582,7 @@ static void PerformanceHistoryWndProc(Window *w, WindowEvent *e)
if (p->is_active) {
gd.colors[numd] = _colour_gradient[p->player_color][6];
for (int j = gd.num_on_x_axis, i = 0; --j >= 0;) {
gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_DATAPOINT : p->old_economy[j].performance_history;
gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_DATAPOINT : (OverflowSafeInt64)p->old_economy[j].performance_history;
i++;
}
}

View File

@ -158,4 +158,139 @@ template <typename T> void ToggleBitT(T &t, int bit_index)
t = (T)(t ^ ((T)1 << bit_index));
}
/**
* Overflow safe template for integers, i.e. integers that will never overflow
* you multiply the maximum value with 2, or add 2, or substract somethng from
* the minimum value, etc.
* @param T the type these integers are stored with.
* @param T_MAX the maximum value for the integers.
* @param T_MIN the minimum value for the integers.
*/
template <class T, T T_MAX, T T_MIN>
class OverflowSafeInt
{
private:
/** The non-overflow safe backend to store the value in. */
T m_value;
public:
OverflowSafeInt() : m_value(0) { }
OverflowSafeInt(const OverflowSafeInt& other) { this->m_value = other.m_value; }
OverflowSafeInt(const int64 int_) { this->m_value = int_; }
FORCEINLINE OverflowSafeInt& operator = (const OverflowSafeInt& other) { this->m_value = other.m_value; return *this; }
FORCEINLINE OverflowSafeInt operator - () const { return OverflowSafeInt(-this->m_value); }
/**
* Safe implementation of addition.
* @param other the amount to add
* @note when the addition would yield more than T_MAX (or less than T_MIN),
* it will be T_MAX (respectively T_MIN).
*/
FORCEINLINE OverflowSafeInt& operator += (const OverflowSafeInt& other)
{
if ((T_MAX - myabs(other.m_value)) < myabs(this->m_value) &&
(this->m_value < 0) == (other.m_value < 0)) {
this->m_value = (this->m_value < 0) ? T_MIN : T_MAX ;
} else {
this->m_value += other.m_value;
}
return *this;
}
/* Operators for addition and substraction */
FORCEINLINE OverflowSafeInt operator + (const OverflowSafeInt& other) const { OverflowSafeInt result = *this; result += other; return result; }
FORCEINLINE OverflowSafeInt operator + (const int other) const { OverflowSafeInt result = *this; result += (int64)other; return result; }
FORCEINLINE OverflowSafeInt operator + (const uint other) const { OverflowSafeInt result = *this; result += (int64)other; return result; }
FORCEINLINE OverflowSafeInt& operator -= (const OverflowSafeInt& other) { return *this += (-other); }
FORCEINLINE OverflowSafeInt operator - (const OverflowSafeInt& other) const { OverflowSafeInt result = *this; result -= other; return result; }
FORCEINLINE OverflowSafeInt operator - (const int other) const { OverflowSafeInt result = *this; result -= (int64)other; return result; }
FORCEINLINE OverflowSafeInt operator - (const uint other) const { OverflowSafeInt result = *this; result -= (int64)other; return result; }
FORCEINLINE OverflowSafeInt& operator ++ (int) { return *this += 1; }
FORCEINLINE OverflowSafeInt& operator -- (int) { return *this += -1; }
/**
* Safe implementation of multiplication.
* @param factor the factor to multiply this with.
* @note when the multiplication would yield more than T_MAX (or less than T_MIN),
* it will be T_MAX (respectively T_MIN).
*/
FORCEINLINE OverflowSafeInt& operator *= (const int factor)
{
if (factor != 0 && (T_MAX / myabs(factor)) < myabs(this->m_value)) {
this->m_value = ((this->m_value < 0) == (factor < 0)) ? T_MAX : T_MIN ;
} else {
this->m_value *= factor ;
}
return *this;
}
/* Operators for multiplication */
FORCEINLINE OverflowSafeInt operator * (const int64 factor) const { OverflowSafeInt result = *this; result *= factor; return result; }
FORCEINLINE OverflowSafeInt operator * (const int factor) const { OverflowSafeInt result = *this; result *= (int64)factor; return result; }
FORCEINLINE OverflowSafeInt operator * (const uint factor) const { OverflowSafeInt result = *this; result *= (int64)factor; return result; }
FORCEINLINE OverflowSafeInt operator * (const uint16 factor) const { OverflowSafeInt result = *this; result *= (int64)factor; return result; }
FORCEINLINE OverflowSafeInt operator * (const byte factor) const { OverflowSafeInt result = *this; result *= (int64)factor; return result; }
/* Operators for division */
FORCEINLINE OverflowSafeInt& operator /= (const int divisor) { this->m_value /= divisor; return *this; }
FORCEINLINE OverflowSafeInt operator / (const OverflowSafeInt& divisor) const { OverflowSafeInt result = *this; result /= divisor.m_value; return result; }
FORCEINLINE OverflowSafeInt operator / (const int divisor) const { OverflowSafeInt result = *this; result /= divisor; return result; }
FORCEINLINE OverflowSafeInt operator / (const uint divisor) const { OverflowSafeInt result = *this; result /= (int)divisor; return result; }
/* Operators for modulo */
FORCEINLINE OverflowSafeInt& operator %= (const int divisor) { this->m_value %= divisor; return *this; }
FORCEINLINE OverflowSafeInt operator % (const int divisor) const { OverflowSafeInt result = *this; result %= divisor; return result; }
/* Operators for shifting */
FORCEINLINE OverflowSafeInt& operator <<= (const int shift) { this->m_value <<= shift; return *this; }
FORCEINLINE OverflowSafeInt operator << (const int shift) const { OverflowSafeInt result = *this; result <<= shift; return result; }
FORCEINLINE OverflowSafeInt& operator >>= (const int shift) { this->m_value >>= shift; return *this; }
FORCEINLINE OverflowSafeInt operator >> (const int shift) const { OverflowSafeInt result = *this; result >>= shift; return result; }
/* Operators for (in)equality when comparing overflow safe ints */
FORCEINLINE bool operator == (const OverflowSafeInt& other) const { return this->m_value == other.m_value; }
FORCEINLINE bool operator != (const OverflowSafeInt& other) const { return !(*this == other); }
FORCEINLINE bool operator > (const OverflowSafeInt& other) const { return this->m_value > other.m_value; }
FORCEINLINE bool operator >= (const OverflowSafeInt& other) const { return this->m_value >= other.m_value; }
FORCEINLINE bool operator < (const OverflowSafeInt& other) const { return !(*this >= other); }
FORCEINLINE bool operator <= (const OverflowSafeInt& other) const { return !(*this > other); }
/* Operators for (in)equality when comparing non-overflow safe ints */
FORCEINLINE bool operator == (const int other) const { return this->m_value == other; }
FORCEINLINE bool operator != (const int other) const { return !(*this == other); }
FORCEINLINE bool operator > (const int other) const { return this->m_value > other; }
FORCEINLINE bool operator >= (const int other) const { return this->m_value >= other; }
FORCEINLINE bool operator < (const int other) const { return !(*this >= other); }
FORCEINLINE bool operator <= (const int other) const { return !(*this > other); }
FORCEINLINE operator int64 () const { return this->m_value; }
};
/* Sometimes we got int64 operator OverflowSafeInt instead of vice versa. Handle that properly */
template <class T, int64 T_MAX, int64 T_MIN> FORCEINLINE OverflowSafeInt<T, T_MAX, T_MIN> operator + (int64 a, OverflowSafeInt<T, T_MAX, T_MIN> b) { return b + a; }
template <class T, int64 T_MAX, int64 T_MIN> FORCEINLINE OverflowSafeInt<T, T_MAX, T_MIN> operator - (int64 a, OverflowSafeInt<T, T_MAX, T_MIN> b) { return -b + a; }
template <class T, int64 T_MAX, int64 T_MIN> FORCEINLINE OverflowSafeInt<T, T_MAX, T_MIN> operator * (int64 a, OverflowSafeInt<T, T_MAX, T_MIN> b) { return b * a; }
template <class T, int64 T_MAX, int64 T_MIN> FORCEINLINE OverflowSafeInt<T, T_MAX, T_MIN> operator / (int64 a, OverflowSafeInt<T, T_MAX, T_MIN> b) { return (OverflowSafeInt<T, T_MAX, T_MIN>)a / (int)b; }
/* Sometimes we got int operator OverflowSafeInt instead of vice versa. Handle that properly */
template <class T, int64 T_MAX, int64 T_MIN> FORCEINLINE OverflowSafeInt<T, T_MAX, T_MIN> operator + (int a, OverflowSafeInt<T, T_MAX, T_MIN> b) { return b + a; }
template <class T, int64 T_MAX, int64 T_MIN> FORCEINLINE OverflowSafeInt<T, T_MAX, T_MIN> operator - (int a, OverflowSafeInt<T, T_MAX, T_MIN> b) { return -b + a; }
template <class T, int64 T_MAX, int64 T_MIN> FORCEINLINE OverflowSafeInt<T, T_MAX, T_MIN> operator * (int a, OverflowSafeInt<T, T_MAX, T_MIN> b) { return b * a; }
template <class T, int64 T_MAX, int64 T_MIN> FORCEINLINE OverflowSafeInt<T, T_MAX, T_MIN> operator / (int a, OverflowSafeInt<T, T_MAX, T_MIN> b) { return (OverflowSafeInt<T, T_MAX, T_MIN>)a / (int)b; }
/* Sometimes we got uint operator OverflowSafeInt instead of vice versa. Handle that properly */
template <class T, int64 T_MAX, int64 T_MIN> FORCEINLINE OverflowSafeInt<T, T_MAX, T_MIN> operator + (uint a, OverflowSafeInt<T, T_MAX, T_MIN> b) { return b + a; }
template <class T, int64 T_MAX, int64 T_MIN> FORCEINLINE OverflowSafeInt<T, T_MAX, T_MIN> operator - (uint a, OverflowSafeInt<T, T_MAX, T_MIN> b) { return -b + a; }
template <class T, int64 T_MAX, int64 T_MIN> FORCEINLINE OverflowSafeInt<T, T_MAX, T_MIN> operator * (uint a, OverflowSafeInt<T, T_MAX, T_MIN> b) { return b * a; }
template <class T, int64 T_MAX, int64 T_MIN> FORCEINLINE OverflowSafeInt<T, T_MAX, T_MIN> operator / (uint a, OverflowSafeInt<T, T_MAX, T_MIN> b) { return (OverflowSafeInt<T, T_MAX, T_MIN>)a / (int)b; }
/* Sometimes we got byte operator OverflowSafeInt instead of vice versa. Handle that properly */
template <class T, int64 T_MAX, int64 T_MIN> FORCEINLINE OverflowSafeInt<T, T_MAX, T_MIN> operator + (byte a, OverflowSafeInt<T, T_MAX, T_MIN> b) { return b + a; }
template <class T, int64 T_MAX, int64 T_MIN> FORCEINLINE OverflowSafeInt<T, T_MAX, T_MIN> operator - (byte a, OverflowSafeInt<T, T_MAX, T_MIN> b) { return -b + a; }
template <class T, int64 T_MAX, int64 T_MIN> FORCEINLINE OverflowSafeInt<T, T_MAX, T_MIN> operator * (byte a, OverflowSafeInt<T, T_MAX, T_MIN> b) { return b * a; }
template <class T, int64 T_MAX, int64 T_MIN> FORCEINLINE OverflowSafeInt<T, T_MAX, T_MIN> operator / (byte a, OverflowSafeInt<T, T_MAX, T_MIN> b) { return (OverflowSafeInt<T, T_MAX, T_MIN>)a / (int)b; }
#endif /* HELPERS_HPP */

View File

@ -69,7 +69,9 @@ typedef uint16 SignID;
typedef uint16 GroupID;
typedef uint16 EngineRenewID;
typedef uint16 DestinationID;
typedef int64 Money;
typedef OverflowSafeInt<int64, INT64_MAX, INT64_MIN> OverflowSafeInt64;
typedef OverflowSafeInt64 Money;
/* DestinationID must be at least as large as every these below, because it can
* be any of them

View File

@ -267,7 +267,7 @@ static CommandCost CheckRailSlope(Slope tileh, TrackBits rail_bits, TrackBits ex
) return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
Foundation f_old = GetRailFoundation(tileh, existing);
return CommandCost(f_new != f_old ? _price.terraform : 0);
return CommandCost(f_new != f_old ? _price.terraform : (Money)0);
}
/* Validate functions for rail building */

View File

@ -366,7 +366,7 @@ static CommandCost CheckRoadSlope(Slope tileh, RoadBits* pieces, RoadBits existi
/* foundation is used. Whole tile is leveled up */
if ((~_valid_tileh_slopes_road[1][tileh] & road_bits) == ROAD_NONE) {
return CommandCost(existing != ROAD_NONE ? 0 : _price.terraform);
return CommandCost(existing != ROAD_NONE ? (Money)0 : _price.terraform);
}
/* Force straight roads. */

View File

@ -331,15 +331,15 @@ static char *FormatTinyDate(char *buff, Date date, const char* last)
static char *FormatGenericCurrency(char *buff, const CurrencySpec *spec, Money number, bool compact, const char* last)
{
const char* multiplier = "";
/* We are going to make number absolute for printing, so
* keep this piece of data as we need it later on */
bool negative = number < 0;
const char *multiplier = "";
char buf[40];
char* p;
char *p;
int j;
/* Multiply by exchange rate, but do it safely. */
CommandCost cs(number);
cs.MultiplyCost(spec->rate);
number = cs.GetCost();
number *= spec->rate;
/* convert from negative */
if (number < 0) {
@ -374,7 +374,7 @@ static char *FormatGenericCurrency(char *buff, const CurrencySpec *spec, Money n
*--p = spec->separator;
j = 3;
}
*--p = '0' + number % 10;
*--p = '0' + (char)(number % 10);
} while ((number /= 10) != 0);
buff = strecpy(buff, p, last);
@ -385,7 +385,7 @@ static char *FormatGenericCurrency(char *buff, const CurrencySpec *spec, Money n
* The only remaining value is 1 (prefix), so everything that is not 0 */
if (spec->symbol_pos != 0) buff = strecpy(buff, spec->suffix, last);
if (cs.GetCost() < 0) {
if (negative) {
if (buff + Utf8CharLen(SCC_PREVIOUS_COLOUR) > last) return buff;
buff += Utf8Encode(buff, SCC_PREVIOUS_COLOUR);
*buff = '\0';