mirror of
https://github.com/subsurface/subsurface.git
synced 2025-02-19 22:16:15 +00:00
core: add CRTP base class to unit types
The goal here is to add general addition and scalar multiplication functions to the unit types. Thereto, we need a CRTP (https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern) base class. However, this breaks compound initialization, so we have to use named initializers: weight_t { 2000 } -> weight_t { .grams = 2000 } The good thing is that this is exactly how these classes were supposed to be used: make the unit explicit! Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
parent
696ba61eef
commit
12ca172a9e
26 changed files with 127 additions and 138 deletions
|
|
@ -618,7 +618,7 @@ static void wlog_compl_parser(std::string &wl_mem, struct dive *dt_dive, int dco
|
|||
*/
|
||||
tmp = (int) two_bytes_to_int(runner[pos_weight + 1], runner[pos_weight]);
|
||||
if (tmp != 0x7fff) {
|
||||
weightsystem_t ws = { {tmp * 10}, translate("gettextFromC", "unknown"), false };
|
||||
weightsystem_t ws = { {.grams = tmp * 10}, translate("gettextFromC", "unknown"), false };
|
||||
dt_dive->weightsystems.push_back(std::move(ws));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2248,7 +2248,7 @@ duration_t dive::totaltime() const
|
|||
time = dc_time;
|
||||
}
|
||||
}
|
||||
return { time };
|
||||
return { .seconds = time };
|
||||
}
|
||||
|
||||
timestamp_t dive::endtime() const
|
||||
|
|
@ -2367,7 +2367,7 @@ bool dive::cache_is_valid() const
|
|||
pressure_t dive::get_surface_pressure() const
|
||||
{
|
||||
return surface_pressure.mbar > 0 ? surface_pressure
|
||||
: pressure_t { SURFACE_PRESSURE };
|
||||
: pressure_t { .mbar = SURFACE_PRESSURE };
|
||||
}
|
||||
|
||||
/* This returns the conversion factor that you need to multiply
|
||||
|
|
@ -2459,13 +2459,13 @@ int dive::mbar_to_depth(int mbar) 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));
|
||||
return depth_t { (int)lrint(depth / roundto) * roundto };
|
||||
return depth_t { .mm = (int)lrint(depth / roundto) * roundto };
|
||||
}
|
||||
|
||||
/* Maximum narcotic depth rounded to multiples of roundto mm */
|
||||
depth_t dive::gas_mnd(struct gasmix mix, depth_t end, int roundto) const
|
||||
{
|
||||
pressure_t ppo2n2 { depth_to_mbar(end.mm) };
|
||||
pressure_t ppo2n2 { .mbar = depth_to_mbar(end.mm) };
|
||||
|
||||
int maxambient = prefs.o2narcotic ?
|
||||
(int)lrint(ppo2n2.mbar / (1 - get_he(mix) / 1000.0))
|
||||
|
|
@ -2475,7 +2475,7 @@ depth_t dive::gas_mnd(struct gasmix mix, depth_t end, int roundto) const
|
|||
:
|
||||
// Actually: Infinity
|
||||
1000000;
|
||||
return depth_t { (int)lrint(((double)mbar_to_depth(maxambient)) / roundto) * roundto };
|
||||
return depth_t { .mm = (int)lrint(((double)mbar_to_depth(maxambient)) / roundto) * roundto };
|
||||
}
|
||||
|
||||
std::string dive::get_country() const
|
||||
|
|
@ -2677,7 +2677,7 @@ temperature_t dive::dc_watertemp() const
|
|||
}
|
||||
if (!nr)
|
||||
return temperature_t();
|
||||
return temperature_t{ static_cast<uint32_t>((sum + nr / 2) / nr) };
|
||||
return temperature_t{ .mkelvin = static_cast<uint32_t>((sum + nr / 2) / nr) };
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -2695,7 +2695,7 @@ temperature_t dive::dc_airtemp() const
|
|||
}
|
||||
if (!nr)
|
||||
return temperature_t();
|
||||
return temperature_t{ static_cast<uint32_t>((sum + nr / 2) / nr) };
|
||||
return temperature_t{ .mkelvin = static_cast<uint32_t>((sum + nr / 2) / nr) };
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -2782,5 +2782,5 @@ weight_t dive::total_weight() const
|
|||
// TODO: implement addition for units.h types
|
||||
return std::accumulate(weightsystems.begin(), weightsystems.end(), weight_t(),
|
||||
[] (weight_t w, const weightsystem_t &ws)
|
||||
{ return weight_t{ w.grams + ws.weight.grams }; });
|
||||
{ return weight_t{ .grams = w.grams + ws.weight.grams }; });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -112,9 +112,9 @@ void set_tank_info_data(std::vector<tank_info> &table, const std::string &name,
|
|||
std::pair<volume_t, pressure_t> extract_tank_info(const struct tank_info &info)
|
||||
{
|
||||
pressure_t working_pressure {
|
||||
static_cast<int32_t>(info.bar != 0 ? info.bar * 1000 : psi_to_mbar(info.psi))
|
||||
.mbar = static_cast<int32_t>(info.bar != 0 ? info.bar * 1000 : psi_to_mbar(info.psi))
|
||||
};
|
||||
volume_t size { 0 };
|
||||
volume_t size;
|
||||
if (info.ml != 0)
|
||||
size.mliter = info.ml;
|
||||
else if (working_pressure.mbar != 0)
|
||||
|
|
@ -128,7 +128,7 @@ std::pair<volume_t, pressure_t> get_tank_info_data(const std::vector<tank_info>
|
|||
auto it = std::find_if(table.begin(), table.end(), [&name](const tank_info &info)
|
||||
{ return info.name == name; });
|
||||
return it != table.end() ? extract_tank_info(*it)
|
||||
: std::make_pair(volume_t{0}, pressure_t{0});
|
||||
: std::make_pair(volume_t(), pressure_t());
|
||||
}
|
||||
|
||||
void add_cylinder_description(const cylinder_type_t &type)
|
||||
|
|
@ -182,7 +182,7 @@ volume_t cylinder_t::gas_volume(pressure_t p) const
|
|||
{
|
||||
double bar = p.mbar / 1000.0;
|
||||
double z_factor = gas_compressibility_factor(gasmix, bar);
|
||||
return volume_t { static_cast<int>(lrint(type.size.mliter * bar_to_atm(bar) / z_factor)) };
|
||||
return volume_t { .mliter = static_cast<int>(lrint(type.size.mliter * bar_to_atm(bar) / z_factor)) };
|
||||
}
|
||||
|
||||
int find_best_gasmix_match(struct gasmix mix, const struct cylinder_table &cylinders)
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ struct gasmix {
|
|||
fraction_t he;
|
||||
std::string name() const;
|
||||
};
|
||||
static const struct gasmix gasmix_invalid = { { -1 }, { -1 } };
|
||||
static const struct gasmix gasmix_air = { { 0 }, { 0 } };
|
||||
static const struct gasmix gasmix_invalid = { { .permille = -1 }, { .permille = -1 } };
|
||||
static const struct gasmix gasmix_air = { { .permille = 0 }, { .permille = 0 } };
|
||||
|
||||
enum gastype {
|
||||
GASTYPE_AIR,
|
||||
|
|
|
|||
|
|
@ -217,7 +217,7 @@ Thumbnailer::Thumbnail Thumbnailer::getVideoThumbnailFromStream(QDataStream &str
|
|||
// is not repeated ad-nauseum for broken images.
|
||||
if (numPics == 0 && prefs.extract_video_thumbnails) {
|
||||
QMetaObject::invokeMethod(VideoFrameExtractor::instance(), "extract", Qt::AutoConnection,
|
||||
Q_ARG(QString, filename), Q_ARG(QString, filename), Q_ARG(duration_t, duration_t{(int32_t)duration}));
|
||||
Q_ARG(QString, filename), Q_ARG(QString, filename), Q_ARG(duration_t, duration_t{ .seconds = (int32_t)duration}));
|
||||
}
|
||||
|
||||
// Currently, we support only one picture
|
||||
|
|
@ -231,7 +231,7 @@ Thumbnailer::Thumbnail Thumbnailer::getVideoThumbnailFromStream(QDataStream &str
|
|||
res = videoImage; // No picture -> show dummy-icon
|
||||
else
|
||||
markVideoThumbnail(res); // We got an image -> place our video marker on top of it
|
||||
return { res, MEDIATYPE_VIDEO, { (int32_t)duration } };
|
||||
return { res, MEDIATYPE_VIDEO, { .seconds = (int32_t)duration } };
|
||||
}
|
||||
|
||||
// Fetch a thumbnail from cache.
|
||||
|
|
|
|||
|
|
@ -309,7 +309,7 @@ static int divinglog_dive(void *param, int, char **data, char **)
|
|||
state->cur_dive->watertemp.mkelvin = C_to_mkelvin(atol(data[9]));
|
||||
|
||||
if (data[10]) {
|
||||
weightsystem_t ws = { { atoi(data[10]) * 1000 }, translate("gettextFromC", "unknown"), false };
|
||||
weightsystem_t ws = { { .grams = atoi(data[10]) * 1000 }, translate("gettextFromC", "unknown"), false };
|
||||
state->cur_dive->weightsystems.push_back(std::move(ws));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@ static dc_status_t parse_gasmixes(device_data_t *devdata, struct dive *dive, dc_
|
|||
}
|
||||
}
|
||||
bool no_volume = true;
|
||||
struct gasmix bottom_gas = { {1000}, {0} }; /* Default to pure O2, or air if there are no mixes defined */
|
||||
struct gasmix bottom_gas = { { .permille = 1000}, {} }; /* Default to pure O2, or air if there are no mixes defined */
|
||||
if (ngases == 0) {
|
||||
bottom_gas = gasmix_air;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ preferences::preferences() :
|
|||
ascratestops(9000 / 60),
|
||||
ascrate50(9000 / 60),
|
||||
ascrate75(9000 / 60),
|
||||
bestmixend({ 30000 }),
|
||||
bestmixend({ .mm = 30'000 }),
|
||||
bottompo2(1400),
|
||||
bottomsac(20000),
|
||||
decopo2(1600),
|
||||
|
|
|
|||
|
|
@ -1504,8 +1504,8 @@ std::vector<std::string> compare_samples(const struct dive *d, const struct plot
|
|||
const cylinder_t *cyl = d->get_cylinder(cylinder_index);
|
||||
|
||||
// TODO: Implement addition/subtraction on units.h types
|
||||
volumes_used[cylinder_index] += cyl->gas_volume((pressure_t){ last_pressures[cylinder_index] }).mliter -
|
||||
cyl->gas_volume((pressure_t){ next_pressure }).mliter;
|
||||
volumes_used[cylinder_index] += cyl->gas_volume((pressure_t){ .mbar = last_pressures[cylinder_index] }).mliter -
|
||||
cyl->gas_volume((pressure_t){ .mbar = next_pressure }).mliter;
|
||||
}
|
||||
|
||||
// check if the gas in this cylinder is being used
|
||||
|
|
|
|||
|
|
@ -786,33 +786,6 @@ int parseTemperatureToMkelvin(const QString &text)
|
|||
return mkelvin;
|
||||
}
|
||||
|
||||
int parseWeightToGrams(const QString &text)
|
||||
{
|
||||
int grams;
|
||||
QString numOnly = text;
|
||||
numOnly.replace(",", ".").remove(QRegularExpression("[^0-9.]"));
|
||||
if (numOnly.isEmpty())
|
||||
return 0;
|
||||
double number = numOnly.toDouble();
|
||||
if (text.contains(gettextFromC::tr("kg"), Qt::CaseInsensitive)) {
|
||||
grams = lrint(number * 1000);
|
||||
} else if (text.contains(gettextFromC::tr("lbs"), Qt::CaseInsensitive)) {
|
||||
grams = lbs_to_grams(number);
|
||||
} else {
|
||||
switch (prefs.units.weight) {
|
||||
case units::KG:
|
||||
grams = lrint(number * 1000);
|
||||
break;
|
||||
case units::LBS:
|
||||
grams = lbs_to_grams(number);
|
||||
break;
|
||||
default:
|
||||
grams = 0;
|
||||
}
|
||||
}
|
||||
return grams;
|
||||
}
|
||||
|
||||
int parsePressureToMbar(const QString &text)
|
||||
{
|
||||
int mbar;
|
||||
|
|
|
|||
|
|
@ -69,7 +69,6 @@ timestamp_t dateTimeToTimestamp(const QDateTime &t);
|
|||
int parseDurationToSeconds(const QString &text);
|
||||
int parseLengthToMm(const QString &text);
|
||||
int parseTemperatureToMkelvin(const QString &text);
|
||||
int parseWeightToGrams(const QString &text);
|
||||
int parsePressureToMbar(const QString &text);
|
||||
int parseGasMixO2(const QString &text);
|
||||
int parseGasMixHE(const QString &text);
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ struct sample // BASE TYPE BYTES UNITS RANGE
|
|||
{ // --------- ----- ----- ----- -----------
|
||||
duration_t time; // int32_t 4 seconds (0-34 yrs) elapsed dive time up to this sample
|
||||
duration_t stoptime; // int32_t 4 seconds (0-34 yrs) time duration of next deco stop
|
||||
duration_t ndl = { -1 }; // int32_t 4 seconds (-1 no val, 0-34 yrs) time duration before no-deco limit
|
||||
duration_t ndl = { .seconds = -1 };// int32_t 4 seconds (-1 no val, 0-34 yrs) time duration before no-deco limit
|
||||
duration_t tts; // int32_t 4 seconds (0-34 yrs) time duration to reach the surface
|
||||
duration_t rbt; // int32_t 4 seconds (0-34 yrs) remaining bottom time
|
||||
depth_t depth; // int32_t 4 mm (0-2000 km) dive depth of this sample
|
||||
|
|
@ -21,7 +21,7 @@ struct sample // BASE TYPE BYTES UNITS RANGE
|
|||
pressure_t pressure[MAX_SENSORS]; // int32_t 2x4 mbar (0-2 Mbar) cylinder pressures (main and CCR o2)
|
||||
o2pressure_t setpoint; // uint16_t 2 mbar (0-65 bar) O2 partial pressure (will be setpoint)
|
||||
o2pressure_t o2sensor[MAX_O2_SENSORS];// uint16_t 6x2 mbar (0-65 bar) Up to 6 PO2 sensor values (rebreather)
|
||||
bearing_t bearing = { -1 }; // int16_t 2 degrees (-1 no val, 0-360 deg) compass bearing
|
||||
bearing_t bearing = { .degrees = -1 };// int16_t 2 degrees (-1 no val, 0-360 deg) compass bearing
|
||||
int16_t sensor[MAX_SENSORS] = {}; // int16_t 2x2 sensorID (0-16k) ID of cylinder pressure sensor
|
||||
uint16_t cns = 0; // uint16_t 2 % (0-64k %) cns% accumulated
|
||||
uint8_t heartbeat = 0; // uint8_t 1 beats/m (0-255) heart rate measurement
|
||||
|
|
|
|||
|
|
@ -275,9 +275,9 @@ static std::pair<volume_t, volume_t> get_gas_parts(struct gasmix mix, volume_t v
|
|||
if (gasmix_is_air(mix))
|
||||
return { volume_t() , volume_t() };
|
||||
|
||||
volume_t air = { (int)lrint(((double)vol.mliter * get_n2(mix)) / (1000 - o2_in_topup)) };
|
||||
volume_t he = { (int)lrint(((double)vol.mliter * get_he(mix)) / 1000.0) };
|
||||
volume_t o2 = { vol.mliter - he.mliter - air.mliter };
|
||||
volume_t air { .mliter = (int)lrint(((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 o2 { .mliter = vol.mliter - he.mliter - air.mliter };
|
||||
return std::make_pair(o2, he);
|
||||
}
|
||||
|
||||
|
|
|
|||
34
core/units.h
34
core/units.h
|
|
@ -67,62 +67,66 @@
|
|||
*/
|
||||
using timestamp_t = int64_t;
|
||||
|
||||
struct duration_t
|
||||
template <typename T>
|
||||
struct unit_base {
|
||||
};
|
||||
|
||||
struct duration_t : public unit_base<duration_t>
|
||||
{
|
||||
int32_t seconds = 0; // durations up to 34 yrs
|
||||
};
|
||||
|
||||
struct offset_t
|
||||
struct offset_t : public unit_base<offset_t>
|
||||
{
|
||||
int32_t seconds = 0; // offsets up to +/- 34 yrs
|
||||
};
|
||||
|
||||
struct depth_t // depth to 2000 km
|
||||
struct depth_t : public unit_base<depth_t> // depth to 2000 km
|
||||
{
|
||||
int32_t mm = 0;
|
||||
};
|
||||
|
||||
struct pressure_t
|
||||
struct pressure_t : public unit_base<pressure_t>
|
||||
{
|
||||
int32_t mbar = 0; // pressure up to 2000 bar
|
||||
};
|
||||
|
||||
struct o2pressure_t
|
||||
struct o2pressure_t : public unit_base<o2pressure_t>
|
||||
{
|
||||
uint16_t mbar = 0;
|
||||
};
|
||||
|
||||
struct bearing_t
|
||||
struct bearing_t : public unit_base<bearing_t>
|
||||
{
|
||||
int16_t degrees = 0;
|
||||
};
|
||||
|
||||
struct temperature_t
|
||||
struct temperature_t : public unit_base<temperature_t>
|
||||
{
|
||||
uint32_t mkelvin = 0; // up to 4 MK (temperatures in K are always positive)
|
||||
};
|
||||
|
||||
struct temperature_sum_t
|
||||
struct temperature_sum_t : public unit_base<temperature_sum_t>
|
||||
{
|
||||
uint64_t mkelvin = 0; // up to 18446744073 MK (temperatures in K are always positive)
|
||||
};
|
||||
|
||||
struct volume_t
|
||||
struct volume_t : public unit_base<volume_t>
|
||||
{
|
||||
int mliter = 0;
|
||||
};
|
||||
|
||||
struct fraction_t
|
||||
struct fraction_t : public unit_base<fraction_t>
|
||||
{
|
||||
int permille = 0;
|
||||
};
|
||||
|
||||
struct weight_t
|
||||
struct weight_t : public unit_base<weight_t>
|
||||
{
|
||||
int grams = 0;
|
||||
};
|
||||
|
||||
struct degrees_t
|
||||
struct degrees_t : public unit_base<degrees_t>
|
||||
{
|
||||
int udeg = 0;
|
||||
};
|
||||
|
|
@ -152,8 +156,8 @@ static inline bool operator!=(const location_t &a, const location_t &b)
|
|||
static inline location_t create_location(double lat, double lon)
|
||||
{
|
||||
location_t location = {
|
||||
{ (int) lrint(lat * 1000000) },
|
||||
{ (int) lrint(lon * 1000000) }
|
||||
{ .udeg = (int) lrint(lat * 1000000) },
|
||||
{ .udeg = (int) lrint(lon * 1000000) }
|
||||
};
|
||||
return location;
|
||||
}
|
||||
|
|
@ -255,7 +259,7 @@ static inline double mbar_to_atm(int mbar)
|
|||
|
||||
static inline double mbar_to_PSI(int mbar)
|
||||
{
|
||||
pressure_t p = { mbar };
|
||||
pressure_t p = { .mbar = mbar };
|
||||
return to_PSI(p);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue