Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Codechange: generify ClampTo<type> #10756

Merged
merged 5 commits into from
May 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/build_vehicle_gui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ static bool EngineCostSorter(const GUIEngineListItem &a, const GUIEngineListItem
{
Money va = Engine::Get(a.engine_id)->GetCost();
Money vb = Engine::Get(b.engine_id)->GetCost();
int r = ClampToI32(va - vb);
int r = ClampTo<int32_t>(va - vb);

/* Use EngineID to sort instead since we want consistent sorting */
if (r == 0) return EngineNumberSorter(a, b);
Expand Down Expand Up @@ -262,7 +262,7 @@ static bool EngineRunningCostSorter(const GUIEngineListItem &a, const GUIEngineL
{
Money va = Engine::Get(a.engine_id)->GetRunningCost();
Money vb = Engine::Get(b.engine_id)->GetRunningCost();
int r = ClampToI32(va - vb);
int r = ClampTo<int32_t>(va - vb);

/* Use EngineID to sort instead since we want consistent sorting */
if (r == 0) return EngineNumberSorter(a, b);
Expand Down
15 changes: 10 additions & 5 deletions src/company_cmd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,14 +268,19 @@ void SubtractMoneyFromCompanyFract(CompanyID company, const CommandCost &cst)
if (cost != 0) SubtractMoneyFromAnyCompany(c, CommandCost(cst.GetExpensesType(), cost));
}

static constexpr void UpdateLandscapingLimit(uint32_t &limit, uint64_t per_64k_frames, uint64_t burst)
{
limit = static_cast<uint32_t>(std::min<uint64_t>(limit + per_64k_frames, burst << 16));
}

/** Update the landscaping limits per company. */
void UpdateLandscapingLimits()
{
for (Company *c : Company::Iterate()) {
c->terraform_limit = std::min<uint64>((uint64)c->terraform_limit + _settings_game.construction.terraform_per_64k_frames, (uint64)_settings_game.construction.terraform_frame_burst << 16);
c->clear_limit = std::min<uint64>((uint64)c->clear_limit + _settings_game.construction.clear_per_64k_frames, (uint64)_settings_game.construction.clear_frame_burst << 16);
c->tree_limit = std::min<uint64>((uint64)c->tree_limit + _settings_game.construction.tree_per_64k_frames, (uint64)_settings_game.construction.tree_frame_burst << 16);
c->build_object_limit = std::min<uint64>((uint64)c->build_object_limit + _settings_game.construction.build_object_per_64k_frames, (uint64)_settings_game.construction.build_object_frame_burst << 16);
UpdateLandscapingLimit(c->terraform_limit, _settings_game.construction.terraform_per_64k_frames, _settings_game.construction.terraform_frame_burst);
UpdateLandscapingLimit(c->clear_limit, _settings_game.construction.clear_per_64k_frames, _settings_game.construction.clear_frame_burst);
UpdateLandscapingLimit(c->tree_limit, _settings_game.construction.tree_per_64k_frames, _settings_game.construction.tree_frame_burst);
UpdateLandscapingLimit(c->build_object_limit, _settings_game.construction.build_object_per_64k_frames, _settings_game.construction.build_object_frame_burst);
}
}

Expand Down Expand Up @@ -1182,7 +1187,7 @@ uint32 CompanyInfrastructure::GetTramTotal() const
* @param dest_company the company to transfer the money to
* @return the cost of this operation or an error
*/
CommandCost CmdGiveMoney(DoCommandFlag flags, uint32 money, CompanyID dest_company)
CommandCost CmdGiveMoney(DoCommandFlag flags, Money money, CompanyID dest_company)
{
if (!_settings_game.economy.give_money) return CMD_ERROR;

Expand Down
2 changes: 1 addition & 1 deletion src/company_cmd.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ enum ClientID : uint32;
enum Colours : byte;

CommandCost CmdCompanyCtrl(DoCommandFlag flags, CompanyCtrlAction cca, CompanyID company_id, CompanyRemoveReason reason, ClientID client_id);
CommandCost CmdGiveMoney(DoCommandFlag flags, uint32 money, CompanyID dest_company);
CommandCost CmdGiveMoney(DoCommandFlag flags, Money money, CompanyID dest_company);
CommandCost CmdRenameCompany(DoCommandFlag flags, const std::string &text);
CommandCost CmdRenamePresident(DoCommandFlag flags, const std::string &text);
CommandCost CmdSetCompanyManagerFace(DoCommandFlag flags, CompanyManagerFace cmf);
Expand Down
6 changes: 2 additions & 4 deletions src/company_gui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2650,10 +2650,8 @@ struct CompanyWindow : Window
default: NOT_REACHED();

case WID_C_GIVE_MONEY: {
Money money = (Money)(std::strtoull(str, nullptr, 10) / _currency->rate);
uint32 money_c = Clamp(ClampToI32(money), 0, 20000000); // Clamp between 20 million and 0

Command<CMD_GIVE_MONEY>::Post(STR_ERROR_CAN_T_GIVE_MONEY, money_c, (CompanyID)this->window_number);
Money money = std::strtoull(str, nullptr, 10) / _currency->rate;
Command<CMD_GIVE_MONEY>::Post(STR_ERROR_CAN_T_GIVE_MONEY, money, (CompanyID)this->window_number);
break;
}

Expand Down
82 changes: 56 additions & 26 deletions src/core/math_func.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
#ifndef MATH_FUNC_HPP
#define MATH_FUNC_HPP

#include <limits>
#include <type_traits>

/**
* Returns the absolute value of (scalar) variable.
*
Expand Down Expand Up @@ -125,38 +128,65 @@ static inline uint ClampU(const uint a, const uint min, const uint max)
}

/**
* Reduce a signed 64-bit int to a signed 32-bit one
* Clamp the given value down to lie within the requested type.
*
* This function clamps a 64-bit integer to a 32-bit integer.
* If the 64-bit value is smaller than the smallest 32-bit integer
* value 0x80000000 this value is returned (the left one bit is the sign bit).
* If the 64-bit value is greater than the greatest 32-bit integer value 0x7FFFFFFF
* this value is returned. In all other cases the 64-bit value 'fits' in a
* 32-bits integer field and so the value is casted to int32 and returned.
* For example ClampTo<uint8_t> will return a value clamped to the range of 0
* to 255. Anything smaller will become 0, anything larger will become 255.
*
* @param a The 64-bit value to clamps
* @return The 64-bit value reduced to a 32-bit value
* @param a The 64-bit value to clamp.
* @return The 64-bit value reduced to a value within the given allowed range
* for the return type.
* @see Clamp(int, int, int)
*/
static inline int32 ClampToI32(const int64 a)
template <typename To, typename From>
constexpr To ClampTo(From value)
{
return static_cast<int32>(Clamp<int64>(a, INT32_MIN, INT32_MAX));
}
static_assert(std::numeric_limits<To>::is_integer, "Do not clamp from non-integer values");
static_assert(std::numeric_limits<From>::is_integer, "Do not clamp to non-integer values");

/**
* Reduce an unsigned 64-bit int to an unsigned 16-bit one
*
* @param a The 64-bit value to clamp
* @return The 64-bit value reduced to a 16-bit value
* @see ClampU(uint, uint, uint)
*/
static inline uint16 ClampToU16(const uint64 a)
{
/* MSVC thinks, in its infinite wisdom, that int min(int, int) is a better
* match for min(uint64, uint) than uint64 min(uint64, uint64). As such we
* need to cast the UINT16_MAX to prevent MSVC from displaying its
* infinite loads of warnings. */
return static_cast<uint16>(std::min(a, static_cast<uint64>(UINT16_MAX)));
if (sizeof(To) >= sizeof(From) && std::numeric_limits<To>::is_signed == std::numeric_limits<From>::is_signed) {
/* Same signedness and To type is larger or equal than From type, no clamping is required. */
return static_cast<To>(value);
}

if (sizeof(To) > sizeof(From) && std::numeric_limits<To>::is_signed) {
/* Signed destination and a larger To type, no clamping is required. */
return static_cast<To>(value);
}

/* Get the bigger of the two types based on essentially the number of bits. */
using BiggerType = typename std::conditional<sizeof(From) >= sizeof(To), From, To>::type;

if constexpr (std::numeric_limits<To>::is_signed) {
/* The output is a signed number. */
if constexpr (std::numeric_limits<From>::is_signed) {
/* Both input and output are signed. */
return static_cast<To>(std::clamp<BiggerType>(value,
std::numeric_limits<To>::lowest(), std::numeric_limits<To>::max()));
}

/* The input is unsigned, so skip the minimum check and use unsigned variant of the biggest type as intermediate type. */
using BiggerUnsignedType = typename std::make_unsigned<BiggerType>::type;
return static_cast<To>(std::min<BiggerUnsignedType>(std::numeric_limits<To>::max(), value));
}

/* The output is unsigned. */

if constexpr (std::numeric_limits<From>::is_signed) {
/* Input is signed; account for the negative numbers in the input. */
if constexpr (sizeof(To) >= sizeof(From)) {
/* If the output type is larger or equal to the input type, then only clamp the negative numbers. */
return static_cast<To>(std::max<From>(value, 0));
}

/* The output type is smaller than the input type. */
using BiggerSignedType = typename std::make_signed<BiggerType>::type;
return static_cast<To>(std::clamp<BiggerSignedType>(value,
std::numeric_limits<To>::lowest(), std::numeric_limits<To>::max()));
}

/* The input and output are unsigned, just clamp at the high side. */
return static_cast<To>(std::min<BiggerType>(value, std::numeric_limits<To>::max()));
}

/**
Expand Down
4 changes: 4 additions & 0 deletions src/core/overflowsafe_type.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,10 @@ static_assert(OverflowSafeInt32(INT32_MAX) + 1 == OverflowSafeInt32(INT32_MAX));
static_assert(OverflowSafeInt32(INT32_MAX) * 2 == OverflowSafeInt32(INT32_MAX));
static_assert(OverflowSafeInt32(INT32_MIN) * 2 == OverflowSafeInt32(INT32_MIN));

/* Specialisation of the generic ClampTo function for overflow safe integers to normal integers. */
template <typename To, typename From>
constexpr To ClampTo(OverflowSafeInt<From> value) { return ClampTo<To>(From(value)); }

#undef HAS_OVERFLOW_BUILTINS

#endif /* OVERFLOWSAFE_TYPE_HPP */
8 changes: 4 additions & 4 deletions src/economy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -938,7 +938,7 @@ Money GetTransportedGoodsIncome(uint num_pieces, uint dist, uint16 transit_days,

/* Use callback to calculate cargo profit, if available */
if (HasBit(cs->callback_mask, CBM_CARGO_PROFIT_CALC)) {
uint32 var18 = std::min(dist, 0xFFFFu) | (std::min(num_pieces, 0xFFu) << 16) | (std::min<uint16>(transit_days, 0xFFu) << 24);
uint32 var18 = ClampTo<uint16_t>(dist) | (ClampTo<uint8_t>(num_pieces) << 16) | (ClampTo<uint8_t>(transit_days) << 24);
uint16 callback = GetCargoCallback(CBID_CARGO_PROFIT_CALC, 0, var18, cs);
if (callback != CALLBACK_FAILED) {
int result = GB(callback, 0, 14);
Expand Down Expand Up @@ -1126,7 +1126,7 @@ static void TriggerIndustryProduction(Industry *i)
if (cargo_waiting == 0) continue;

for (uint ci_out = 0; ci_out < lengthof(i->produced_cargo_waiting); ci_out++) {
i->produced_cargo_waiting[ci_out] = std::min(i->produced_cargo_waiting[ci_out] + (cargo_waiting * indspec->input_cargo_multiplier[ci_in][ci_out] / 256), 0xFFFFu);
i->produced_cargo_waiting[ci_out] = ClampTo<uint16_t>(i->produced_cargo_waiting[ci_out] + (cargo_waiting * indspec->input_cargo_multiplier[ci_in][ci_out] / 256));
}

i->incoming_cargo_waiting[ci_in] = 0;
Expand Down Expand Up @@ -1728,8 +1728,8 @@ static void LoadUnloadVehicle(Vehicle *front)
}

/* if last speed is 0, we treat that as if no vehicle has ever visited the station. */
ge->last_speed = std::min(t, 255);
ge->last_age = std::min(TimerGameCalendar::year - front->build_year, 255);
ge->last_speed = ClampTo<uint8_t>(t);
ge->last_age = ClampTo<uint8_t>(TimerGameCalendar::year - front->build_year);

assert(v->cargo_cap >= v->cargo.StoredCount());
/* Capacity available for loading more cargo. */
Expand Down
4 changes: 2 additions & 2 deletions src/ground_vehicle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,10 +175,10 @@ int GroundVehicle<T, Type>::GetAcceleration() const
* down hill will never slow down enough, and a vehicle that came up
* a hill will never speed up enough to (eventually) get back to the
* same (maximum) speed. */
int accel = ClampToI32((force - resistance) / (mass * 4));
int accel = ClampTo<int32_t>((force - resistance) / (mass * 4));
return force < resistance ? std::min(-1, accel) : std::max(1, accel);
} else {
return ClampToI32(std::min<int64>(-force - resistance, -10000) / mass);
return ClampTo<int32_t>(std::min<int64>(-force - resistance, -10000) / mass);
}
}

Expand Down
10 changes: 5 additions & 5 deletions src/group_gui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -606,13 +606,13 @@ class VehicleGroupWindow : public BaseVehicleListWindow {

case WID_GL_LIST_GROUP: {
int y1 = r.top;
int max = std::min<size_t>(this->group_sb->GetPosition() + this->group_sb->GetCapacity(), this->groups.size());
for (int i = this->group_sb->GetPosition(); i < max; ++i) {
size_t max = std::min<size_t>(this->group_sb->GetPosition() + this->group_sb->GetCapacity(), this->groups.size());
for (size_t i = this->group_sb->GetPosition(); i < max; ++i) {
const Group *g = this->groups[i];

assert(g->owner == this->owner);

DrawGroupInfo(y1, r.left, r.right, g->index, this->indents[i] * WidgetDimensions::scaled.hsep_indent, HasBit(g->flags, GroupFlags::GF_REPLACE_PROTECTION), g->folded || (i + 1 < (int)this->groups.size() && indents[i + 1] > this->indents[i]));
DrawGroupInfo(y1, r.left, r.right, g->index, this->indents[i] * WidgetDimensions::scaled.hsep_indent, HasBit(g->flags, GroupFlags::GF_REPLACE_PROTECTION), g->folded || (i + 1 < this->groups.size() && indents[i + 1] > this->indents[i]));

y1 += this->tiny_step_height;
}
Expand All @@ -630,8 +630,8 @@ class VehicleGroupWindow : public BaseVehicleListWindow {
if (this->vli.index != ALL_GROUP && this->grouping == GB_NONE) {
/* Mark vehicles which are in sub-groups (only if we are not using shared order coalescing) */
Rect mr = r.WithHeight(this->resize.step_height);
uint max = static_cast<uint>(std::min<size_t>(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->vehgroups.size()));
for (uint i = this->vscroll->GetPosition(); i < max; ++i) {
size_t max = std::min<size_t>(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->vehgroups.size());
for (size_t i = this->vscroll->GetPosition(); i < max; ++i) {
const Vehicle *v = this->vehgroups[i].GetSingleVehicle();
if (v->group_id != this->vli.index) {
GfxFillRect(mr.Shrink(WidgetDimensions::scaled.bevel), _colour_gradient[COLOUR_GREY][3], FILLRECT_CHECKER);
Expand Down
2 changes: 1 addition & 1 deletion src/highscore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ void SaveToHighScore()
for (i = 0; i < SP_SAVED_HIGHSCORE_END; i++) {
for (hs = _highscore_table[i]; hs != endof(_highscore_table[i]); hs++) {
/* First character is a command character, so strlen will fail on that */
byte length = std::min(sizeof(hs->company), StrEmpty(hs->company) ? 0 : strlen(&hs->company[1]) + 1);
byte length = ClampTo<byte>(std::min(sizeof(hs->company), StrEmpty(hs->company) ? 0 : strlen(&hs->company[1]) + 1));
rubidium42 marked this conversation as resolved.
Show resolved Hide resolved

if (fwrite(&length, sizeof(length), 1, fp) != 1 || // write away string length
fwrite(hs->company, length, 1, fp) > 1 || // Yes... could be 0 bytes too
Expand Down
12 changes: 6 additions & 6 deletions src/industry_cmd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,7 @@ static bool TransportIndustryGoods(TileIndex tile)
bool moved_cargo = false;

for (uint j = 0; j < lengthof(i->produced_cargo_waiting); j++) {
uint cw = std::min<uint>(i->produced_cargo_waiting[j], 255u);
uint cw = ClampTo<uint8_t>(i->produced_cargo_waiting[j]);
if (cw > indspec->minimal_cargo && i->produced_cargo[j] != CT_INVALID) {
i->produced_cargo_waiting[j] -= cw;

Expand Down Expand Up @@ -1142,7 +1142,7 @@ static void ChopLumberMillTrees(Industry *i)

TileIndex tile = i->location.tile;
if (CircularTileSearch(&tile, 40, SearchLumberMillTrees, nullptr)) { // 40x40 tiles to search.
i->produced_cargo_waiting[0] = std::min(0xffff, i->produced_cargo_waiting[0] + 45); // Found a tree, add according value to waiting cargo.
i->produced_cargo_waiting[0] = ClampTo<uint16_t>(i->produced_cargo_waiting[0] + 45); // Found a tree, add according value to waiting cargo.
}
}

Expand Down Expand Up @@ -1174,7 +1174,7 @@ static void ProduceIndustryGoods(Industry *i)

IndustryBehaviour indbehav = indsp->behaviour;
for (size_t j = 0; j < lengthof(i->produced_cargo_waiting); j++) {
i->produced_cargo_waiting[j] = std::min(0xffff, i->produced_cargo_waiting[j] + i->production_rate[j]);
i->produced_cargo_waiting[j] = ClampTo<uint16_t>(i->produced_cargo_waiting[j] + i->production_rate[j]);
}

if ((indbehav & INDUSTRYBEH_PLANT_FIELDS) != 0) {
Expand Down Expand Up @@ -1785,7 +1785,7 @@ static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type,
/* Randomize inital production if non-original economy is used and there are no production related callbacks. */
if (!indspec->UsesOriginalEconomy()) {
for (size_t ci = 0; ci < lengthof(i->production_rate); ci++) {
i->production_rate[ci] = std::min((RandomRange(256) + 128) * i->production_rate[ci] >> 8, 255u);
i->production_rate[ci] = ClampTo<byte>((RandomRange(256) + 128) * i->production_rate[ci] >> 8);
}
}

Expand Down Expand Up @@ -2423,7 +2423,7 @@ static void UpdateIndustryStatistics(Industry *i)
byte pct = 0;
if (i->this_month_production[j] != 0) {
i->last_prod_year = TimerGameCalendar::year;
pct = std::min(i->this_month_transported[j] * 256 / i->this_month_production[j], 255);
pct = ClampTo<byte>(i->this_month_transported[j] * 256 / i->this_month_production[j]);
}
i->last_month_pct_transported[j] = pct;

Expand All @@ -2447,7 +2447,7 @@ void Industry::RecomputeProductionMultipliers()

/* Rates are rounded up, so e.g. oilrig always produces some passengers */
for (size_t i = 0; i < lengthof(this->production_rate); i++) {
this->production_rate[i] = std::min(CeilDiv(indspec->production_rate[i] * this->prod_level, PRODLEVEL_DEFAULT), 0xFFu);
this->production_rate[i] = ClampTo<byte>(CeilDiv(indspec->production_rate[i] * this->prod_level, PRODLEVEL_DEFAULT));
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/industry_gui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1037,10 +1037,10 @@ class IndustryViewWindow : public Window
case EA_MULTIPLIER:
if (decrease) {
if (i->prod_level <= PRODLEVEL_MINIMUM) return;
i->prod_level = std::max<uint>(i->prod_level / 2, PRODLEVEL_MINIMUM);
i->prod_level = static_cast<byte>(std::max<uint>(i->prod_level / 2, PRODLEVEL_MINIMUM));
} else {
if (i->prod_level >= PRODLEVEL_MAXIMUM) return;
i->prod_level = std::min<uint>(i->prod_level * 2, PRODLEVEL_MAXIMUM);
i->prod_level = static_cast<byte>(std::min<uint>(i->prod_level * 2, PRODLEVEL_MAXIMUM));
}
break;

Expand All @@ -1052,7 +1052,7 @@ class IndustryViewWindow : public Window
if (i->production_rate[line - IL_RATE1] >= 255) return;
/* a zero production industry is unlikely to give anything but zero, so push it a little bit */
int new_prod = i->production_rate[line - IL_RATE1] == 0 ? 1 : i->production_rate[line - IL_RATE1] * 2;
i->production_rate[line - IL_RATE1] = std::min<uint>(new_prod, 255);
i->production_rate[line - IL_RATE1] = ClampTo<byte>(new_prod);
}
break;

Expand Down
2 changes: 1 addition & 1 deletion src/newgrf_airport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ void AirportOverrideManager::SetEntitySpec(AirportSpec *as)
case 0x7C: return (this->st->airport.psa != nullptr) ? this->st->airport.psa->GetValue(parameter) : 0;

case 0xF0: return this->st->facilities;
case 0xFA: return Clamp(this->st->build_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 65535);
case 0xFA: return ClampTo<uint16_t>(this->st->build_date - DAYS_TILL_ORIGINAL_BASE_YEAR);
}

return this->st->GetNewGRFVariable(this->ro, variable, parameter, available);
Expand Down
2 changes: 1 addition & 1 deletion src/newgrf_commons.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ uint32 GetNearbyTileInformation(TileIndex tile, bool grf_version8)
/* Return 0 if the tile is a land tile */
byte terrain_type = (HasTileWaterClass(tile) ? (GetWaterClass(tile) + 1) & 3 : 0) << 5 | GetTerrainType(tile) << 2 | (tile_type == MP_WATER ? 1 : 0) << 1;
if (grf_version8) z /= TILE_HEIGHT;
return tile_type << 24 | Clamp(z, 0, 0xFF) << 16 | terrain_type << 8 | tileh;
return tile_type << 24 | ClampTo<uint8_t>(z) << 16 | terrain_type << 8 | tileh;
}

/**
Expand Down