core: add cast_int<> function

We had a pattern where doubles were converted to long with
lrint() and then down-cast to a narrower int type.

Because this is unwieldy, introduce a function encapsulating
this.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2024-09-03 09:52:12 +02:00 committed by bstoeger
parent 110e64bc66
commit 77b12bbccf
10 changed files with 34 additions and 23 deletions

View file

@ -554,7 +554,7 @@ static void match_standard_cylinder(cylinder_type_t &type)
default: default:
return; return;
} }
type.description = format_string_std(fmt, (int)lrint(cuft)); type.description = format_string_std(fmt, int_cast<int>(cuft));
} }
/* /*
@ -2439,7 +2439,7 @@ int dive::rel_mbar_to_depth(int mbar) const
/* whole mbar gives us cm precision */ /* whole mbar gives us cm precision */
double specific_weight = salinity_to_specific_weight(salinity); double specific_weight = salinity_to_specific_weight(salinity);
return (int)lrint(mbar / specific_weight); return int_cast<int>(mbar / specific_weight);
} }
int dive::mbar_to_depth(int mbar) const int dive::mbar_to_depth(int mbar) const
@ -2459,7 +2459,7 @@ int dive::mbar_to_depth(int mbar) const
depth_t dive::gas_mod(struct gasmix mix, pressure_t po2_limit, int roundto) const depth_t dive::gas_mod(struct gasmix mix, pressure_t po2_limit, int roundto) const
{ {
double depth = (double) mbar_to_depth(po2_limit.mbar * 1000 / get_o2(mix)); double depth = (double) mbar_to_depth(po2_limit.mbar * 1000 / get_o2(mix));
return depth_t { .mm = (int)lrint(depth / roundto) * roundto }; return depth_t { .mm = int_cast<int>(depth / roundto) * roundto };
} }
/* Maximum narcotic depth rounded to multiples of roundto mm */ /* Maximum narcotic depth rounded to multiples of roundto mm */
@ -2468,14 +2468,14 @@ depth_t dive::gas_mnd(struct gasmix mix, depth_t end, int roundto) const
pressure_t ppo2n2 { .mbar = depth_to_mbar(end.mm) }; pressure_t ppo2n2 { .mbar = depth_to_mbar(end.mm) };
int maxambient = prefs.o2narcotic ? int maxambient = prefs.o2narcotic ?
(int)lrint(ppo2n2.mbar / (1 - get_he(mix) / 1000.0)) int_cast<int>(ppo2n2.mbar / (1 - get_he(mix) / 1000.0))
: :
get_n2(mix) > 0 ? get_n2(mix) > 0 ?
(int)lrint(ppo2n2.mbar * N2_IN_AIR / get_n2(mix)) int_cast<int>(ppo2n2.mbar * N2_IN_AIR / get_n2(mix))
: :
// Actually: Infinity // Actually: Infinity
1000000; 1000000;
return depth_t { .mm = (int)lrint(((double)mbar_to_depth(maxambient)) / roundto) * roundto }; return depth_t { .mm = int_cast<int>(((double)mbar_to_depth(maxambient)) / roundto) * roundto };
} }
std::string dive::get_country() const std::string dive::get_country() const

View file

@ -182,7 +182,7 @@ volume_t cylinder_t::gas_volume(pressure_t p) const
{ {
double bar = p.mbar / 1000.0; double bar = p.mbar / 1000.0;
double z_factor = gas_compressibility_factor(gasmix, bar); double z_factor = gas_compressibility_factor(gasmix, bar);
return volume_t { .mliter = static_cast<int>(lrint(type.size.mliter * bar_to_atm(bar) / z_factor)) }; return volume_t { .mliter = int_cast<int>(type.size.mliter * bar_to_atm(bar) / z_factor) };
} }
int find_best_gasmix_match(struct gasmix mix, const struct cylinder_table &cylinders) int find_best_gasmix_match(struct gasmix mix, const struct cylinder_table &cylinders)
@ -348,7 +348,7 @@ void copy_cylinder_types(const struct dive *s, struct dive *d)
void fill_default_cylinder(const struct dive *dive, cylinder_t *cyl) void fill_default_cylinder(const struct dive *dive, cylinder_t *cyl)
{ {
const std::string &cyl_name = prefs.default_cylinder; const std::string &cyl_name = prefs.default_cylinder;
pressure_t pO2 = {.mbar = static_cast<int>(lrint(prefs.modpO2 * 1000.0))}; pressure_t pO2 = {.mbar = int_cast<int>(prefs.modpO2 * 1000.0)};
if (cyl_name.empty()) if (cyl_name.empty())
return; return;

View file

@ -283,7 +283,7 @@ static int display_to_base_unit(double f, enum filter_constraint_type type)
switch (desc->units) { switch (desc->units) {
case FILTER_CONSTRAINT_NO_UNIT: case FILTER_CONSTRAINT_NO_UNIT:
default: default:
return (int)lrint(f); return int_cast<int>(f);
case FILTER_CONSTRAINT_LENGTH_UNIT: case FILTER_CONSTRAINT_LENGTH_UNIT:
return prefs.units.length == units::METERS ? lrint(f * 1000.0) : feet_to_mm(f); return prefs.units.length == units::METERS ? lrint(f * 1000.0) : feet_to_mm(f);
case FILTER_CONSTRAINT_DURATION_UNIT: case FILTER_CONSTRAINT_DURATION_UNIT:

View file

@ -93,17 +93,17 @@ static weight_t get_weight(const char *line)
static pressure_t get_airpressure(const char *line) static pressure_t get_airpressure(const char *line)
{ {
return pressure_t { .mbar = static_cast<int32_t>(lrint(ascii_strtod(line, NULL))) }; return pressure_t { .mbar = int_cast<int32_t>(ascii_strtod(line, NULL)) };
} }
static pressure_t get_pressure(const char *line) static pressure_t get_pressure(const char *line)
{ {
return pressure_t { .mbar = static_cast<int32_t>(lrint(1000 * ascii_strtod(line, NULL))) }; return pressure_t { .mbar = int_cast<int32_t>(1000 * ascii_strtod(line, NULL)) };
} }
static o2pressure_t get_o2pressure(const char *line) static o2pressure_t get_o2pressure(const char *line)
{ {
return o2pressure_t { .mbar = static_cast<uint16_t>(lrint(1000 * ascii_strtod(line, NULL))) }; return o2pressure_t { .mbar = int_cast<uint16_t>(1000 * ascii_strtod(line, NULL)) };
} }
static int get_salinity(const char *line) static int get_salinity(const char *line)

View file

@ -275,8 +275,8 @@ static std::pair<volume_t, volume_t> get_gas_parts(struct gasmix mix, volume_t v
if (gasmix_is_air(mix)) if (gasmix_is_air(mix))
return { volume_t() , volume_t() }; return { volume_t() , volume_t() };
volume_t air { .mliter = (int)lrint(((double)vol.mliter * get_n2(mix)) / (1000 - o2_in_topup)) }; volume_t air { .mliter = int_cast<int>(((double)vol.mliter * get_n2(mix)) / (1000 - o2_in_topup)) };
volume_t he { .mliter = (int)lrint(((double)vol.mliter * get_he(mix)) / 1000.0) }; volume_t he { .mliter = int_cast<int>(((double)vol.mliter * get_he(mix)) / 1000.0) };
volume_t o2 { .mliter = vol.mliter - he.mliter - air.mliter }; volume_t o2 { .mliter = vol.mliter - he.mliter - air.mliter };
return std::make_pair(o2, he); return std::make_pair(o2, he);
} }

View file

@ -22,7 +22,7 @@ int get_pressure_units(int mb, const char **units)
unit = translate("gettextFromC", "bar"); unit = translate("gettextFromC", "bar");
break; break;
case units::PSI: case units::PSI:
pressure = (int)lrint(mbar_to_PSI(mb)); pressure = int_cast<int>(mbar_to_PSI(mb));
unit = translate("gettextFromC", "psi"); unit = translate("gettextFromC", "psi");
break; break;
} }

View file

@ -67,6 +67,17 @@
*/ */
using timestamp_t = int64_t; using timestamp_t = int64_t;
/*
* There is a semi-common pattern where lrint() is used to round
* doubles to long integers and then cast down to a less wide
* int. Since this is unwieldy, encapsulate this in this function
*/
template <typename INT>
INT int_cast(double v)
{
return static_cast<INT>(lrint(v));
}
// Base class for all unit types using the "Curiously recurring template pattern" // Base class for all unit types using the "Curiously recurring template pattern"
// (https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern) // (https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern)
// to implement addition, subtraction and negation. // to implement addition, subtraction and negation.
@ -190,8 +201,8 @@ static inline bool operator!=(const location_t &a, const location_t &b)
static inline location_t create_location(double lat, double lon) static inline location_t create_location(double lat, double lon)
{ {
location_t location = { location_t location = {
{ .udeg = (int) lrint(lat * 1000000) }, { .udeg = int_cast<int>(lat * 1000000) },
{ .udeg = (int) lrint(lon * 1000000) } { .udeg = int_cast<int>(lon * 1000000) }
}; };
return location; return location;
} }
@ -208,7 +219,7 @@ static inline double grams_to_lbs(int grams)
static inline int lbs_to_grams(double lbs) static inline int lbs_to_grams(double lbs)
{ {
return (int)lrint(lbs * 453.6); return int_cast<int>(lbs * 453.6);
} }
static inline double ml_to_cuft(int ml) static inline double ml_to_cuft(int ml)
@ -238,7 +249,7 @@ static inline long feet_to_mm(double feet)
static inline int to_feet(depth_t depth) static inline int to_feet(depth_t depth)
{ {
return (int)lrint(mm_to_feet(depth.mm)); return int_cast<int>(mm_to_feet(depth.mm));
} }
static inline double mkelvin_to_C(int mkelvin) static inline double mkelvin_to_C(int mkelvin)

View file

@ -1170,13 +1170,13 @@ static weight_t parseWeight(const QString &text)
return {}; return {};
double number = numOnly.toDouble(); double number = numOnly.toDouble();
if (text.contains(gettextFromC::tr("kg"), Qt::CaseInsensitive)) { if (text.contains(gettextFromC::tr("kg"), Qt::CaseInsensitive)) {
return { .grams = static_cast<int>(lrint(number * 1000)) }; return { .grams = int_cast<int>(number * 1000) };
} else if (text.contains(gettextFromC::tr("lbs"), Qt::CaseInsensitive)) { } else if (text.contains(gettextFromC::tr("lbs"), Qt::CaseInsensitive)) {
return { .grams = lbs_to_grams(number) }; return { .grams = lbs_to_grams(number) };
} else { } else {
switch (prefs.units.weight) { switch (prefs.units.weight) {
case units::KG: case units::KG:
return { .grams = static_cast<int>(lrint(number * 1000)) }; return { .grams = int_cast<int>(number * 1000) };
case units::LBS: case units::LBS:
return { .grams = lbs_to_grams(number) }; return { .grams = lbs_to_grams(number) };
default: default:

View file

@ -296,7 +296,7 @@ QVariant DivePlannerPointsModel::data(const QModelIndex &index, int role) const
case CCSETPOINT: case CCSETPOINT:
return (divemode == CCR) ? (double)(p.setpoint / 1000.0) : QVariant(); return (divemode == CCR) ? (double)(p.setpoint / 1000.0) : QVariant();
case DEPTH: case DEPTH:
return (int) lrint(get_depth_units(p.depth.mm, NULL, NULL)); return int_cast<int>(get_depth_units(p.depth.mm, NULL, NULL));
case RUNTIME: case RUNTIME:
return p.time / 60; return p.time / 60;
case DURATION: case DURATION:

View file

@ -1001,7 +1001,7 @@ void smartrak_import(const char *file, struct divelog *log)
/* No DC related data */ /* No DC related data */
smtkdive->visibility = strtod((char *)col[coln(VISIBILITY)]->bind_ptr, NULL) > 25 ? 5 : lrint(strtod((char *)col[13]->bind_ptr, NULL) / 5); smtkdive->visibility = strtod((char *)col[coln(VISIBILITY)]->bind_ptr, NULL) > 25 ? 5 : lrint(strtod((char *)col[13]->bind_ptr, NULL) / 5);
weightsystem_t ws = { { .grams = (int)lrint(strtod((char *)col[coln(WEIGHT)]->bind_ptr, NULL) * 1000)}, std::string(), false }; weightsystem_t ws = { { .grams = int_cast<int>(strtod((char *)col[coln(WEIGHT)]->bind_ptr, NULL) * 1000)}, std::string(), false };
smtkdive->weightsystems.push_back(std::move(ws)); smtkdive->weightsystems.push_back(std::move(ws));
smtkdive->suit = get(suit_list, atoi((char *)col[coln(SUITIDX)]->bind_ptr) - 1); smtkdive->suit = get(suit_list, atoi((char *)col[coln(SUITIDX)]->bind_ptr) - 1);
smtk_build_location(mdb_clon, (char *)col[coln(SITEIDX)]->bind_ptr, &smtkdive->dive_site, log); smtk_build_location(mdb_clon, (char *)col[coln(SITEIDX)]->bind_ptr, &smtkdive->dive_site, log);