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:
Berthold Stoeger 2024-09-01 21:48:31 +02:00 committed by bstoeger
parent 696ba61eef
commit 12ca172a9e
26 changed files with 127 additions and 138 deletions

View file

@ -47,10 +47,10 @@ diveplan setupPlan()
dp.bottomsac = prefs.bottomsac;
dp.decosac = prefs.decosac;
struct gasmix bottomgas = {{150}, {450}};
struct gasmix ean36 = {{360}, {0}};
struct gasmix oxygen = {{1000}, {0}};
pressure_t po2 = {1600};
struct gasmix bottomgas = {{.permille = 150}, {.permille = 450}};
struct gasmix ean36 = {{.permille = 360}, {}};
struct gasmix oxygen = {{.permille = 1000}, {}};
pressure_t po2 = {.mbar = 1600};
// Note: we add the highest-index cylinder first, because
// pointers to cylinders are not stable when reallocating.
// For testing OK - don't do this in actual code!
@ -82,10 +82,10 @@ diveplan setupPlanVpmb45m30mTx()
dp.bottomsac = prefs.bottomsac;
dp.decosac = prefs.decosac;
struct gasmix bottomgas = {{210}, {350}};
struct gasmix ean50 = {{500}, {0}};
struct gasmix oxygen = {{1000}, {0}};
pressure_t po2 = {1600};
struct gasmix bottomgas = {{.permille = 210}, {.permille = 350}};
struct gasmix ean50 = {{.permille = 500}, {}};
struct gasmix oxygen = {{.permille = 1000}, {}};
pressure_t po2 = {.mbar = 1600};
// Note: we add the highest-index cylinder first, because
// pointers to cylinders are not stable when reallocating.
// For testing OK - don't do this in actual code!
@ -117,10 +117,10 @@ diveplan setupPlanVpmb60m10mTx()
dp.bottomsac = prefs.bottomsac;
dp.decosac = prefs.decosac;
struct gasmix bottomgas = {{180}, {450}};
struct gasmix tx50_15 = {{500}, {150}};
struct gasmix oxygen = {{1000}, {0}};
pressure_t po2 = {1600};
struct gasmix bottomgas = {{.permille = 180}, {.permille = 450}};
struct gasmix tx50_15 = {{.permille = 500}, {.permille = 150}};
struct gasmix oxygen = {{.permille = 1000}, {}};
pressure_t po2 = {.mbar = 1600};
// Note: we add the highest-index cylinder first, because
// pointers to cylinders are not stable when reallocating.
// For testing OK - don't do this in actual code!
@ -150,7 +150,7 @@ diveplan setupPlanVpmb60m30minAir()
dp.bottomsac = prefs.bottomsac;
dp.decosac = prefs.decosac;
struct gasmix bottomgas = {{210}, {0}};
struct gasmix bottomgas = {{.permille = 210}, {}};
cylinder_t *cyl0 = dive.get_or_create_cylinder(0);
cyl0->gasmix = bottomgas;
cyl0->type.size.mliter = 100000;
@ -172,9 +172,9 @@ diveplan setupPlanVpmb60m30minEan50()
dp.bottomsac = prefs.bottomsac;
dp.decosac = prefs.decosac;
struct gasmix bottomgas = {{210}, {0}};
struct gasmix ean50 = {{500}, {0}};
pressure_t po2 = {1600};
struct gasmix bottomgas = {{.permille = 210}, {}};
struct gasmix ean50 = {{.permille = 500}, {}};
pressure_t po2 = {.mbar = 1600};
// Note: we add the highest-index cylinder first, because
// pointers to cylinders are not stable when reallocating.
// For testing OK - don't do this in actual code!
@ -202,9 +202,9 @@ diveplan setupPlanVpmb60m30minTx()
dp.bottomsac = prefs.bottomsac;
dp.decosac = prefs.decosac;
struct gasmix bottomgas = {{180}, {450}};
struct gasmix ean50 = {{500}, {0}};
pressure_t po2 = {1600};
struct gasmix bottomgas = {{.permille = 180}, {.permille = 450}};
struct gasmix ean50 = {{.permille = 500}, {}};
pressure_t po2 = {.mbar = 1600};
// Note: we add the highest-index cylinder first, because
// pointers to cylinders are not stable when reallocating.
// For testing OK - don't do this in actual code!
@ -232,7 +232,7 @@ diveplan setupPlanVpmbMultiLevelAir()
dp.bottomsac = prefs.bottomsac;
dp.decosac = prefs.decosac;
struct gasmix bottomgas = {{210}, {0}};
struct gasmix bottomgas = {{.permille = 210}, {}};
cylinder_t *cyl0 = dive.get_or_create_cylinder(0);
cyl0->gasmix = bottomgas;
cyl0->type.size.mliter = 200000;
@ -256,10 +256,10 @@ diveplan setupPlanVpmb100m60min()
dp.bottomsac = prefs.bottomsac;
dp.decosac = prefs.decosac;
struct gasmix bottomgas = {{180}, {450}};
struct gasmix ean50 = {{500}, {0}};
struct gasmix oxygen = {{1000}, {0}};
pressure_t po2 = {1600};
struct gasmix bottomgas = {{.permille = 180}, {.permille = 450}};
struct gasmix ean50 = {{.permille = 500}, {}};
struct gasmix oxygen = {{.permille = 1000}, {}};
pressure_t po2 = {.mbar = 1600};
// Note: we add the highest-index cylinder first, because
// pointers to cylinders are not stable when reallocating.
// For testing OK - don't do this in actual code!
@ -290,10 +290,10 @@ diveplan setupPlanVpmb100m10min()
dp.bottomsac = prefs.bottomsac;
dp.decosac = prefs.decosac;
struct gasmix bottomgas = {{180}, {450}};
struct gasmix ean50 = {{500}, {0}};
struct gasmix oxygen = {{1000}, {0}};
pressure_t po2 = {1600};
struct gasmix bottomgas = {{.permille = 180}, {.permille = 450}};
struct gasmix ean50 = {{.permille = 500}, {}};
struct gasmix oxygen = {{.permille = 1000}, {}};
pressure_t po2 = {.mbar = 1600};
// Note: we add the highest-index cylinder first, because
// pointers to cylinders are not stable when reallocating.
// For testing OK - don't do this in actual code!
@ -324,7 +324,7 @@ diveplan setupPlanVpmb30m20min()
dp.bottomsac = prefs.bottomsac;
dp.decosac = prefs.decosac;
struct gasmix bottomgas = {{210}, {0}};
struct gasmix bottomgas = {{.permille = 210}, {}};
cylinder_t *cyl0 = dive.get_or_create_cylinder(0);
cyl0->gasmix = bottomgas;
cyl0->type.size.mliter = 36000;
@ -346,11 +346,11 @@ diveplan setupPlanVpmb100mTo70m30min()
dp.bottomsac = prefs.bottomsac;
dp.decosac = prefs.decosac;
struct gasmix bottomgas = {{120}, {650}};
struct gasmix tx21_35 = {{210}, {350}};
struct gasmix ean50 = {{500}, {0}};
struct gasmix oxygen = {{1000}, {0}};
pressure_t po2 = {1600};
struct gasmix bottomgas = {{.permille = 120}, {.permille = 650}};
struct gasmix tx21_35 = {{.permille = 210}, {.permille = 350}};
struct gasmix ean50 = {{.permille = 500}, {}};
struct gasmix oxygen = {{.permille = 1000}, {}};
pressure_t po2 = {.mbar = 1600};
// Note: we add the highest-index cylinder first, because
// pointers to cylinders are not stable when reallocating.
// For testing OK - don't do this in actual code!
@ -388,8 +388,8 @@ diveplan setupPlanSeveralGases()
dp.bottomsac = prefs.bottomsac;
dp.decosac = prefs.decosac;
struct gasmix ean36 = {{360}, {0}};
struct gasmix tx11_50 = {{110}, {500}};
struct gasmix ean36 = {{.permille = 360}, {}};
struct gasmix tx11_50 = {{.permille = 110}, {.permille = 500}};
// Note: we add the highest-index cylinder first, because
// pointers to cylinders are not stable when reallocating.
@ -420,10 +420,10 @@ diveplan setupPlanCcr()
dp.bottomsac = prefs.bottomsac;
dp.decosac = prefs.decosac;
pressure_t po2 = {1600};
struct gasmix diluent = {{200}, {210}};
struct gasmix ean53 = {{530}, {0}};
struct gasmix tx19_33 = {{190}, {330}};
pressure_t po2 = {.mbar = 1600};
struct gasmix diluent = {{.permille = 200}, {.permille = 210}};
struct gasmix ean53 = {{.permille = 530}, {}};
struct gasmix tx19_33 = {{.permille = 190}, {.permille = 330}};
// Note: we add the highest-index cylinder first, because
// pointers to cylinders are not stable when reallocating.
// For testing OK - don't do this in actual code!
@ -754,7 +754,7 @@ void TestPlan::testMultipleGases()
save_dive(stdout, dive, false);
#endif
gasmix gas = dive.get_gasmix_at_time(dive.dcs[0], {20 * 60 + 1});
gasmix gas = dive.get_gasmix_at_time(dive.dcs[0], {.seconds = 20 * 60 + 1});
QCOMPARE(get_o2(gas), 110);
QVERIFY(compareDecoTime(dive.dcs[0].duration.seconds, 2480u, 2480u));
}
@ -934,17 +934,17 @@ void TestPlan::testCcrBailoutGasSelection()
#endif
// check diluent used
cylinder_t *cylinder = dive.get_cylinder(get_cylinderid_at_time(&dive, &dive.dcs[0], { 20 * 60 - 1 }));
cylinder_t *cylinder = dive.get_cylinder(get_cylinderid_at_time(&dive, &dive.dcs[0], { .seconds = 20 * 60 - 1 }));
QCOMPARE(cylinder->cylinder_use, DILUENT);
QCOMPARE(get_o2(cylinder->gasmix), 200);
// check deep bailout used
cylinder = dive.get_cylinder(get_cylinderid_at_time(&dive, &dive.dcs[0], { 20 * 60 + 1 }));
cylinder = dive.get_cylinder(get_cylinderid_at_time(&dive, &dive.dcs[0], { .seconds = 20 * 60 + 1 }));
QCOMPARE(cylinder->cylinder_use, OC_GAS);
QCOMPARE(get_o2(cylinder->gasmix), 190);
// check shallow bailout used
cylinder = dive.get_cylinder(get_cylinderid_at_time(&dive, &dive.dcs[0], { 30 * 60 }));
cylinder = dive.get_cylinder(get_cylinderid_at_time(&dive, &dive.dcs[0], { .seconds = 30 * 60 }));
QCOMPARE(cylinder->cylinder_use, OC_GAS);
QCOMPARE(get_o2(cylinder->gasmix), 530);

View file

@ -11,14 +11,14 @@ void TestUnitConversion::testUnitConversions()
QCOMPARE(nearly_equal(cuft_to_l(1), 28.316847), true);
QCOMPARE(nearly_equal(mm_to_feet(1000), 3.280840), true);
QCOMPARE(feet_to_mm(1), 305L);
QCOMPARE(to_feet((depth_t){1000}), 3);
QCOMPARE(to_feet(depth_t{ .mm = 1'000}), 3);
QCOMPARE(nearly_equal(mkelvin_to_C(647000), 373.85), true);
QCOMPARE(nearly_equal(mkelvin_to_F(647000), 704.93), true);
QCOMPARE(F_to_mkelvin(704.93), 647000UL);
QCOMPARE(C_to_mkelvin(373.85), 647000UL);
QCOMPARE(nearly_equal(psi_to_bar(14.6959488), 1.01325), true);
QCOMPARE(psi_to_mbar(14.6959488), 1013L);
QCOMPARE(nearly_equal(to_PSI((pressure_t){1013}), 14.6923228594), true);
QCOMPARE(nearly_equal(to_PSI(pressure_t{ .mbar = 1013}), 14.6923228594), true);
QCOMPARE(nearly_equal(bar_to_atm(1.013), 1.0), true);
QCOMPARE(nearly_equal(mbar_to_atm(1013), 1.0), true);
QCOMPARE(nearly_equal(mbar_to_PSI(1013), 14.6923228594), true);