core: convert cylinder_t and cylinder_table to C++

This had to be done simultaneously, because the table macros
do not work properly with C++ objects.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2024-05-28 21:31:11 +02:00 committed by bstoeger
parent 284582d2e8
commit 28520da655
48 changed files with 593 additions and 710 deletions

View file

@ -205,10 +205,10 @@ void export_TeX(const char *filename, bool selected_only, bool plain, ExportCall
// Print cylinder data // Print cylinder data
put_format(&buf, "\n%% Gas use information:\n"); put_format(&buf, "\n%% Gas use information:\n");
qty_cyl = 0; qty_cyl = 0;
for (i = 0; i < dive->cylinders.nr; i++){ for (int i = 0; i < static_cast<int>(dive->cylinders.size()); i++){
const cylinder_t &cyl = *get_cylinder(dive, i); const cylinder_t &cyl = dive->cylinders[i];
if (is_cylinder_used(dive, i) || (prefs.include_unused_tanks && cyl.type.description)){ if (is_cylinder_used(dive, i) || (prefs.include_unused_tanks && !cyl.type.description.empty())){
put_format(&buf, "\\def\\%scyl%cdescription{%s}\n", ssrf, 'a' + i, cyl.type.description); put_format(&buf, "\\def\\%scyl%cdescription{%s}\n", ssrf, 'a' + i, cyl.type.description.c_str());
put_format(&buf, "\\def\\%scyl%cgasname{%s}\n", ssrf, 'a' + i, gasname(cyl.gasmix)); put_format(&buf, "\\def\\%scyl%cgasname{%s}\n", ssrf, 'a' + i, gasname(cyl.gasmix));
put_format(&buf, "\\def\\%scyl%cmixO2{%.1f\\%%}\n", ssrf, 'a' + i, get_o2(cyl.gasmix)/10.0); put_format(&buf, "\\def\\%scyl%cmixO2{%.1f\\%%}\n", ssrf, 'a' + i, get_o2(cyl.gasmix)/10.0);
put_format(&buf, "\\def\\%scyl%cmixHe{%.1f\\%%}\n", ssrf, 'a' + i, get_he(cyl.gasmix)/10.0); put_format(&buf, "\\def\\%scyl%cmixHe{%.1f\\%%}\n", ssrf, 'a' + i, get_he(cyl.gasmix)/10.0);

View file

@ -962,7 +962,7 @@ MergeDives::MergeDives(const QVector <dive *> &dives)
{ {
setText(Command::Base::tr("merge dive")); setText(Command::Base::tr("merge dive"));
// Just a safety check - if there's not two or more dives - do nothing // Just a safety check - if there's not two or more dives - do nothing.
// The caller should have made sure that this doesn't happen. // The caller should have made sure that this doesn't happen.
if (dives.count() < 2) { if (dives.count() < 2) {
qWarning("Merging less than two dives"); qWarning("Merging less than two dives");

View file

@ -629,7 +629,6 @@ static void swapCandQString(QString &q, char *&c)
PasteState::PasteState(dive *dIn, const dive *data, dive_components what) : d(dIn), PasteState::PasteState(dive *dIn, const dive *data, dive_components what) : d(dIn),
tags(nullptr) tags(nullptr)
{ {
memset(&cylinders, 0, sizeof(cylinders));
memset(&weightsystems, 0, sizeof(weightsystems)); memset(&weightsystems, 0, sizeof(weightsystems));
if (what.notes) if (what.notes)
notes = data->notes; notes = data->notes;
@ -656,14 +655,14 @@ PasteState::PasteState(dive *dIn, const dive *data, dive_components what) : d(dI
if (what.tags) if (what.tags)
tags = taglist_copy(data->tag_list); tags = taglist_copy(data->tag_list);
if (what.cylinders) { if (what.cylinders) {
copy_cylinders(&data->cylinders, &cylinders); cylinders = data->cylinders;
// Paste cylinders is "special": // Paste cylinders is "special":
// 1) For cylinders that exist in the destination dive we keep the gas-mix and pressures. // 1) For cylinders that exist in the destination dive we keep the gas-mix and pressures.
// 2) For cylinders that do not yet exist in the destination dive, we set the pressures to 0, i.e. unset. // 2) For cylinders that do not yet exist in the destination dive, we set the pressures to 0, i.e. unset.
// Moreover, for these we set the manually_added flag, because they weren't downloaded from a DC. // Moreover, for these we set the manually_added flag, because they weren't downloaded from a DC.
for (int i = 0; i < d->cylinders.nr && i < cylinders.nr; ++i) { for (size_t i = 0; i < d->cylinders.size() && i < cylinders.size(); ++i) {
const cylinder_t &src = *get_cylinder(d, i); const cylinder_t &src = d->cylinders[i];
cylinder_t &dst = cylinders.cylinders[i]; cylinder_t &dst = cylinders[i];
dst.gasmix = src.gasmix; dst.gasmix = src.gasmix;
dst.start = src.start; dst.start = src.start;
dst.end = src.end; dst.end = src.end;
@ -677,8 +676,8 @@ PasteState::PasteState(dive *dIn, const dive *data, dive_components what) : d(dI
dst.bestmix_o2 = src.bestmix_o2; dst.bestmix_o2 = src.bestmix_o2;
dst.bestmix_he = src.bestmix_he; dst.bestmix_he = src.bestmix_he;
} }
for (int i = d->cylinders.nr; i < cylinders.nr; ++i) { for (size_t i = d->cylinders.size(); i < cylinders.size(); ++i) {
cylinder_t &cyl = cylinders.cylinders[i]; cylinder_t &cyl = cylinders[i];
cyl.start.mbar = 0; cyl.start.mbar = 0;
cyl.end.mbar = 0; cyl.end.mbar = 0;
cyl.sample_start.mbar = 0; cyl.sample_start.mbar = 0;
@ -697,7 +696,6 @@ PasteState::PasteState(dive *dIn, const dive *data, dive_components what) : d(dI
PasteState::~PasteState() PasteState::~PasteState()
{ {
taglist_free(tags); taglist_free(tags);
clear_cylinder_table(&cylinders);
clear_weightsystem_table(&weightsystems); clear_weightsystem_table(&weightsystems);
free(weightsystems.weightsystems); free(weightsystems.weightsystems);
} }
@ -803,7 +801,6 @@ ReplanDive::ReplanDive(dive *source) : d(current_dive),
duration({0}), duration({0}),
salinity(0) salinity(0)
{ {
memset(&cylinders, 0, sizeof(cylinders));
if (!d) if (!d)
return; return;
@ -828,7 +825,6 @@ ReplanDive::ReplanDive(dive *source) : d(current_dive),
ReplanDive::~ReplanDive() ReplanDive::~ReplanDive()
{ {
clear_cylinder_table(&cylinders);
free(notes); free(notes);
} }
@ -1124,7 +1120,6 @@ AddCylinder::AddCylinder(bool currentDiveOnly) :
AddCylinder::~AddCylinder() AddCylinder::~AddCylinder()
{ {
free_cylinder(cyl);
} }
bool AddCylinder::workToBeDone() bool AddCylinder::workToBeDone()
@ -1148,7 +1143,7 @@ void AddCylinder::redo()
for (dive *d: dives) { for (dive *d: dives) {
int index = first_hidden_cylinder(d); int index = first_hidden_cylinder(d);
indexes.push_back(index); indexes.push_back(index);
add_cylinder(&d->cylinders, index, clone_cylinder(cyl)); add_cylinder(&d->cylinders, index, cyl);
update_cylinder_related_info(d); update_cylinder_related_info(d);
emit diveListNotifier.cylinderAdded(d, index); emit diveListNotifier.cylinderAdded(d, index);
invalidate_dive_cache(d); // Ensure that dive is written in git_save() invalidate_dive_cache(d); // Ensure that dive is written in git_save()
@ -1157,14 +1152,14 @@ void AddCylinder::redo()
static bool same_cylinder_type(const cylinder_t &cyl1, const cylinder_t &cyl2) static bool same_cylinder_type(const cylinder_t &cyl1, const cylinder_t &cyl2)
{ {
return same_string(cyl1.type.description, cyl2.type.description) && return std::tie(cyl1.cylinder_use, cyl1.type.description) ==
cyl1.cylinder_use == cyl2.cylinder_use; std::tie(cyl2.cylinder_use, cyl2.type.description);
} }
static bool same_cylinder_size(const cylinder_t &cyl1, const cylinder_t &cyl2) static bool same_cylinder_size(const cylinder_t &cyl1, const cylinder_t &cyl2)
{ {
return cyl1.type.size.mliter == cyl2.type.size.mliter && return std::tie(cyl1.type.size.mliter, cyl1.type.workingpressure.mbar) ==
cyl1.type.workingpressure.mbar == cyl2.type.workingpressure.mbar; std::tie(cyl2.type.size.mliter, cyl2.type.workingpressure.mbar);
} }
// Flags for comparing cylinders // Flags for comparing cylinders
@ -1177,7 +1172,7 @@ EditCylinderBase::EditCylinderBase(int index, bool currentDiveOnly, bool nonProt
EditDivesBase(currentDiveOnly) EditDivesBase(currentDiveOnly)
{ {
// Get the old cylinder, bail if index is invalid // Get the old cylinder, bail if index is invalid
if (!current || index < 0 || index >= current->cylinders.nr) { if (!current || index < 0 || index >= static_cast<int>(current->cylinders.size())) {
dives.clear(); dives.clear();
return; return;
} }
@ -1189,12 +1184,12 @@ EditCylinderBase::EditCylinderBase(int index, bool currentDiveOnly, bool nonProt
cyl.reserve(dives.size()); cyl.reserve(dives.size());
for (dive *d: dives) { for (dive *d: dives) {
if (index >= d->cylinders.nr) if (index >= static_cast<int>(d->cylinders.size()))
continue; continue;
if (nonProtectedOnly && is_cylinder_prot(d, index)) if (nonProtectedOnly && is_cylinder_prot(d, index))
continue; continue;
// We checked that the cylinder exists above. // We checked that the cylinder exists above.
const cylinder_t &cylinder = *get_cylinder(d, index); const cylinder_t &cylinder = d->cylinders[index];
if (d != current && if (d != current &&
(!same_cylinder_size(orig, cylinder) || !same_cylinder_type(orig, cylinder))) { (!same_cylinder_size(orig, cylinder) || !same_cylinder_type(orig, cylinder))) {
// when editing cylinders, we assume that the user wanted to edit the 'n-th' cylinder // when editing cylinders, we assume that the user wanted to edit the 'n-th' cylinder
@ -1206,15 +1201,13 @@ EditCylinderBase::EditCylinderBase(int index, bool currentDiveOnly, bool nonProt
// that's silly as it's always the same value - but we need this vector of indices in the case where we add // that's silly as it's always the same value - but we need this vector of indices in the case where we add
// a cylinder to several dives as the spot will potentially be different in different dives // a cylinder to several dives as the spot will potentially be different in different dives
indexes.push_back(index); indexes.push_back(index);
cyl.push_back(clone_cylinder(cylinder)); cyl.push_back(cylinder);
} }
dives = std::move(divesNew); dives = std::move(divesNew);
} }
EditCylinderBase::~EditCylinderBase() EditCylinderBase::~EditCylinderBase()
{ {
for (cylinder_t c: cyl)
free_cylinder(c);
} }
bool EditCylinderBase::workToBeDone() bool EditCylinderBase::workToBeDone()
@ -1235,8 +1228,8 @@ RemoveCylinder::RemoveCylinder(int index, bool currentDiveOnly) :
void RemoveCylinder::undo() void RemoveCylinder::undo()
{ {
for (size_t i = 0; i < dives.size(); ++i) { for (size_t i = 0; i < dives.size(); ++i) {
std::vector<int> mapping = get_cylinder_map_for_add(dives[i]->cylinders.nr, indexes[i]); std::vector<int> mapping = get_cylinder_map_for_add(dives[i]->cylinders.size(), indexes[i]);
add_cylinder(&dives[i]->cylinders, indexes[i], clone_cylinder(cyl[i])); add_cylinder(&dives[i]->cylinders, indexes[i], cyl[i]);
cylinder_renumber(dives[i], &mapping[0]); cylinder_renumber(dives[i], &mapping[0]);
update_cylinder_related_info(dives[i]); update_cylinder_related_info(dives[i]);
emit diveListNotifier.cylinderAdded(dives[i], indexes[i]); emit diveListNotifier.cylinderAdded(dives[i], indexes[i]);
@ -1247,7 +1240,7 @@ void RemoveCylinder::undo()
void RemoveCylinder::redo() void RemoveCylinder::redo()
{ {
for (size_t i = 0; i < dives.size(); ++i) { for (size_t i = 0; i < dives.size(); ++i) {
std::vector<int> mapping = get_cylinder_map_for_remove(dives[i]->cylinders.nr, indexes[i]); std::vector<int> mapping = get_cylinder_map_for_remove(dives[i]->cylinders.size(), indexes[i]);
remove_cylinder(dives[i], indexes[i]); remove_cylinder(dives[i], indexes[i]);
cylinder_renumber(dives[i], &mapping[0]); cylinder_renumber(dives[i], &mapping[0]);
update_cylinder_related_info(dives[i]); update_cylinder_related_info(dives[i]);
@ -1282,15 +1275,12 @@ EditCylinder::EditCylinder(int index, cylinder_t cylIn, EditCylinderType typeIn,
else else
setText(Command::Base::tr("Edit cylinder (%n dive(s))", "", dives.size())); setText(Command::Base::tr("Edit cylinder (%n dive(s))", "", dives.size()));
QString description = cylIn.type.description;
// The base class copied the cylinders for us, let's edit them // The base class copied the cylinders for us, let's edit them
for (int i = 0; i < (int)indexes.size(); ++i) { for (int i = 0; i < (int)indexes.size(); ++i) {
switch (type) { switch (type) {
case EditCylinderType::TYPE: case EditCylinderType::TYPE:
free((void *)cyl[i].type.description);
cyl[i].type = cylIn.type; cyl[i].type = cylIn.type;
cyl[i].type.description = copy_qstring(description); cyl[i].type.description = cylIn.type.description;
cyl[i].cylinder_use = cylIn.cylinder_use; cyl[i].cylinder_use = cylIn.cylinder_use;
break; break;
case EditCylinderType::PRESSURE: case EditCylinderType::PRESSURE:
@ -1301,7 +1291,7 @@ EditCylinder::EditCylinder(int index, cylinder_t cylIn, EditCylinderType typeIn,
cyl[i].gasmix = cylIn.gasmix; cyl[i].gasmix = cylIn.gasmix;
cyl[i].bestmix_o2 = cylIn.bestmix_o2; cyl[i].bestmix_o2 = cylIn.bestmix_o2;
cyl[i].bestmix_he = cylIn.bestmix_he; cyl[i].bestmix_he = cylIn.bestmix_he;
sanitize_gasmix(&cyl[i].gasmix); sanitize_gasmix(cyl[i].gasmix);
break; break;
} }
} }
@ -1310,7 +1300,7 @@ EditCylinder::EditCylinder(int index, cylinder_t cylIn, EditCylinderType typeIn,
void EditCylinder::redo() void EditCylinder::redo()
{ {
for (size_t i = 0; i < dives.size(); ++i) { for (size_t i = 0; i < dives.size(); ++i) {
std::string name = cyl[i].type.description; const std::string &name = cyl[i].type.description;
set_tank_info_data(tank_info_table, name, cyl[i].type.size, cyl[i].type.workingpressure); set_tank_info_data(tank_info_table, name, cyl[i].type.size, cyl[i].type.workingpressure);
std::swap(*get_cylinder(dives[i], indexes[i]), cyl[i]); std::swap(*get_cylinder(dives[i], indexes[i]), cyl[i]);
update_cylinder_related_info(dives[i]); update_cylinder_related_info(dives[i]);

View file

@ -672,24 +672,22 @@ static void cochran_parse_dive(const unsigned char *decode, unsigned mod,
case TYPE_GEMINI: case TYPE_GEMINI:
case TYPE_COMMANDER: case TYPE_COMMANDER:
if (config.type == TYPE_GEMINI) { if (config.type == TYPE_GEMINI) {
cylinder_t cyl;
dc->model = "Gemini"; dc->model = "Gemini";
dc->deviceid = buf[0x18c] * 256 + buf[0x18d]; // serial no dc->deviceid = buf[0x18c] * 256 + buf[0x18d]; // serial no
fill_default_cylinder(dive.get(), &cyl); cylinder_t cyl = default_cylinder(dive.get());
cyl.gasmix.o2.permille = (log[CMD_O2_PERCENT] / 256 cyl.gasmix.o2.permille = (log[CMD_O2_PERCENT] / 256
+ log[CMD_O2_PERCENT + 1]) * 10; + log[CMD_O2_PERCENT + 1]) * 10;
cyl.gasmix.he.permille = 0; cyl.gasmix.he.permille = 0;
add_cylinder(&dive->cylinders, 0, cyl); add_cylinder(&dive->cylinders, 0, std::move(cyl));
} else { } else {
dc->model = "Commander"; dc->model = "Commander";
dc->deviceid = array_uint32_le(buf + 0x31e); // serial no dc->deviceid = array_uint32_le(buf + 0x31e); // serial no
for (g = 0; g < 2; g++) { for (g = 0; g < 2; g++) {
cylinder_t cyl; cylinder_t cyl = default_cylinder(dive.get());
fill_default_cylinder(dive.get(), &cyl);
cyl.gasmix.o2.permille = (log[CMD_O2_PERCENT + g * 2] / 256 cyl.gasmix.o2.permille = (log[CMD_O2_PERCENT + g * 2] / 256
+ log[CMD_O2_PERCENT + g * 2 + 1]) * 10; + log[CMD_O2_PERCENT + g * 2 + 1]) * 10;
cyl.gasmix.he.permille = 0; cyl.gasmix.he.permille = 0;
add_cylinder(&dive->cylinders, g, cyl); add_cylinder(&dive->cylinders, g, std::move(cyl));
} }
} }
@ -727,15 +725,14 @@ static void cochran_parse_dive(const unsigned char *decode, unsigned mod,
dc->model = "EMC"; dc->model = "EMC";
dc->deviceid = array_uint32_le(buf + 0x31e); // serial no dc->deviceid = array_uint32_le(buf + 0x31e); // serial no
for (g = 0; g < 4; g++) { for (g = 0; g < 4; g++) {
cylinder_t cyl; cylinder_t cyl = default_cylinder(dive.get());
fill_default_cylinder(dive.get(), &cyl);
cyl.gasmix.o2.permille = cyl.gasmix.o2.permille =
(log[EMC_O2_PERCENT + g * 2] / 256 (log[EMC_O2_PERCENT + g * 2] / 256
+ log[EMC_O2_PERCENT + g * 2 + 1]) * 10; + log[EMC_O2_PERCENT + g * 2 + 1]) * 10;
cyl.gasmix.he.permille = cyl.gasmix.he.permille =
(log[EMC_HE_PERCENT + g * 2] / 256 (log[EMC_HE_PERCENT + g * 2] / 256
+ log[EMC_HE_PERCENT + g * 2 + 1]) * 10; + log[EMC_HE_PERCENT + g * 2 + 1]) * 10;
add_cylinder(&dive->cylinders, g, cyl); add_cylinder(&dive->cylinders, g, std::move(cyl));
} }
tm.tm_year = log[EMC_YEAR]; tm.tm_year = log[EMC_YEAR];

View file

@ -334,14 +334,13 @@ static char *dt_dive_parser(unsigned char *runner, struct dive *dt_dive, struct
read_bytes(2); read_bytes(2);
if (tmp_2bytes != 0x7FFF) { if (tmp_2bytes != 0x7FFF) {
cylinder_t cyl; cylinder_t cyl;
std::string desc = cyl_type_by_size(tmp_2bytes * 10);
cyl.type.size.mliter = tmp_2bytes * 10; cyl.type.size.mliter = tmp_2bytes * 10;
cyl.type.description = desc.c_str(); cyl.type.description = cyl_type_by_size(tmp_2bytes * 10);
cyl.start.mbar = 200000; cyl.start.mbar = 200000;
cyl.gasmix.he.permille = 0; cyl.gasmix.he.permille = 0;
cyl.gasmix.o2.permille = 210; cyl.gasmix.o2.permille = 210;
cyl.manually_added = true; cyl.manually_added = true;
add_cloned_cylinder(&dt_dive->cylinders, cyl); dt_dive->cylinders.push_back(std::move(cyl));
} }
/* /*
@ -372,7 +371,7 @@ static char *dt_dive_parser(unsigned char *runner, struct dive *dt_dive, struct
* Air used in bar*100. * Air used in bar*100.
*/ */
read_bytes(2); read_bytes(2);
if (tmp_2bytes != 0x7FFF && dt_dive->cylinders.nr > 0) if (tmp_2bytes != 0x7FFF && dt_dive->cylinders.size() > 0)
get_cylinder(dt_dive, 0)->gas_used.mliter = lrint(get_cylinder(dt_dive, 0)->type.size.mliter * (tmp_2bytes / 100.0)); get_cylinder(dt_dive, 0)->gas_used.mliter = lrint(get_cylinder(dt_dive, 0)->type.size.mliter * (tmp_2bytes / 100.0));
/* /*
@ -548,10 +547,10 @@ static char *dt_dive_parser(unsigned char *runner, struct dive *dt_dive, struct
free(compl_buffer); free(compl_buffer);
goto bail; goto bail;
} }
if (is_nitrox && dt_dive->cylinders.nr > 0) if (is_nitrox && dt_dive->cylinders.size() > 0)
get_cylinder(dt_dive, 0)->gasmix.o2.permille = get_cylinder(dt_dive, 0)->gasmix.o2.permille =
lrint(membuf[23] & 0x0F ? 20.0 + 2 * (membuf[23] & 0x0F) : 21.0) * 10; lrint(membuf[23] & 0x0F ? 20.0 + 2 * (membuf[23] & 0x0F) : 21.0) * 10;
if (is_O2 && dt_dive->cylinders.nr > 0) if (is_O2 && dt_dive->cylinders.size() > 0)
get_cylinder(dt_dive, 0)->gasmix.o2.permille = membuf[23] * 10; get_cylinder(dt_dive, 0)->gasmix.o2.permille = membuf[23] * 10;
free(compl_buffer); free(compl_buffer);
} }
@ -564,7 +563,7 @@ static char *dt_dive_parser(unsigned char *runner, struct dive *dt_dive, struct
dt_dive->dcs[0].deviceid = 0; dt_dive->dcs[0].deviceid = 0;
else else
dt_dive->dcs[0].deviceid = 0xffffffff; dt_dive->dcs[0].deviceid = 0xffffffff;
if (!is_SCR && dt_dive->cylinders.nr > 0) { if (!is_SCR && dt_dive->cylinders.size() > 0) {
get_cylinder(dt_dive, 0)->end.mbar = get_cylinder(dt_dive, 0)->start.mbar - get_cylinder(dt_dive, 0)->end.mbar = get_cylinder(dt_dive, 0)->start.mbar -
((get_cylinder(dt_dive, 0)->gas_used.mliter / get_cylinder(dt_dive, 0)->type.size.mliter) * 1000); ((get_cylinder(dt_dive, 0)->gas_used.mliter / get_cylinder(dt_dive, 0)->type.size.mliter) * 1000);
} }

View file

@ -17,6 +17,7 @@
#include "errorhelper.h" #include "errorhelper.h"
#include "event.h" #include "event.h"
#include "extradata.h" #include "extradata.h"
#include "format.h"
#include "interpolate.h" #include "interpolate.h"
#include "qthelper.h" #include "qthelper.h"
#include "membuffer.h" #include "membuffer.h"
@ -121,8 +122,8 @@ void add_gas_switch_event(struct dive *dive, struct divecomputer *dc, int second
/* sanity check so we don't crash */ /* sanity check so we don't crash */
/* FIXME: The planner uses a dummy cylinder one past the official number of cylinders /* FIXME: The planner uses a dummy cylinder one past the official number of cylinders
* in the table to mark no-cylinder surface interavals. This is horrendous. Fix ASAP. */ * in the table to mark no-cylinder surface interavals. This is horrendous. Fix ASAP. */
//if (idx < 0 || idx >= dive->cylinders.nr) { //if (idx < 0 || idx >= dive->cylinders.size()) {
if (idx < 0 || idx >= dive->cylinders.nr + 1 || idx >= dive->cylinders.allocated) { if (idx < 0 || static_cast<size_t>(idx) >= dive->cylinders.size() + 1) {
report_error("Unknown cylinder index: %d", idx); report_error("Unknown cylinder index: %d", idx);
return; return;
} }
@ -135,9 +136,7 @@ struct gasmix get_gasmix_from_event(const struct dive *dive, const struct event
if (ev.is_gaschange()) { if (ev.is_gaschange()) {
int index = ev.gas.index; int index = ev.gas.index;
// FIXME: The planner uses one past cylinder-count to signify "surface air". Remove in due course. // FIXME: The planner uses one past cylinder-count to signify "surface air". Remove in due course.
if (index == dive->cylinders.nr) if (index >= 0 && static_cast<size_t>(index) < dive->cylinders.size() + 1)
return gasmix_air;
if (index >= 0 && index < dive->cylinders.nr)
return get_cylinder(dive, index)->gasmix; return get_cylinder(dive, index)->gasmix;
return ev.gas.mix; return ev.gas.mix;
} }
@ -176,8 +175,7 @@ static void free_dive_structures(struct dive *d)
free(d->suit); free(d->suit);
/* free tags, additional dive computers, and pictures */ /* free tags, additional dive computers, and pictures */
taglist_free(d->tag_list); taglist_free(d->tag_list);
clear_cylinder_table(&d->cylinders); d->cylinders.clear();
free(d->cylinders.cylinders);
clear_weightsystem_table(&d->weightsystems); clear_weightsystem_table(&d->weightsystems);
free(d->weightsystems.weightsystems); free(d->weightsystems.weightsystems);
clear_picture_table(&d->pictures); clear_picture_table(&d->pictures);
@ -185,7 +183,7 @@ static void free_dive_structures(struct dive *d)
} }
/* copy_dive makes duplicates of many components of a dive; /* copy_dive makes duplicates of many components of a dive;
* in order not to leak memory, we need to free those . * in order not to leak memory, we need to free those.
* copy_dive doesn't play with the divetrip and forward/backward pointers * copy_dive doesn't play with the divetrip and forward/backward pointers
* so we can ignore those */ * so we can ignore those */
void clear_dive(struct dive *d) void clear_dive(struct dive *d)
@ -206,7 +204,6 @@ void copy_dive(const struct dive *s, struct dive *d)
* relevant components that are referenced through pointers, * relevant components that are referenced through pointers,
* so all the strings and the structured lists */ * so all the strings and the structured lists */
*d = *s; *d = *s;
memset(&d->cylinders, 0, sizeof(d->cylinders));
memset(&d->weightsystems, 0, sizeof(d->weightsystems)); memset(&d->weightsystems, 0, sizeof(d->weightsystems));
memset(&d->pictures, 0, sizeof(d->pictures)); memset(&d->pictures, 0, sizeof(d->pictures));
d->full_text = NULL; d->full_text = NULL;
@ -215,7 +212,6 @@ void copy_dive(const struct dive *s, struct dive *d)
d->diveguide = copy_string(s->diveguide); d->diveguide = copy_string(s->diveguide);
d->notes = copy_string(s->notes); d->notes = copy_string(s->notes);
d->suit = copy_string(s->suit); d->suit = copy_string(s->suit);
copy_cylinders(&s->cylinders, &d->cylinders);
copy_weights(&s->weightsystems, &d->weightsystems); copy_weights(&s->weightsystems, &d->weightsystems);
copy_pictures(&s->pictures, &d->pictures); copy_pictures(&s->pictures, &d->pictures);
d->tag_list = taglist_copy(s->tag_list); d->tag_list = taglist_copy(s->tag_list);
@ -293,11 +289,6 @@ void copy_events_until(const struct dive *sd, struct dive *dd, int dcNr, int tim
} }
} }
int nr_cylinders(const struct dive *dive)
{
return dive->cylinders.nr;
}
int nr_weightsystems(const struct dive *dive) int nr_weightsystems(const struct dive *dive)
{ {
return dive->weightsystems.nr; return dive->weightsystems.nr;
@ -305,14 +296,13 @@ int nr_weightsystems(const struct dive *dive)
void copy_used_cylinders(const struct dive *s, struct dive *d, bool used_only) void copy_used_cylinders(const struct dive *s, struct dive *d, bool used_only)
{ {
int i;
if (!s || !d) if (!s || !d)
return; return;
clear_cylinder_table(&d->cylinders); d->cylinders.clear();
for (i = 0; i < s->cylinders.nr; i++) { for (auto [i, cyl]: enumerated_range(s->cylinders)) {
if (!used_only || is_cylinder_used(s, i) || get_cylinder(s, i)->cylinder_use == NOT_USED) if (!used_only || is_cylinder_used(s, i) || get_cylinder(s, i)->cylinder_use == NOT_USED)
add_cloned_cylinder(&d->cylinders, *get_cylinder(s, i)); d->cylinders.push_back(cyl);
} }
} }
@ -354,12 +344,12 @@ static void update_temperature(temperature_t *temperature, int new_temp)
/* Which cylinders had gas used? */ /* Which cylinders had gas used? */
#define SOME_GAS 5000 #define SOME_GAS 5000
static bool cylinder_used(const cylinder_t *cyl) static bool cylinder_used(const cylinder_t &cyl)
{ {
int start_mbar, end_mbar; int start_mbar, end_mbar;
start_mbar = cyl->start.mbar ?: cyl->sample_start.mbar; start_mbar = cyl.start.mbar ?: cyl.sample_start.mbar;
end_mbar = cyl->end.mbar ?: cyl->sample_end.mbar; end_mbar = cyl.end.mbar ?: cyl.sample_end.mbar;
// More than 5 bar used? This matches statistics.cpp // More than 5 bar used? This matches statistics.cpp
// heuristics // heuristics
@ -369,10 +359,10 @@ static bool cylinder_used(const cylinder_t *cyl)
/* Get list of used cylinders. Returns the number of used cylinders. */ /* Get list of used cylinders. Returns the number of used cylinders. */
static int get_cylinder_used(const struct dive *dive, bool used[]) static int get_cylinder_used(const struct dive *dive, bool used[])
{ {
int i, num = 0; int num = 0;
for (i = 0; i < dive->cylinders.nr; i++) { for (auto [i, cyl]: enumerated_range(dive->cylinders)) {
used[i] = cylinder_used(get_cylinder(dive, i)); used[i] = cylinder_used(cyl);
if (used[i]) if (used[i])
num++; num++;
} }
@ -384,8 +374,8 @@ static bool has_unknown_used_cylinders(const struct dive *dive, const struct div
const bool used_cylinders[], int num) const bool used_cylinders[], int num)
{ {
int idx; int idx;
auto used_and_unknown = std::make_unique<bool[]>(dive->cylinders.nr); auto used_and_unknown = std::make_unique<bool[]>(dive->cylinders.size());
std::copy(used_cylinders, used_cylinders + dive->cylinders.nr, used_and_unknown.get()); std::copy(used_cylinders, used_cylinders + dive->cylinders.size(), used_and_unknown.get());
/* We know about using the O2 cylinder in a CCR dive */ /* We know about using the O2 cylinder in a CCR dive */
if (dc->divemode == CCR) { if (dc->divemode == CCR) {
@ -419,16 +409,15 @@ static bool has_unknown_used_cylinders(const struct dive *dive, const struct div
void per_cylinder_mean_depth(const struct dive *dive, struct divecomputer *dc, int *mean, int *duration) void per_cylinder_mean_depth(const struct dive *dive, struct divecomputer *dc, int *mean, int *duration)
{ {
int i;
int32_t lasttime = 0; int32_t lasttime = 0;
int lastdepth = 0; int lastdepth = 0;
int idx = 0; int idx = 0;
int num_used_cylinders; int num_used_cylinders;
if (dive->cylinders.nr <= 0) if (dive->cylinders.empty())
return; return;
for (i = 0; i < dive->cylinders.nr; i++) for (size_t i = 0; i < dive->cylinders.size(); i++)
mean[i] = duration[i] = 0; mean[i] = duration[i] = 0;
if (!dc) if (!dc)
return; return;
@ -438,7 +427,7 @@ void per_cylinder_mean_depth(const struct dive *dive, struct divecomputer *dc, i
* if we don't actually know about the usage of all the * if we don't actually know about the usage of all the
* used cylinders. * used cylinders.
*/ */
auto used_cylinders = std::make_unique<bool[]>(dive->cylinders.nr); auto used_cylinders = std::make_unique<bool[]>(dive->cylinders.size());
num_used_cylinders = get_cylinder_used(dive, used_cylinders.get()); num_used_cylinders = get_cylinder_used(dive, used_cylinders.get());
if (has_unknown_used_cylinders(dive, dc, used_cylinders.get(), num_used_cylinders)) { if (has_unknown_used_cylinders(dive, dc, used_cylinders.get(), num_used_cylinders)) {
/* /*
@ -453,7 +442,7 @@ void per_cylinder_mean_depth(const struct dive *dive, struct divecomputer *dc, i
* For a single cylinder, use the overall mean * For a single cylinder, use the overall mean
* and duration * and duration
*/ */
for (i = 0; i < dive->cylinders.nr; i++) { for (size_t i = 0; i < dive->cylinders.size(); i++) {
if (used_cylinders[i]) { if (used_cylinders[i]) {
mean[i] = dc->meandepth.mm; mean[i] = dc->meandepth.mm;
duration[i] = dc->duration.seconds; duration[i] = dc->duration.seconds;
@ -466,7 +455,7 @@ void per_cylinder_mean_depth(const struct dive *dive, struct divecomputer *dc, i
fake_dc(dc); fake_dc(dc);
event_loop loop("gaschange"); event_loop loop("gaschange");
const struct event *ev = loop.next(*dc); const struct event *ev = loop.next(*dc);
std::vector<int> depthtime(dive->cylinders.nr, 0); std::vector<int> depthtime(dive->cylinders.size(), 0);
for (auto it = dc->samples.begin(); it != dc->samples.end(); ++it) { for (auto it = dc->samples.begin(); it != dc->samples.end(); ++it) {
int32_t time = it->time.seconds; int32_t time = it->time.seconds;
int depth = it->depth.mm; int depth = it->depth.mm;
@ -494,7 +483,7 @@ void per_cylinder_mean_depth(const struct dive *dive, struct divecomputer *dc, i
lastdepth = depth; lastdepth = depth;
lasttime = time; lasttime = time;
} }
for (i = 0; i < dive->cylinders.nr; i++) { for (size_t i = 0; i < dive->cylinders.size(); i++) {
if (duration[i]) if (duration[i])
mean[i] = (depthtime[i] + duration[i] / 2) / duration[i]; mean[i] = (depthtime[i] + duration[i] / 2) / duration[i];
} }
@ -529,7 +518,7 @@ static int same_rounded_pressure(pressure_t a, pressure_t b)
int explicit_first_cylinder(const struct dive *dive, const struct divecomputer *dc) int explicit_first_cylinder(const struct dive *dive, const struct divecomputer *dc)
{ {
int res = 0; int res = 0;
if (!dive->cylinders.nr) if (dive->cylinders.empty())
return -1; return -1;
if (dc) { if (dc) {
const struct event *ev = get_first_event(*dc, "gaschange"); const struct event *ev = get_first_event(*dc, "gaschange");
@ -538,7 +527,7 @@ int explicit_first_cylinder(const struct dive *dive, const struct divecomputer *
else if (dc->divemode == CCR) else if (dc->divemode == CCR)
res = std::max(get_cylinder_idx_by_use(dive, DILUENT), res); res = std::max(get_cylinder_idx_by_use(dive, DILUENT), res);
} }
return res < dive->cylinders.nr ? res : 0; return static_cast<size_t>(res) < dive->cylinders.size() ? res : 0;
} }
/* this gets called when the dive mode has changed (so OC vs. CC) /* this gets called when the dive mode has changed (so OC vs. CC)
@ -598,22 +587,18 @@ void update_setpoint_events(const struct dive *dive, struct divecomputer *dc)
* cylinder name is independent from the gasmix, and different * cylinder name is independent from the gasmix, and different
* gasmixes have different compressibility. * gasmixes have different compressibility.
*/ */
static void match_standard_cylinder(cylinder_type_t *type) static void match_standard_cylinder(cylinder_type_t &type)
{ {
double cuft, bar;
int psi, len;
const char *fmt;
char buffer[40], *p;
/* Do we already have a cylinder description? */ /* Do we already have a cylinder description? */
if (type->description) if (!type.description.empty())
return; return;
bar = type->workingpressure.mbar / 1000.0; double bar = type.workingpressure.mbar / 1000.0;
cuft = ml_to_cuft(type->size.mliter); double cuft = ml_to_cuft(type.size.mliter);
cuft *= bar_to_atm(bar); cuft *= bar_to_atm(bar);
psi = lrint(to_PSI(type->workingpressure)); int psi = lrint(to_PSI(type.workingpressure));
const char *fmt;
switch (psi) { switch (psi) {
case 2300 ... 2500: /* 2400 psi: LP tank */ case 2300 ... 2500: /* 2400 psi: LP tank */
fmt = "LP%d"; fmt = "LP%d";
@ -633,12 +618,7 @@ static void match_standard_cylinder(cylinder_type_t *type)
default: default:
return; return;
} }
len = snprintf(buffer, sizeof(buffer), fmt, (int)lrint(cuft)); type.description = format_string_std(fmt, (int)lrint(cuft));
p = (char *)malloc(len + 1);
if (!p)
return;
memcpy(p, buffer, len + 1);
type->description = p;
} }
/* /*
@ -651,14 +631,14 @@ static void match_standard_cylinder(cylinder_type_t *type)
* We internally use physical size only. But we save the workingpressure * We internally use physical size only. But we save the workingpressure
* so that we can do the conversion if required. * so that we can do the conversion if required.
*/ */
static void sanitize_cylinder_type(cylinder_type_t *type) static void sanitize_cylinder_type(cylinder_type_t &type)
{ {
/* If we have no working pressure, it had *better* be just a physical size! */ /* If we have no working pressure, it had *better* be just a physical size! */
if (!type->workingpressure.mbar) if (!type.workingpressure.mbar)
return; return;
/* No size either? Nothing to go on */ /* No size either? Nothing to go on */
if (!type->size.mliter) if (!type.size.mliter)
return; return;
/* Ok, we have both size and pressure: try to match a description */ /* Ok, we have both size and pressure: try to match a description */
@ -667,11 +647,9 @@ static void sanitize_cylinder_type(cylinder_type_t *type)
static void sanitize_cylinder_info(struct dive *dive) static void sanitize_cylinder_info(struct dive *dive)
{ {
int i; for (auto &cyl :dive->cylinders) {
sanitize_gasmix(cyl.gasmix);
for (i = 0; i < dive->cylinders.nr; i++) { sanitize_cylinder_type(cyl.type);
sanitize_gasmix(&get_cylinder(dive, i)->gasmix);
sanitize_cylinder_type(&get_cylinder(dive, i)->type);
} }
} }
@ -935,19 +913,19 @@ static void simplify_dc_pressures(struct divecomputer &dc)
/* Do we need a sensor -> cylinder mapping? */ /* Do we need a sensor -> cylinder mapping? */
static void fixup_start_pressure(struct dive *dive, int idx, pressure_t p) static void fixup_start_pressure(struct dive *dive, int idx, pressure_t p)
{ {
if (idx >= 0 && idx < dive->cylinders.nr) { if (idx >= 0 && static_cast<size_t>(idx) < dive->cylinders.size()) {
cylinder_t *cyl = get_cylinder(dive, idx); cylinder_t &cyl = dive->cylinders[idx];
if (p.mbar && !cyl->sample_start.mbar) if (p.mbar && !cyl.sample_start.mbar)
cyl->sample_start = p; cyl.sample_start = p;
} }
} }
static void fixup_end_pressure(struct dive *dive, int idx, pressure_t p) static void fixup_end_pressure(struct dive *dive, int idx, pressure_t p)
{ {
if (idx >= 0 && idx < dive->cylinders.nr) { if (idx >= 0 && static_cast<size_t>(idx) < dive->cylinders.size()) {
cylinder_t *cyl = get_cylinder(dive, idx); cylinder_t &cyl = dive->cylinders[idx];
if (p.mbar && !cyl->sample_end.mbar) if (p.mbar && !cyl.sample_end.mbar)
cyl->sample_end = p; cyl.sample_end = p;
} }
} }
@ -1003,13 +981,13 @@ static bool validate_gaschange(struct dive *dive, struct event &event)
if (event.gas.index >= 0) if (event.gas.index >= 0)
return true; return true;
index = find_best_gasmix_match(event.gas.mix, &dive->cylinders); index = find_best_gasmix_match(event.gas.mix, dive->cylinders);
if (index < 0 || index >= dive->cylinders.nr) if (index < 0 || static_cast<size_t>(index) >= dive->cylinders.size())
return false; return false;
/* Fix up the event to have the right information */ /* Fix up the event to have the right information */
event.gas.index = index; event.gas.index = index;
event.gas.mix = get_cylinder(dive, index)->gasmix; event.gas.mix = dive->cylinders[index].gasmix;
/* Convert to odd libdivecomputer format */ /* Convert to odd libdivecomputer format */
o2 = get_o2(event.gas.mix); o2 = get_o2(event.gas.mix);
@ -1094,7 +1072,7 @@ static void fixup_dc_sample_sensors(struct dive *dive, struct divecomputer &dc)
} }
// Ignore the sensors we have cylinders for // Ignore the sensors we have cylinders for
sensor_mask >>= dive->cylinders.nr; sensor_mask >>= dive->cylinders.size();
// Do we need to add empty cylinders? // Do we need to add empty cylinders?
while (sensor_mask) { while (sensor_mask) {
@ -1160,13 +1138,12 @@ struct dive *fixup_dive(struct dive *dive)
fixup_duration(dive); fixup_duration(dive);
fixup_watertemp(dive); fixup_watertemp(dive);
fixup_airtemp(dive); fixup_airtemp(dive);
for (i = 0; i < dive->cylinders.nr; i++) { for (auto &cyl: dive->cylinders) {
cylinder_t *cyl = get_cylinder(dive, i); add_cylinder_description(cyl.type);
add_cylinder_description(cyl->type); if (same_rounded_pressure(cyl.sample_start, cyl.start))
if (same_rounded_pressure(cyl->sample_start, cyl->start)) cyl.start.mbar = 0;
cyl->start.mbar = 0; if (same_rounded_pressure(cyl.sample_end, cyl.end))
if (same_rounded_pressure(cyl->sample_end, cyl->end)) cyl.end.mbar = 0;
cyl->end.mbar = 0;
} }
update_cylinder_related_info(dive); update_cylinder_related_info(dive);
for (i = 0; i < dive->weightsystems.nr; i++) { for (i = 0; i < dive->weightsystems.nr; i++) {
@ -1487,12 +1464,9 @@ pick_b:
* cylinder_use_type = an enum, one of {oxygen, diluent, bailout} */ * cylinder_use_type = an enum, one of {oxygen, diluent, bailout} */
int get_cylinder_idx_by_use(const struct dive *dive, enum cylinderuse cylinder_use_type) int get_cylinder_idx_by_use(const struct dive *dive, enum cylinderuse cylinder_use_type)
{ {
int cylinder_index; auto it = std::find_if(dive->cylinders.begin(), dive->cylinders.end(), [cylinder_use_type]
for (cylinder_index = 0; cylinder_index < dive->cylinders.nr; cylinder_index++) { (auto &cyl) { return cyl.cylinder_use == cylinder_use_type; });
if (get_cylinder(dive, cylinder_index)->cylinder_use == cylinder_use_type) return it != dive->cylinders.end() ? it - dive->cylinders.begin() : -1;
return cylinder_index; // return the index of the cylinder with that cylinder use type
}
return -1; // negative number means cylinder_use_type not found in list of cylinders
} }
/* Force an initial gaschange event to the (old) gas #0 */ /* Force an initial gaschange event to the (old) gas #0 */
@ -1580,13 +1554,13 @@ void cylinder_renumber(struct dive *dive, int mapping[])
dc_cylinder_renumber(dive, dc, mapping); dc_cylinder_renumber(dive, dc, mapping);
} }
int same_gasmix_cylinder(const cylinder_t *cyl, int cylid, const struct dive *dive, bool check_unused) int same_gasmix_cylinder(const cylinder_t &cyl, int cylid, const struct dive *dive, bool check_unused)
{ {
struct gasmix mygas = cyl->gasmix; struct gasmix mygas = cyl.gasmix;
for (int i = 0; i < dive->cylinders.nr; i++) { for (auto [i, cyl]: enumerated_range(dive->cylinders)) {
if (i == cylid) if (i == cylid)
continue; continue;
struct gasmix gas2 = get_cylinder(dive, i)->gasmix; struct gasmix gas2 = cyl.gasmix;
if (gasmix_distance(mygas, gas2) == 0 && (is_cylinder_used(dive, i) || check_unused)) if (gasmix_distance(mygas, gas2) == 0 && (is_cylinder_used(dive, i) || check_unused))
return i; return i;
} }
@ -1614,20 +1588,15 @@ static int different_manual_pressures(const cylinder_t *a, const cylinder_t *b)
*/ */
static int match_cylinder(const cylinder_t *cyl, const struct dive *dive, const bool try_match[]) static int match_cylinder(const cylinder_t *cyl, const struct dive *dive, const bool try_match[])
{ {
int i; for (auto [i, target]: enumerated_range(dive->cylinders)) {
for (i = 0; i < dive->cylinders.nr; i++) {
const cylinder_t *target;
if (!try_match[i]) if (!try_match[i])
continue; continue;
target = get_cylinder(dive, i); if (!same_gasmix(cyl->gasmix, target.gasmix))
if (!same_gasmix(cyl->gasmix, target->gasmix))
continue; continue;
if (cyl->cylinder_use != target->cylinder_use) if (cyl->cylinder_use != target.cylinder_use)
continue; continue;
if (different_manual_pressures(cyl, target)) if (different_manual_pressures(cyl, &target))
continue; continue;
/* open question: Should we check sizes too? */ /* open question: Should we check sizes too? */
@ -1679,8 +1648,8 @@ static void merge_one_cylinder(cylinder_t *a, const cylinder_t *b)
a->type.size.mliter = b->type.size.mliter; a->type.size.mliter = b->type.size.mliter;
if (!a->type.workingpressure.mbar) if (!a->type.workingpressure.mbar)
a->type.workingpressure.mbar = b->type.workingpressure.mbar; a->type.workingpressure.mbar = b->type.workingpressure.mbar;
if (empty_string(a->type.description)) if (a->type.description.empty())
a->type.description = copy_string(b->type.description); a->type.description = b->type.description;
/* If either cylinder has manually entered pressures, try to merge them. /* If either cylinder has manually entered pressures, try to merge them.
* Use pressures from divecomputer samples if only one cylinder has such a value. * Use pressures from divecomputer samples if only one cylinder has such a value.
@ -1697,24 +1666,24 @@ static void merge_one_cylinder(cylinder_t *a, const cylinder_t *b)
a->bestmix_he = a->bestmix_he && b->bestmix_he; a->bestmix_he = a->bestmix_he && b->bestmix_he;
} }
static bool cylinder_has_data(const cylinder_t *cyl) static bool cylinder_has_data(const cylinder_t &cyl)
{ {
return !cyl->type.size.mliter && return !cyl.type.size.mliter &&
!cyl->type.workingpressure.mbar && !cyl.type.workingpressure.mbar &&
!cyl->type.description && cyl.type.description.empty() &&
!cyl->gasmix.o2.permille && !cyl.gasmix.o2.permille &&
!cyl->gasmix.he.permille && !cyl.gasmix.he.permille &&
!cyl->start.mbar && !cyl.start.mbar &&
!cyl->end.mbar && !cyl.end.mbar &&
!cyl->sample_start.mbar && !cyl.sample_start.mbar &&
!cyl->sample_end.mbar && !cyl.sample_end.mbar &&
!cyl->gas_used.mliter && !cyl.gas_used.mliter &&
!cyl->deco_gas_used.mliter; !cyl.deco_gas_used.mliter;
} }
static bool cylinder_in_use(const struct dive *dive, int idx) static bool cylinder_in_use(const struct dive *dive, int idx)
{ {
if (idx < 0 || idx >= dive->cylinders.nr) if (idx < 0 || static_cast<size_t>(idx) >= dive->cylinders.size())
return false; return false;
/* This tests for gaschange events or pressure changes */ /* This tests for gaschange events or pressure changes */
@ -1722,7 +1691,7 @@ static bool cylinder_in_use(const struct dive *dive, int idx)
return true; return true;
/* This tests for typenames or gas contents */ /* This tests for typenames or gas contents */
return cylinder_has_data(get_cylinder(dive, idx)); return cylinder_has_data(dive->cylinders[idx]);
} }
/* /*
@ -1738,22 +1707,21 @@ static bool cylinder_in_use(const struct dive *dive, int idx)
static void merge_cylinders(struct dive *res, const struct dive *a, const struct dive *b, static void merge_cylinders(struct dive *res, const struct dive *a, const struct dive *b,
int mapping_a[], int mapping_b[]) int mapping_a[], int mapping_b[])
{ {
int i; size_t max_cylinders = a->cylinders.size() + b->cylinders.size();
int max_cylinders = a->cylinders.nr + b->cylinders.nr;
auto used_in_a = std::make_unique<bool[]>(max_cylinders); auto used_in_a = std::make_unique<bool[]>(max_cylinders);
auto used_in_b = std::make_unique<bool[]>(max_cylinders); auto used_in_b = std::make_unique<bool[]>(max_cylinders);
auto try_to_match = std::make_unique<bool[]>(max_cylinders); auto try_to_match = std::make_unique<bool[]>(max_cylinders);
std::fill(try_to_match.get(), try_to_match.get() + max_cylinders, false); std::fill(try_to_match.get(), try_to_match.get() + max_cylinders, false);
/* First, clear all cylinders in destination */ /* First, clear all cylinders in destination */
clear_cylinder_table(&res->cylinders); res->cylinders.clear();
/* Clear all cylinder mappings */ /* Clear all cylinder mappings */
std::fill(mapping_a, mapping_a + a->cylinders.nr, -1); std::fill(mapping_a, mapping_a + a->cylinders.size(), -1);
std::fill(mapping_b, mapping_b + b->cylinders.nr, -1); std::fill(mapping_b, mapping_b + b->cylinders.size(), -1);
/* Calculate usage map of cylinders, clear matching map */ /* Calculate usage map of cylinders, clear matching map */
for (i = 0; i < max_cylinders; i++) { for (size_t i = 0; i < max_cylinders; i++) {
used_in_a[i] = cylinder_in_use(a, i); used_in_a[i] = cylinder_in_use(a, i);
used_in_b[i] = cylinder_in_use(b, i); used_in_b[i] = cylinder_in_use(b, i);
} }
@ -1762,20 +1730,20 @@ static void merge_cylinders(struct dive *res, const struct dive *a, const struct
* For each cylinder in 'a' that is used, copy it to 'res'. * For each cylinder in 'a' that is used, copy it to 'res'.
* These are also potential matches for 'b' to use. * These are also potential matches for 'b' to use.
*/ */
for (i = 0; i < max_cylinders; i++) { for (size_t i = 0; i < max_cylinders; i++) {
int res_nr = res->cylinders.nr; size_t res_nr = res->cylinders.size();
if (!used_in_a[i]) if (!used_in_a[i])
continue; continue;
mapping_a[i] = res_nr; mapping_a[i] = static_cast<int>(res_nr);
try_to_match[res_nr] = true; try_to_match[res_nr] = true;
add_cloned_cylinder(&res->cylinders, *get_cylinder(a, i)); res->cylinders.push_back(a->cylinders[i]);
} }
/* /*
* For each cylinder in 'b' that is used, try to match it * For each cylinder in 'b' that is used, try to match it
* with an existing cylinder in 'res' from 'a' * with an existing cylinder in 'res' from 'a'
*/ */
for (i = 0; i < b->cylinders.nr; i++) { for (size_t i = 0; i < b->cylinders.size(); i++) {
int j; int j;
if (!used_in_b[i]) if (!used_in_b[i])
@ -1785,9 +1753,9 @@ static void merge_cylinders(struct dive *res, const struct dive *a, const struct
/* No match? Add it to the result */ /* No match? Add it to the result */
if (j < 0) { if (j < 0) {
int res_nr = res->cylinders.nr; size_t res_nr = res->cylinders.size();
mapping_b[i] = res_nr; mapping_b[i] = static_cast<int>(res_nr);
add_cloned_cylinder(&res->cylinders, *get_cylinder(b, i)); res->cylinders.push_back(b->cylinders[i]);
continue; continue;
} }
@ -2402,8 +2370,8 @@ struct dive *merge_dives(const struct dive *a, const struct dive *b, int offset,
taglist_merge(&res->tag_list, a->tag_list, b->tag_list); taglist_merge(&res->tag_list, a->tag_list, b->tag_list);
/* if we get dives without any gas / cylinder information in an import, make sure /* if we get dives without any gas / cylinder information in an import, make sure
* that there is at leatst one entry in the cylinder map for that dive */ * that there is at leatst one entry in the cylinder map for that dive */
auto cylinders_map_a = std::make_unique<int[]>(std::max(1, a->cylinders.nr)); auto cylinders_map_a = std::make_unique<int[]>(std::max(size_t(1), a->cylinders.size()));
auto cylinders_map_b = std::make_unique<int[]>(std::max(1, b->cylinders.nr)); auto cylinders_map_b = std::make_unique<int[]>(std::max(size_t(1), b->cylinders.size()));
merge_cylinders(res, a, b, cylinders_map_a.get(), cylinders_map_b.get()); merge_cylinders(res, a, b, cylinders_map_a.get(), cylinders_map_b.get());
merge_equipment(res, a, b); merge_equipment(res, a, b);
merge_temperatures(res, a, b); merge_temperatures(res, a, b);
@ -2456,7 +2424,7 @@ static void force_fixup_dive(struct dive *d)
int old_mintemp = d->mintemp.mkelvin; int old_mintemp = d->mintemp.mkelvin;
int old_maxtemp = d->maxtemp.mkelvin; int old_maxtemp = d->maxtemp.mkelvin;
duration_t old_duration = d->duration; duration_t old_duration = d->duration;
std::vector<start_end_pressure> old_pressures(d->cylinders.nr); std::vector<start_end_pressure> old_pressures(d->cylinders.size());
d->maxdepth.mm = 0; d->maxdepth.mm = 0;
dc->maxdepth.mm = 0; dc->maxdepth.mm = 0;
@ -2465,12 +2433,11 @@ static void force_fixup_dive(struct dive *d)
d->duration.seconds = 0; d->duration.seconds = 0;
d->maxtemp.mkelvin = 0; d->maxtemp.mkelvin = 0;
d->mintemp.mkelvin = 0; d->mintemp.mkelvin = 0;
for (int i = 0; i < d->cylinders.nr; i++) { for (auto [i, cyl]: enumerated_range(d->cylinders)) {
cylinder_t *cyl = get_cylinder(d, i); old_pressures[i].start = cyl.start;
old_pressures[i].start = cyl->start; old_pressures[i].end = cyl.end;
old_pressures[i].end = cyl->end; cyl.start.mbar = 0;
cyl->start.mbar = 0; cyl.end.mbar = 0;
cyl->end.mbar = 0;
} }
fixup_dive(d); fixup_dive(d);
@ -2489,11 +2456,11 @@ static void force_fixup_dive(struct dive *d)
if (!d->duration.seconds) if (!d->duration.seconds)
d->duration = old_duration; d->duration = old_duration;
for (int i = 0; i < d->cylinders.nr; i++) { for (auto [i, cyl]: enumerated_range(d->cylinders)) {
if (!get_cylinder(d, i)->start.mbar) if (!cyl.start.mbar)
get_cylinder(d, i)->start = old_pressures[i].start; cyl.start = old_pressures[i].start;
if (!get_cylinder(d, i)->end.mbar) if (!cyl.end.mbar)
get_cylinder(d, i)->end = old_pressures[i].end; cyl.end = old_pressures[i].end;
} }
} }
@ -3171,7 +3138,7 @@ gasmix_loop::gasmix_loop(const struct dive &d, const struct divecomputer &dc) :
dive(d), dc(dc), last(gasmix_air), loop("gaschange") dive(d), dc(dc), last(gasmix_air), loop("gaschange")
{ {
/* if there is no cylinder, return air */ /* if there is no cylinder, return air */
if (dive.cylinders.nr <= 0) if (dive.cylinders.empty())
return; return;
/* on first invocation, get initial gas mix and first event (if any) */ /* on first invocation, get initial gas mix and first event (if any) */
@ -3183,7 +3150,7 @@ gasmix_loop::gasmix_loop(const struct dive &d, const struct divecomputer &dc) :
gasmix gasmix_loop::next(int time) gasmix gasmix_loop::next(int time)
{ {
/* if there is no cylinder, return air */ /* if there is no cylinder, return air */
if (dive.cylinders.nr <= 0) if (dive.cylinders.empty())
return last; return last;
while (ev && ev->time.seconds <= time) { while (ev && ev->time.seconds <= time) {

View file

@ -30,7 +30,7 @@ struct dive {
struct dive_site *dive_site = nullptr; struct dive_site *dive_site = nullptr;
char *notes = nullptr; char *notes = nullptr;
char *diveguide = nullptr, *buddy = nullptr; char *diveguide = nullptr, *buddy = nullptr;
struct cylinder_table cylinders = { }; struct cylinder_table cylinders;
struct weightsystem_table weightsystems = { }; struct weightsystem_table weightsystems = { };
char *suit = nullptr; char *suit = nullptr;
int number = 0; int number = 0;
@ -74,7 +74,7 @@ extern bool dive_cache_is_valid(const struct dive *dive);
extern int get_cylinder_idx_by_use(const struct dive *dive, enum cylinderuse cylinder_use_type); extern int get_cylinder_idx_by_use(const struct dive *dive, enum cylinderuse cylinder_use_type);
extern void cylinder_renumber(struct dive *dive, int mapping[]); extern void cylinder_renumber(struct dive *dive, int mapping[]);
extern int same_gasmix_cylinder(const cylinder_t *cyl, int cylid, const struct dive *dive, bool check_unused); extern int same_gasmix_cylinder(const cylinder_t &cyl, int cylid, const struct dive *dive, bool check_unused);
/* when selectively copying dive information, which parts should be copied? */ /* when selectively copying dive information, which parts should be copied? */
struct dive_components { struct dive_components {
@ -190,7 +190,6 @@ extern struct event create_gas_switch_event(struct dive *dive, struct divecomput
extern void per_cylinder_mean_depth(const struct dive *dive, struct divecomputer *dc, int *mean, int *duration); extern void per_cylinder_mean_depth(const struct dive *dive, struct divecomputer *dc, int *mean, int *duration);
extern int get_cylinder_index(const struct dive *dive, const struct event &ev); extern int get_cylinder_index(const struct dive *dive, const struct event &ev);
extern struct gasmix get_gasmix_from_event(const struct dive *, const struct event &ev); extern struct gasmix get_gasmix_from_event(const struct dive *, const struct event &ev);
extern int nr_cylinders(const struct dive *dive);
extern int nr_weightsystems(const struct dive *dive); extern int nr_weightsystems(const struct dive *dive);
extern bool cylinder_with_sensor_sample(const struct dive *dive, int cylinder_id); extern bool cylinder_with_sensor_sample(const struct dive *dive, int cylinder_id);

View file

@ -32,19 +32,17 @@
*/ */
void get_dive_gas(const struct dive *dive, int *o2_p, int *he_p, int *o2max_p) void get_dive_gas(const struct dive *dive, int *o2_p, int *he_p, int *o2max_p)
{ {
int i;
int maxo2 = -1, maxhe = -1, mino2 = 1000; int maxo2 = -1, maxhe = -1, mino2 = 1000;
for (i = 0; i < dive->cylinders.nr; i++) { for (auto [i, cyl]: enumerated_range(dive->cylinders)) {
const cylinder_t *cyl = get_cylinder(dive, i); int o2 = get_o2(cyl.gasmix);
int o2 = get_o2(cyl->gasmix); int he = get_he(cyl.gasmix);
int he = get_he(cyl->gasmix);
if (!is_cylinder_used(dive, i)) if (!is_cylinder_used(dive, i))
continue; continue;
if (cyl->cylinder_use == OXYGEN) if (cyl.cylinder_use == OXYGEN)
continue; continue;
if (cyl->cylinder_use == NOT_USED) if (cyl.cylinder_use == NOT_USED)
continue; continue;
if (o2 > maxo2) if (o2 > maxo2)
maxo2 = o2; maxo2 = o2;
@ -337,12 +335,11 @@ static double calculate_airuse(const struct dive *dive)
if (dive->dcs[0].divemode == CCR) if (dive->dcs[0].divemode == CCR)
return 0.0; return 0.0;
for (int i = 0; i < dive->cylinders.nr; i++) { for (auto [i, cyl]: enumerated_range(dive->cylinders)) {
pressure_t start, end; pressure_t start, end;
const cylinder_t *cyl = get_cylinder(dive, i);
start = cyl->start.mbar ? cyl->start : cyl->sample_start; start = cyl.start.mbar ? cyl.start : cyl.sample_start;
end = cyl->end.mbar ? cyl->end : cyl->sample_end; end = cyl.end.mbar ? cyl.end : cyl.sample_end;
if (!end.mbar || start.mbar <= end.mbar) { if (!end.mbar || start.mbar <= end.mbar) {
// If a cylinder is used but we do not have info on amout of gas used // If a cylinder is used but we do not have info on amout of gas used
// better not pretend we know the total gas use. // better not pretend we know the total gas use.
@ -354,7 +351,7 @@ static double calculate_airuse(const struct dive *dive)
continue; continue;
} }
airuse += gas_volume(cyl, start) - gas_volume(cyl, end); airuse += gas_volume(&cyl, start) - gas_volume(&cyl, end);
} }
return airuse / 1000.0; return airuse / 1000.0;
} }

View file

@ -18,9 +18,43 @@
#include "divelog.h" #include "divelog.h"
#include "errorhelper.h" #include "errorhelper.h"
#include "pref.h" #include "pref.h"
#include "range.h"
#include "subsurface-string.h" #include "subsurface-string.h"
#include "table.h" #include "table.h"
cylinder_t::cylinder_t() = default;
cylinder_t::~cylinder_t() = default;
static cylinder_t make_surface_air_cylinder()
{
cylinder_t res;
res.cylinder_use = NOT_USED;
return res;
}
static const cylinder_t surface_air_cylinder = make_surface_air_cylinder();
static void warn_index(size_t i, size_t max)
{
if (i >= max + 1) {
report_info("Warning: accessing invalid cylinder %lu (%lu existing)",
static_cast<unsigned long>(i), static_cast<unsigned long>(max));
}
}
cylinder_t &cylinder_table::operator[](size_t i)
{
warn_index(i, size());
return i < size() ? std::vector<cylinder_t>::operator[](i)
: const_cast<cylinder_t &>(surface_air_cylinder);
}
const cylinder_t &cylinder_table::operator[](size_t i) const
{
warn_index(i, size());
return i < size() ? std::vector<cylinder_t>::operator[](i)
: surface_air_cylinder;
}
/* Warning: this has strange semantics for C-code! Not the weightsystem object /* Warning: this has strange semantics for C-code! Not the weightsystem object
* is freed, but the data it references. The object itself is passed in by value. * is freed, but the data it references. The object itself is passed in by value.
* This is due to the fact how the table macros work. * This is due to the fact how the table macros work.
@ -31,12 +65,6 @@ void free_weightsystem(weightsystem_t ws)
ws.description = NULL; ws.description = NULL;
} }
void free_cylinder(cylinder_t c)
{
free((void *)c.type.description);
c.type.description = NULL;
}
void copy_weights(const struct weightsystem_table *s, struct weightsystem_table *d) void copy_weights(const struct weightsystem_table *s, struct weightsystem_table *d)
{ {
clear_weightsystem_table(d); clear_weightsystem_table(d);
@ -44,14 +72,6 @@ void copy_weights(const struct weightsystem_table *s, struct weightsystem_table
add_cloned_weightsystem(d, s->weightsystems[i]); add_cloned_weightsystem(d, s->weightsystems[i]);
} }
void copy_cylinders(const struct cylinder_table *s, struct cylinder_table *d)
{
int i;
clear_cylinder_table(d);
for (i = 0; i < s->nr; i++)
add_cloned_cylinder(d, s->cylinders[i]);
}
/* weightsystem table functions */ /* weightsystem table functions */
//static MAKE_GET_IDX(weightsystem_table, weightsystem_t, weightsystems) //static MAKE_GET_IDX(weightsystem_table, weightsystem_t, weightsystems)
static MAKE_GROW_TABLE(weightsystem_table, weightsystem_t, weightsystems) static MAKE_GROW_TABLE(weightsystem_table, weightsystem_t, weightsystems)
@ -62,16 +82,6 @@ static MAKE_REMOVE_FROM(weightsystem_table, weightsystems)
//MAKE_REMOVE(weightsystem_table, weightsystem_t, weightsystem) //MAKE_REMOVE(weightsystem_table, weightsystem_t, weightsystem)
MAKE_CLEAR_TABLE(weightsystem_table, weightsystems, weightsystem) MAKE_CLEAR_TABLE(weightsystem_table, weightsystems, weightsystem)
/* cylinder table functions */
//static MAKE_GET_IDX(cylinder_table, cylinder_t, cylinders)
static MAKE_GROW_TABLE(cylinder_table, cylinder_t, cylinders)
//static MAKE_GET_INSERTION_INDEX(cylinder_table, cylinder_t, cylinders, cylinder_less_than)
static MAKE_ADD_TO(cylinder_table, cylinder_t, cylinders)
static MAKE_REMOVE_FROM(cylinder_table, cylinders)
//MAKE_SORT(cylinder_table, cylinder_t, cylinders, comp_cylinders)
//MAKE_REMOVE(cylinder_table, cylinder_t, cylinder)
MAKE_CLEAR_TABLE(cylinder_table, cylinders, cylinder)
const char *cylinderuse_text[NUM_GAS_USE] = { const char *cylinderuse_text[NUM_GAS_USE] = {
QT_TRANSLATE_NOOP("gettextFromC", "OC-gas"), QT_TRANSLATE_NOOP("gettextFromC", "diluent"), QT_TRANSLATE_NOOP("gettextFromC", "oxygen"), QT_TRANSLATE_NOOP("gettextFromC", "not used") QT_TRANSLATE_NOOP("gettextFromC", "OC-gas"), QT_TRANSLATE_NOOP("gettextFromC", "diluent"), QT_TRANSLATE_NOOP("gettextFromC", "oxygen"), QT_TRANSLATE_NOOP("gettextFromC", "not used")
}; };
@ -144,11 +154,11 @@ std::pair<volume_t, pressure_t> get_tank_info_data(const std::vector<tank_info>
void add_cylinder_description(const cylinder_type_t &type) void add_cylinder_description(const cylinder_type_t &type)
{ {
std::string desc = type.description ? type.description : std::string(); const std::string &desc = type.description;
if (desc.empty()) if (desc.empty())
return; return;
if (std::any_of(tank_info_table.begin(), tank_info_table.end(), if (std::any_of(tank_info_table.begin(), tank_info_table.end(),
[&type](const tank_info &info) { return info.name == type.description; })) [&desc](const tank_info &info) { return info.name == desc; }))
return; return;
add_tank_info_metric(tank_info_table, desc, type.size.mliter, add_tank_info_metric(tank_info_table, desc, type.size.mliter,
type.workingpressure.mbar / 1000); type.workingpressure.mbar / 1000);
@ -191,30 +201,16 @@ void add_cloned_weightsystem(struct weightsystem_table *t, weightsystem_t ws)
add_to_weightsystem_table(t, t->nr, clone_weightsystem(ws)); add_to_weightsystem_table(t, t->nr, clone_weightsystem(ws));
} }
cylinder_t clone_cylinder(cylinder_t cyl) /* Add a clone of a weightsystem to the end of a weightsystem table.
* Cloned means that the description-string is copied. */
void add_cloned_weightsystem_at(struct weightsystem_table *t, weightsystem_t ws)
{ {
cylinder_t res = cyl; add_to_weightsystem_table(t, t->nr, clone_weightsystem(ws));
res.type.description = copy_string(res.type.description);
return res;
} }
void add_cylinder(struct cylinder_table *t, int idx, cylinder_t cyl) void add_cylinder(struct cylinder_table *t, int idx, cylinder_t cyl)
{ {
add_to_cylinder_table(t, idx, cyl); t->insert(t->begin() + idx, std::move(cyl));
/* FIXME: This is a horrible hack: we make sure that at the end of
* every single cylinder table there is an empty cylinder that can
* be used by the planner as "surface air" cylinder. Fix this.
*/
add_to_cylinder_table(t, t->nr, cylinder_t());
t->nr--;
t->cylinders[t->nr].cylinder_use = NOT_USED;
}
/* Add a clone of a cylinder to the end of a cylinder table.
* Cloned means that the description-string is copied. */
void add_cloned_cylinder(struct cylinder_table *t, cylinder_t cyl)
{
add_cylinder(t, t->nr, clone_cylinder(cyl));
} }
bool same_weightsystem(weightsystem_t w1, weightsystem_t w2) bool same_weightsystem(weightsystem_t w1, weightsystem_t w2)
@ -250,17 +246,12 @@ int gas_volume(const cylinder_t *cyl, pressure_t p)
return lrint(cyl->type.size.mliter * bar_to_atm(bar) / z_factor); return lrint(cyl->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)
{ {
int i;
int best = -1, score = INT_MAX; int best = -1, score = INT_MAX;
for (i = 0; i < cylinders->nr; i++) { for (auto [i, match]: enumerated_range(cylinders)) {
const cylinder_t *match; int distance = gasmix_distance(mix, match.gasmix);
int distance;
match = cylinders->cylinders + i;
distance = gasmix_distance(mix, match->gasmix);
if (distance >= score) if (distance >= score)
continue; continue;
best = i; best = i;
@ -336,10 +327,8 @@ void reset_tank_info_table(std::vector<tank_info> &table)
/* Add cylinders from dive list */ /* Add cylinders from dive list */
for (int i = 0; i < divelog.dives->nr; ++i) { for (int i = 0; i < divelog.dives->nr; ++i) {
const struct dive *dive = divelog.dives->dives[i]; const struct dive *dive = divelog.dives->dives[i];
for (int j = 0; j < dive->cylinders.nr; j++) { for (auto &cyl: dive->cylinders)
const cylinder_t *cyl = get_cylinder(dive, j); add_cylinder_description(cyl.type);
add_cylinder_description(cyl->type);
}
} }
} }
@ -357,7 +346,7 @@ struct std::vector<ws_info> ws_info_table = {
void remove_cylinder(struct dive *dive, int idx) void remove_cylinder(struct dive *dive, int idx)
{ {
remove_from_cylinder_table(&dive->cylinders, idx); dive->cylinders.erase(dive->cylinders.begin() + idx);
} }
void remove_weightsystem(struct dive *dive, int idx) void remove_weightsystem(struct dive *dive, int idx)
@ -380,68 +369,61 @@ void reset_cylinders(struct dive *dive, bool track_gas)
{ {
pressure_t decopo2 = {.mbar = prefs.decopo2}; pressure_t decopo2 = {.mbar = prefs.decopo2};
for (int i = 0; i < dive->cylinders.nr; i++) { for (cylinder_t &cyl: dive->cylinders) {
cylinder_t *cyl = get_cylinder(dive, i); if (cyl.depth.mm == 0) /* if the gas doesn't give a mod, calculate based on prefs */
if (cyl->depth.mm == 0) /* if the gas doesn't give a mod, calculate based on prefs */ cyl.depth = gas_mod(cyl.gasmix, decopo2, dive, M_OR_FT(3,10));
cyl->depth = gas_mod(cyl->gasmix, decopo2, dive, M_OR_FT(3,10));
if (track_gas) if (track_gas)
cyl->start.mbar = cyl->end.mbar = cyl->type.workingpressure.mbar; cyl.start.mbar = cyl.end.mbar = cyl.type.workingpressure.mbar;
cyl->gas_used.mliter = 0; cyl.gas_used.mliter = 0;
cyl->deco_gas_used.mliter = 0; cyl.deco_gas_used.mliter = 0;
} }
} }
static void copy_cylinder_type(const cylinder_t *s, cylinder_t *d) static void copy_cylinder_type(const cylinder_t &s, cylinder_t &d)
{ {
free_cylinder(*d); d.type = s.type;
d->type = s->type; d.gasmix = s.gasmix;
d->type.description = s->type.description ? strdup(s->type.description) : NULL; d.depth = s.depth;
d->gasmix = s->gasmix; d.cylinder_use = s.cylinder_use;
d->depth = s->depth; d.manually_added = true;
d->cylinder_use = s->cylinder_use;
d->manually_added = true;
} }
/* copy the equipment data part of the cylinders but keep pressures */ /* copy the equipment data part of the cylinders but keep pressures */
void copy_cylinder_types(const struct dive *s, struct dive *d) void copy_cylinder_types(const struct dive *s, struct dive *d)
{ {
int i;
if (!s || !d) if (!s || !d)
return; return;
for (i = 0; i < s->cylinders.nr && i < d->cylinders.nr; i++) for (size_t i = 0; i < s->cylinders.size() && i < d->cylinders.size(); i++)
copy_cylinder_type(get_cylinder(s, i), get_cylinder(d, i)); copy_cylinder_type(s->cylinders[i], d->cylinders[i]);
for ( ; i < s->cylinders.nr; i++) for (size_t i = d->cylinders.size(); i < s->cylinders.size(); i++)
add_cloned_cylinder(&d->cylinders, *get_cylinder(s, i)); d->cylinders.push_back(s->cylinders[i]);
} }
cylinder_t *add_empty_cylinder(struct cylinder_table *t) cylinder_t *add_empty_cylinder(struct cylinder_table *t)
{ {
cylinder_t cyl; t->emplace_back();
cyl.type.description = strdup(""); return &t->back();
add_cylinder(t, t->nr, cyl);
return &t->cylinders[t->nr - 1];
} }
/* access to cylinders is controlled by two functions: /* access to cylinders is controlled by two functions:
* - get_cylinder() returns the cylinder of a dive and supposes that * - get_cylinder() returns the cylinder of a dive and supposes that
* the cylinder with the given index exists. If it doesn't, an error * the cylinder with the given index exists. If it doesn't, an error
* message is printed and NULL returned. * message is printed and the "surface air" cylinder returned.
* (NOTE: this MUST not be written into!).
* - get_or_create_cylinder() creates an empty cylinder if it doesn't exist. * - get_or_create_cylinder() creates an empty cylinder if it doesn't exist.
* Multiple cylinders might be created if the index is bigger than the * Multiple cylinders might be created if the index is bigger than the
* number of existing cylinders * number of existing cylinders
*/ */
cylinder_t *get_cylinder(const struct dive *d, int idx) cylinder_t *get_cylinder(struct dive *d, int idx)
{ {
/* FIXME: The planner uses a dummy cylinder one past the official number of cylinders return &d->cylinders[idx];
* in the table to mark no-cylinder surface interavals. This is horrendous. Fix ASAP. */ }
// if (idx < 0 || idx >= d->cylinders.nr) {
if (idx < 0 || idx >= d->cylinders.nr + 1 || idx >= d->cylinders.allocated) { const cylinder_t *get_cylinder(const struct dive *d, int idx)
report_info("Warning: accessing invalid cylinder %d (%d existing)", idx, d->cylinders.nr); {
return NULL; return &d->cylinders[idx];
}
return &d->cylinders.cylinders[idx];
} }
cylinder_t *get_or_create_cylinder(struct dive *d, int idx) cylinder_t *get_or_create_cylinder(struct dive *d, int idx)
@ -450,9 +432,9 @@ cylinder_t *get_or_create_cylinder(struct dive *d, int idx)
report_info("Warning: accessing invalid cylinder %d", idx); report_info("Warning: accessing invalid cylinder %d", idx);
return NULL; return NULL;
} }
while (idx >= d->cylinders.nr) while (static_cast<size_t>(idx) >= d->cylinders.size())
add_empty_cylinder(&d->cylinders); add_empty_cylinder(&d->cylinders);
return &d->cylinders.cylinders[idx]; return &d->cylinders[idx];
} }
/* if a default cylinder is set, use that */ /* if a default cylinder is set, use that */
@ -465,7 +447,7 @@ void fill_default_cylinder(const struct dive *dive, cylinder_t *cyl)
return; return;
for (auto &ti: tank_info_table) { for (auto &ti: tank_info_table) {
if (ti.name == cyl_name) { if (ti.name == cyl_name) {
cyl->type.description = strdup(ti.name.c_str()); cyl->type.description = ti.name;
if (ti.ml) { if (ti.ml) {
cyl->type.size.mliter = ti.ml; cyl->type.size.mliter = ti.ml;
cyl->type.workingpressure.mbar = ti.bar * 1000; cyl->type.workingpressure.mbar = ti.bar * 1000;
@ -481,10 +463,16 @@ void fill_default_cylinder(const struct dive *dive, cylinder_t *cyl)
} }
} }
cylinder_t default_cylinder(const struct dive *d)
{
cylinder_t res;
fill_default_cylinder(d, &res);
return res;
}
cylinder_t create_new_cylinder(const struct dive *d) cylinder_t create_new_cylinder(const struct dive *d)
{ {
cylinder_t cyl; cylinder_t cyl = default_cylinder(d);
fill_default_cylinder(d, &cyl);
cyl.start = cyl.type.workingpressure; cyl.start = cyl.type.workingpressure;
cyl.cylinder_use = OC_GAS; cyl.cylinder_use = OC_GAS;
return cyl; return cyl;
@ -500,7 +488,7 @@ cylinder_t create_new_manual_cylinder(const struct dive *d)
void add_default_cylinder(struct dive *d) void add_default_cylinder(struct dive *d)
{ {
// Only add if there are no cylinders yet // Only add if there are no cylinders yet
if (d->cylinders.nr > 0) if (!d->cylinders.empty())
return; return;
cylinder_t cyl; cylinder_t cyl;
@ -508,7 +496,7 @@ void add_default_cylinder(struct dive *d)
cyl = create_new_cylinder(d); cyl = create_new_cylinder(d);
} else { } else {
// roughly an AL80 // roughly an AL80
cyl.type.description = strdup(translate("gettextFromC", "unknown")); cyl.type.description = translate("gettextFromC", "unknown");
cyl.type.size.mliter = 11100; cyl.type.size.mliter = 11100;
cyl.type.workingpressure.mbar = 207000; cyl.type.workingpressure.mbar = 207000;
} }
@ -521,11 +509,11 @@ static bool show_cylinder(const struct dive *d, int i)
if (is_cylinder_used(d, i)) if (is_cylinder_used(d, i))
return true; return true;
const cylinder_t *cyl = &d->cylinders.cylinders[i]; const cylinder_t &cyl = d->cylinders[i];
if (cyl->start.mbar || cyl->sample_start.mbar || if (cyl.start.mbar || cyl.sample_start.mbar ||
cyl->end.mbar || cyl->sample_end.mbar) cyl.end.mbar || cyl.sample_end.mbar)
return true; return true;
if (cyl->manually_added) if (cyl.manually_added)
return true; return true;
/* /*
@ -538,10 +526,10 @@ static bool show_cylinder(const struct dive *d, int i)
/* The unused cylinders at the end of the cylinder list are hidden. */ /* The unused cylinders at the end of the cylinder list are hidden. */
int first_hidden_cylinder(const struct dive *d) int first_hidden_cylinder(const struct dive *d)
{ {
int res = d->cylinders.nr; size_t res = d->cylinders.size();
while (res > 0 && !show_cylinder(d, res - 1)) while (res > 0 && !show_cylinder(d, res - 1))
--res; --res;
return res; return static_cast<int>(res);
} }
#ifdef DEBUG_CYL #ifdef DEBUG_CYL
@ -551,7 +539,7 @@ void dump_cylinders(struct dive *dive, bool verbose)
for (int i = 0; i < dive->cylinders; i++) { for (int i = 0; i < dive->cylinders; i++) {
cylinder_t *cyl = get_cylinder(dive, i); cylinder_t *cyl = get_cylinder(dive, i);
printf("%02d: Type %s, %3.1fl, %3.0fbar\n", i, cyl->type.description, cyl->type.size.mliter / 1000.0, cyl->type.workingpressure.mbar / 1000.0); printf("%02d: Type %s, %3.1fl, %3.0fbar\n", i, cyl->type.description.c_str(), cyl->type.size.mliter / 1000.0, cyl->type.workingpressure.mbar / 1000.0);
printf(" Gasmix O2 %2.0f%% He %2.0f%%\n", cyl->gasmix.o2.permille / 10.0, cyl->gasmix.he.permille / 10.0); printf(" Gasmix O2 %2.0f%% He %2.0f%%\n", cyl->gasmix.o2.permille / 10.0, cyl->gasmix.he.permille / 10.0);
printf(" Pressure Start %3.0fbar End %3.0fbar Sample start %3.0fbar Sample end %3.0fbar\n", cyl->start.mbar / 1000.0, cyl->end.mbar / 1000.0, cyl->sample_start.mbar / 1000.0, cyl->sample_end.mbar / 1000.0); printf(" Pressure Start %3.0fbar End %3.0fbar Sample start %3.0fbar Sample end %3.0fbar\n", cyl->start.mbar / 1000.0, cyl->end.mbar / 1000.0, cyl->sample_start.mbar / 1000.0, cyl->sample_end.mbar / 1000.0);
if (verbose) { if (verbose) {

View file

@ -17,7 +17,7 @@ struct cylinder_type_t
{ {
volume_t size; volume_t size;
pressure_t workingpressure; pressure_t workingpressure;
const char *description = nullptr; /* "LP85", "AL72", "AL80", "HP100+" or whatever */ std::string description; /* "LP85", "AL72", "AL80", "HP100+" or whatever */
}; };
struct cylinder_t struct cylinder_t
@ -32,17 +32,23 @@ struct cylinder_t
enum cylinderuse cylinder_use = OC_GAS; enum cylinderuse cylinder_use = OC_GAS;
bool bestmix_o2 = false; bool bestmix_o2 = false;
bool bestmix_he = false; bool bestmix_he = false;
cylinder_t();
~cylinder_t();
}; };
/* Table of cylinders. Attention: this stores cylinders, /* Table of cylinders.
* *not* pointers to cylinders. This has two crucial consequences: * This is a crazy class: it is basically a std::vector<>, but overrides
* 1) Pointers to cylinders are not stable. They may be * the [] accessor functions and allows out-of-bound accesses.
* invalidated if the table is reallocated. * This is used in the planner, which uses "max_index + 1" for the
* 2) add_cylinder(), etc. take ownership of the * surface air cylinder.
* cylinder. Notably of the description string. */ * Note: an out-of-bound access returns a reference to an object with
struct cylinder_table { * static linkage that MUST NOT be written into.
int nr, allocated; * Yes, this is all very mad, but it grew historically.
cylinder_t *cylinders; */
struct cylinder_table : public std::vector<cylinder_t> {
cylinder_t &operator[](size_t i);
const cylinder_t &operator[](size_t i) const;
}; };
struct weightsystem_t struct weightsystem_t
@ -68,16 +74,13 @@ struct weightsystem_table {
extern enum cylinderuse cylinderuse_from_text(const char *text); extern enum cylinderuse cylinderuse_from_text(const char *text);
extern void copy_weights(const struct weightsystem_table *s, struct weightsystem_table *d); extern void copy_weights(const struct weightsystem_table *s, struct weightsystem_table *d);
extern void copy_cylinders(const struct cylinder_table *s, struct cylinder_table *d);
extern weightsystem_t clone_weightsystem(weightsystem_t ws); extern weightsystem_t clone_weightsystem(weightsystem_t ws);
extern void free_weightsystem(weightsystem_t ws); extern void free_weightsystem(weightsystem_t ws);
extern void copy_cylinder_types(const struct dive *s, struct dive *d); extern void copy_cylinder_types(const struct dive *s, struct dive *d);
extern void add_cloned_weightsystem(struct weightsystem_table *t, weightsystem_t ws); extern void add_cloned_weightsystem(struct weightsystem_table *t, weightsystem_t ws);
extern cylinder_t clone_cylinder(cylinder_t cyl);
extern void free_cylinder(cylinder_t cyl);
extern cylinder_t *add_empty_cylinder(struct cylinder_table *t); extern cylinder_t *add_empty_cylinder(struct cylinder_table *t);
extern void add_cloned_cylinder(struct cylinder_table *t, cylinder_t cyl); extern cylinder_t *get_cylinder(struct dive *d, int idx);
extern cylinder_t *get_cylinder(const struct dive *d, int idx); extern const cylinder_t *get_cylinder(const struct dive *d, int idx);
extern cylinder_t *get_or_create_cylinder(struct dive *d, int idx); extern cylinder_t *get_or_create_cylinder(struct dive *d, int idx);
extern bool same_weightsystem(weightsystem_t w1, weightsystem_t w2); extern bool same_weightsystem(weightsystem_t w1, weightsystem_t w2);
extern void remove_cylinder(struct dive *dive, int idx); extern void remove_cylinder(struct dive *dive, int idx);
@ -85,8 +88,9 @@ extern void remove_weightsystem(struct dive *dive, int idx);
extern void set_weightsystem(struct dive *dive, int idx, weightsystem_t ws); extern void set_weightsystem(struct dive *dive, int idx, weightsystem_t ws);
extern void reset_cylinders(struct dive *dive, bool track_gas); extern void reset_cylinders(struct dive *dive, bool track_gas);
extern int gas_volume(const cylinder_t *cyl, pressure_t p); /* Volume in mliter of a cylinder at pressure 'p' */ extern int gas_volume(const cylinder_t *cyl, pressure_t p); /* Volume in mliter of a cylinder at pressure 'p' */
extern int find_best_gasmix_match(struct gasmix mix, const struct cylinder_table *cylinders); extern int find_best_gasmix_match(struct gasmix mix, const struct cylinder_table &cylinders);
extern void fill_default_cylinder(const struct dive *dive, cylinder_t *cyl); /* dive is needed to fill out MOD, which depends on salinity. */ extern void fill_default_cylinder(const struct dive *dive, cylinder_t *cyl); /* dive is needed to fill out MOD, which depends on salinity. */
extern cylinder_t default_cylinder(const struct dive *d);
extern cylinder_t create_new_manual_cylinder(const struct dive *dive); /* dive is needed to fill out MOD, which depends on salinity. */ extern cylinder_t create_new_manual_cylinder(const struct dive *dive); /* dive is needed to fill out MOD, which depends on salinity. */
extern void add_default_cylinder(struct dive *dive); extern void add_default_cylinder(struct dive *dive);
extern int first_hidden_cylinder(const struct dive *d); extern int first_hidden_cylinder(const struct dive *d);
@ -99,7 +103,6 @@ extern void clear_weightsystem_table(struct weightsystem_table *);
extern void add_to_weightsystem_table(struct weightsystem_table *, int idx, weightsystem_t ws); extern void add_to_weightsystem_table(struct weightsystem_table *, int idx, weightsystem_t ws);
/* Cylinder table functions */ /* Cylinder table functions */
extern void clear_cylinder_table(struct cylinder_table *);
extern void add_cylinder(struct cylinder_table *, int idx, cylinder_t cyl); extern void add_cylinder(struct cylinder_table *, int idx, cylinder_t cyl);
void get_gas_string(struct gasmix gasmix, char *text, int len); void get_gas_string(struct gasmix gasmix, char *text, int len);

View file

@ -857,8 +857,8 @@ static bool has_weight_type(const filter_constraint &c, const struct dive *d)
static bool has_cylinder_type(const filter_constraint &c, const struct dive *d) static bool has_cylinder_type(const filter_constraint &c, const struct dive *d)
{ {
QStringList cylinderTypes; QStringList cylinderTypes;
for (int i = 0; i < d->cylinders.nr; ++i) for (const cylinder_t &cyl: d->cylinders)
cylinderTypes.push_back(d->cylinders.cylinders[i].type.description); cylinderTypes.push_back(QString::fromStdString(cyl.type.description));
return check(c, cylinderTypes); return check(c, cylinderTypes);
} }
@ -904,22 +904,15 @@ static bool check_numerical_range_non_zero(const filter_constraint &c, int v)
static bool check_cylinder_size(const filter_constraint &c, const struct dive *d) static bool check_cylinder_size(const filter_constraint &c, const struct dive *d)
{ {
for (int i = 0; i < d->cylinders.nr; ++i) { return std::any_of(d->cylinders.begin(), d->cylinders.end(), [&c](auto &cyl)
const cylinder_t &cyl = d->cylinders.cylinders[i]; { return cyl.type.size.mliter &&
if (cyl.type.size.mliter && check_numerical_range(c, cyl.type.size.mliter)) check_numerical_range(c, cyl.type.size.mliter); });
return true;
}
return false;
} }
static bool check_gas_range(const filter_constraint &c, const struct dive *d, gas_component component) static bool check_gas_range(const filter_constraint &c, const struct dive *d, gas_component component)
{ {
for (int i = 0; i < d->cylinders.nr; ++i) { return std::any_of(d->cylinders.begin(), d->cylinders.end(), [&c, &component](auto &cyl)
const cylinder_t &cyl = d->cylinders.cylinders[i]; { return check_numerical_range(c, get_gas_component_fraction(cyl.gasmix, component).permille); });
if (check_numerical_range(c, get_gas_component_fraction(cyl.gasmix, component).permille))
return true;
}
return false;
} }
static long days_since_epoch(timestamp_t timestamp) static long days_since_epoch(timestamp_t timestamp)

View file

@ -125,10 +125,8 @@ static std::vector<QString> getWords(const dive *d)
tokenize(QString(d->suit), res); tokenize(QString(d->suit), res);
for (const tag_entry *tag = d->tag_list; tag; tag = tag->next) for (const tag_entry *tag = d->tag_list; tag; tag = tag->next)
tokenize(QString::fromStdString(tag->tag->name), res); tokenize(QString::fromStdString(tag->tag->name), res);
for (int i = 0; i < d->cylinders.nr; ++i) { for (auto &cyl: d->cylinders)
const cylinder_t &cyl = *get_cylinder(d, i); tokenize(QString::fromStdString(cyl.type.description), res);
tokenize(QString(cyl.type.description), res);
}
for (int i = 0; i < d->weightsystems.nr; ++i) { for (int i = 0; i < d->weightsystems.nr; ++i) {
const weightsystem_t &ws = d->weightsystems.weightsystems[i]; const weightsystem_t &ws = d->weightsystems.weightsystems[i];
tokenize(QString(ws.description), res); tokenize(QString(ws.description), res);

View file

@ -40,20 +40,20 @@ int same_gasmix(struct gasmix a, struct gasmix b)
return get_o2(a) == get_o2(b) && get_he(a) == get_he(b); return get_o2(a) == get_o2(b) && get_he(a) == get_he(b);
} }
void sanitize_gasmix(struct gasmix *mix) void sanitize_gasmix(struct gasmix &mix)
{ {
unsigned int o2, he; unsigned int o2, he;
o2 = get_o2(*mix); o2 = get_o2(mix);
he = get_he(*mix); he = get_he(mix);
/* Regular air: leave empty */ /* Regular air: leave empty */
if (!he) { if (!he) {
if (!o2) if (!o2)
return; return;
/* 20.8% to 21% O2 is just air */ /* 20.8% to 21% O2 is just air */
if (gasmix_is_air(*mix)) { if (gasmix_is_air(mix)) {
mix->o2.permille = 0; mix.o2.permille = 0;
return; return;
} }
} }
@ -62,7 +62,7 @@ void sanitize_gasmix(struct gasmix *mix)
if (o2 <= 1000 && he <= 1000 && o2 + he <= 1000) if (o2 <= 1000 && he <= 1000 && o2 + he <= 1000)
return; return;
report_info("Odd gasmix: %u O2 %u He", o2, he); report_info("Odd gasmix: %u O2 %u He", o2, he);
*mix = gasmix_air; mix = gasmix_air;
} }
int gasmix_distance(struct gasmix a, struct gasmix b) int gasmix_distance(struct gasmix a, struct gasmix b)

View file

@ -58,7 +58,7 @@ struct gas_pressures {
double o2 = 0.0, n2 = 0.0, he = 0.0; double o2 = 0.0, n2 = 0.0, he = 0.0;
}; };
extern void sanitize_gasmix(struct gasmix *mix); extern void sanitize_gasmix(struct gasmix &mix);
extern int gasmix_distance(struct gasmix a, struct gasmix b); extern int gasmix_distance(struct gasmix a, struct gasmix b);
extern fraction_t get_gas_component_fraction(struct gasmix mix, enum gas_component component); extern fraction_t get_gas_component_fraction(struct gasmix mix, enum gas_component component);
extern gas_pressures fill_pressures(double amb_pressure, struct gasmix mix, double po2, enum divemode_t dctype); extern gas_pressures fill_pressures(double amb_pressure, struct gasmix mix, double po2, enum divemode_t dctype);

View file

@ -310,13 +310,13 @@ static void debug_print_pressures(struct plot_info &pi)
void populate_pressure_information(const struct dive *dive, const struct divecomputer *dc, struct plot_info &pi, int sensor) void populate_pressure_information(const struct dive *dive, const struct divecomputer *dc, struct plot_info &pi, int sensor)
{ {
int first, last, cyl; int first, last, cyl;
cylinder_t *cylinder = get_cylinder(dive, sensor); const cylinder_t *cylinder = get_cylinder(dive, sensor);
std::vector<pr_track_t> track; std::vector<pr_track_t> track;
size_t current = std::string::npos; size_t current = std::string::npos;
int missing_pr = 0, dense = 1; int missing_pr = 0, dense = 1;
const double gasfactor[5] = {1.0, 0.0, prefs.pscr_ratio/1000.0, 1.0, 1.0 }; const double gasfactor[5] = {1.0, 0.0, prefs.pscr_ratio/1000.0, 1.0, 1.0 };
if (sensor < 0 || sensor >= dive->cylinders.nr) if (sensor < 0 || static_cast<size_t>(sensor) >= dive->cylinders.size())
return; return;
/* if we have no pressure data whatsoever, this is pointless, so let's just return */ /* if we have no pressure data whatsoever, this is pointless, so let's just return */

View file

@ -494,7 +494,6 @@ int parse_txt_file(const char *filename, const char *csv, struct divelog *log)
bool has_depth = false, has_setpoint = false, has_ndl = false; bool has_depth = false, has_setpoint = false, has_ndl = false;
char *lineptr; char *lineptr;
int prev_time = 0; int prev_time = 0;
cylinder_t cyl;
struct divecomputer *dc; struct divecomputer *dc;
struct tm cur_tm; struct tm cur_tm;
@ -517,26 +516,32 @@ int parse_txt_file(const char *filename, const char *csv, struct divelog *log)
dive->dcs[0].divemode = CCR; dive->dcs[0].divemode = CCR;
dive->dcs[0].no_o2sensors = 2; dive->dcs[0].no_o2sensors = 2;
cyl.cylinder_use = OXYGEN; {
cyl.type.size.mliter = 3000; cylinder_t cyl;
cyl.type.workingpressure.mbar = 200000; cyl.cylinder_use = OXYGEN;
cyl.type.description = "3l Mk6"; cyl.type.size.mliter = 3000;
cyl.gasmix.o2.permille = 1000; cyl.type.workingpressure.mbar = 200000;
cyl.manually_added = true; cyl.type.description = "3l Mk6";
cyl.bestmix_o2 = 0; cyl.gasmix.o2.permille = 1000;
cyl.bestmix_he = 0; cyl.manually_added = true;
add_cloned_cylinder(&dive->cylinders, cyl); cyl.bestmix_o2 = 0;
cyl.bestmix_he = 0;
dive->cylinders.push_back(std::move(cyl));
}
cyl.cylinder_use = DILUENT; {
cyl.type.size.mliter = 3000; cylinder_t cyl;
cyl.type.workingpressure.mbar = 200000; cyl.cylinder_use = DILUENT;
cyl.type.description = "3l Mk6"; cyl.type.size.mliter = 3000;
value = parse_mkvi_value(memtxt.data(), "Helium percentage"); cyl.type.workingpressure.mbar = 200000;
he = atoi(value.c_str()); cyl.type.description = "3l Mk6";
value = parse_mkvi_value(memtxt.data(), "Nitrogen percentage"); value = parse_mkvi_value(memtxt.data(), "Helium percentage");
cyl.gasmix.o2.permille = (100 - atoi(value.c_str()) - he) * 10; he = atoi(value.c_str());
cyl.gasmix.he.permille = he * 10; value = parse_mkvi_value(memtxt.data(), "Nitrogen percentage");
add_cloned_cylinder(&dive->cylinders, cyl); cyl.gasmix.o2.permille = (100 - atoi(value.c_str()) - he) * 10;
cyl.gasmix.he.permille = he * 10;
dive->cylinders.push_back(std::move(cyl));
}
lineptr = strstr(memtxt.data(), "Dive started at"); lineptr = strstr(memtxt.data(), "Dive started at");
while (!empty_string(lineptr) && (lineptr = strchr(lineptr, '\n'))) { while (!empty_string(lineptr) && (lineptr = strchr(lineptr, '\n'))) {

View file

@ -130,7 +130,7 @@ static int divinglog_profile(void *param, int, char **data, char **)
state->cur_sample->temperature.mkelvin = C_to_mkelvin(temp / 10.0f); state->cur_sample->temperature.mkelvin = C_to_mkelvin(temp / 10.0f);
state->cur_sample->pressure[0].mbar = pressure * 100; state->cur_sample->pressure[0].mbar = pressure * 100;
state->cur_sample->rbt.seconds = rbt; state->cur_sample->rbt.seconds = rbt;
if (oldcyl != tank && tank >= 0 && tank < state->cur_dive->cylinders.nr) { if (oldcyl != tank && tank >= 0 && static_cast<size_t>(tank) < state->cur_dive->cylinders.size()) {
struct gasmix mix = get_cylinder(state->cur_dive.get(), tank)->gasmix; struct gasmix mix = get_cylinder(state->cur_dive.get(), tank)->gasmix;
int o2 = get_o2(mix); int o2 = get_o2(mix);
int he = get_he(mix); int he = get_he(mix);

View file

@ -58,24 +58,20 @@ static int shearwater_changes(void *param, int columns, char **data, char **)
o2 = 1000; o2 = 1000;
// Find the cylinder index // Find the cylinder index
int index; auto it = std::find_if(state->cur_dive->cylinders.begin(), state->cur_dive->cylinders.end(),
bool found = false; [o2, he](auto &cyl)
for (index = 0; index < state->cur_dive->cylinders.nr; ++index) { { return cyl.gasmix.o2.permille == o2 && cyl.gasmix.he.permille == he; });
const cylinder_t *cyl = get_cylinder(state->cur_dive.get(), index); if (it == state->cur_dive->cylinders.end()) {
if (cyl->gasmix.o2.permille == o2 && cyl->gasmix.he.permille == he) {
found = true;
break;
}
}
if (!found) {
// Cylinder not found, creating a new one // Cylinder not found, creating a new one
cyl = cylinder_start(state); cyl = cylinder_start(state);
cyl->gasmix.o2.permille = o2; cyl->gasmix.o2.permille = o2;
cyl->gasmix.he.permille = he; cyl->gasmix.he.permille = he;
cylinder_end(state); cylinder_end(state);
it = std::prev(state->cur_dive->cylinders.end());
} }
add_gas_switch_event(state->cur_dive.get(), get_dc(state), state->sample_rate ? atoi(data[0]) / state->sample_rate * 10 : atoi(data[0]), index); add_gas_switch_event(state->cur_dive.get(), get_dc(state), state->sample_rate ? atoi(data[0]) / state->sample_rate * 10 : atoi(data[0]),
it - state->cur_dive->cylinders.begin());
return 0; return 0;
} }
@ -103,9 +99,8 @@ static int shearwater_profile_sample(void *param, int, char **data, char **)
state->cur_sample->depth.mm = state->metric ? lrint(permissive_strtod(data[1], NULL) * 1000) : feet_to_mm(permissive_strtod(data[1], NULL)); state->cur_sample->depth.mm = state->metric ? lrint(permissive_strtod(data[1], NULL) * 1000) : feet_to_mm(permissive_strtod(data[1], NULL));
if (data[2]) if (data[2])
state->cur_sample->temperature.mkelvin = state->metric ? C_to_mkelvin(permissive_strtod(data[2], NULL)) : F_to_mkelvin(permissive_strtod(data[2], NULL)); state->cur_sample->temperature.mkelvin = state->metric ? C_to_mkelvin(permissive_strtod(data[2], NULL)) : F_to_mkelvin(permissive_strtod(data[2], NULL));
if (data[3]) { if (data[3])
state->cur_sample->setpoint.mbar = lrint(permissive_strtod(data[3], NULL) * 1000); state->cur_sample->setpoint.mbar = lrint(permissive_strtod(data[3], NULL) * 1000);
}
if (data[4]) if (data[4])
state->cur_sample->ndl.seconds = atoi(data[4]) * 60; state->cur_sample->ndl.seconds = atoi(data[4]) * 60;
if (data[5]) if (data[5])

View file

@ -165,7 +165,7 @@ static dc_status_t parse_gasmixes(device_data_t *devdata, struct dive *dive, dc_
bottom_gas = gasmix_air; bottom_gas = gasmix_air;
} }
clear_cylinder_table(&dive->cylinders); dive->cylinders.clear();
for (i = 0; i < std::max(ngases, ntanks); i++) { for (i = 0; i < std::max(ngases, ntanks); i++) {
cylinder_t cyl; cylinder_t cyl;
cyl.cylinder_use = NOT_USED; cyl.cylinder_use = NOT_USED;
@ -266,7 +266,7 @@ static dc_status_t parse_gasmixes(device_data_t *devdata, struct dive *dive, dc_
snprintf(name_buffer, sizeof(name_buffer), "%d cuft", rounded_size); snprintf(name_buffer, sizeof(name_buffer), "%d cuft", rounded_size);
break; break;
} }
cyl.type.description = copy_string(name_buffer); cyl.type.description = name_buffer;
cyl.type.size.mliter = lrint(cuft_to_l(rounded_size) * 1000 / cyl.type.size.mliter = lrint(cuft_to_l(rounded_size) * 1000 /
mbar_to_atm(cyl.type.workingpressure.mbar)); mbar_to_atm(cyl.type.workingpressure.mbar));
} }
@ -301,10 +301,10 @@ static dc_status_t parse_gasmixes(device_data_t *devdata, struct dive *dive, dc_
fill_default_cylinder(dive, &cyl); fill_default_cylinder(dive, &cyl);
} }
/* whatever happens, make sure there is a name for the cylinder */ /* whatever happens, make sure there is a name for the cylinder */
if (empty_string(cyl.type.description)) if (cyl.type.description.empty())
cyl.type.description = strdup(translate("gettextFromC", "unknown")); cyl.type.description = translate("gettextFromC", "unknown");
add_cylinder(&dive->cylinders, dive->cylinders.nr, cyl); dive->cylinders.push_back(std::move(cyl));
} }
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
} }

View file

@ -147,8 +147,7 @@ static void parse_dives(int log_version, const unsigned char *buf, unsigned int
/* Just the main cylinder until we can handle the buddy cylinder porperly */ /* Just the main cylinder until we can handle the buddy cylinder porperly */
for (i = 0; i < 1; i++) { for (i = 0; i < 1; i++) {
cylinder_t cyl; cylinder_t cyl = default_cylinder(dive.get());
fill_default_cylinder(dive.get(), &cyl);
add_cylinder(&dive->cylinders, i, cyl); add_cylinder(&dive->cylinders, i, cyl);
} }

View file

@ -389,7 +389,7 @@ static void parse_cylinder_keyvalue(void *_cylinder, const char *key, const std:
return; return;
} }
if (!strcmp(key, "description")) { if (!strcmp(key, "description")) {
cylinder->type.description = strdup(value.c_str()); cylinder->type.description = value;
return; return;
} }
if (!strcmp(key, "o2")) { if (!strcmp(key, "o2")) {
@ -444,9 +444,9 @@ static void parse_dive_cylinder(char *line, struct git_parser_state *state)
line = parse_keyvalue_entry(parse_cylinder_keyvalue, &cylinder, line, state); line = parse_keyvalue_entry(parse_cylinder_keyvalue, &cylinder, line, state);
} }
if (cylinder.cylinder_use == OXYGEN) if (cylinder.cylinder_use == OXYGEN)
state->o2pressure_sensor = state->active_dive->cylinders.nr; state->o2pressure_sensor = static_cast<int>(state->active_dive->cylinders.size());
add_cylinder(&state->active_dive->cylinders, state->active_dive->cylinders.nr, cylinder); state->active_dive->cylinders.push_back(std::move(cylinder));
} }
static void parse_weightsystem_keyvalue(void *_ws, const char *key, const std::string &value) static void parse_weightsystem_keyvalue(void *_ws, const char *key, const std::string &value)
@ -655,7 +655,7 @@ static char *parse_sample_unit(struct sample *sample, double val, char *unit)
*/ */
static int sanitize_sensor_id(const struct dive *d, int nr) static int sanitize_sensor_id(const struct dive *d, int nr)
{ {
return d && nr >= 0 && nr < d->cylinders.nr ? nr : NO_SENSOR; return d && nr >= 0 && static_cast<size_t>(nr) < d->cylinders.size() ? nr : NO_SENSOR;
} }
/* /*

View file

@ -32,6 +32,7 @@
#include "membuffer.h" #include "membuffer.h"
#include "picture.h" #include "picture.h"
#include "qthelper.h" #include "qthelper.h"
#include "range.h"
#include "sample.h" #include "sample.h"
#include "tag.h" #include "tag.h"
#include "xmlparams.h" #include "xmlparams.h"
@ -233,7 +234,7 @@ static void cylinder_use(const char *buffer, enum cylinderuse *cyl_use, struct p
enum cylinderuse use = cylinderuse_from_text(trimmed.c_str()); enum cylinderuse use = cylinderuse_from_text(trimmed.c_str());
*cyl_use = use; *cyl_use = use;
if (use == OXYGEN) if (use == OXYGEN)
state->o2pressure_sensor = state->cur_dive->cylinders.nr - 1; state->o2pressure_sensor = static_cast<int>(state->cur_dive->cylinders.size()) - 1;
} }
} }
@ -990,10 +991,8 @@ static int divinglog_dive_match(struct dive *dive, const char *name, char *buf,
{ {
/* For cylinder related fields, we might have to create a cylinder first. */ /* For cylinder related fields, we might have to create a cylinder first. */
cylinder_t cyl; cylinder_t cyl;
if (MATCH("tanktype", utf8_string, (char **)&cyl.type.description)) { if (MATCH("tanktype", utf8_string_std, &cyl.type.description)) {
cylinder_t *cyl0 = get_or_create_cylinder(dive, 0); get_or_create_cylinder(dive, 0)->type.description = std::move(cyl.type.description);
free((void *)cyl0->type.description);
cyl0->type.description = cyl.type.description;
return 1; return 1;
} }
if (MATCH("tanksize", cylindersize, &cyl.type.size)) { if (MATCH("tanksize", cylindersize, &cyl.type.size)) {
@ -1230,7 +1229,7 @@ static void gps_picture_location(const char *buffer, struct picture *pic)
/* We're in the top-level dive xml. Try to convert whatever value to a dive value */ /* We're in the top-level dive xml. Try to convert whatever value to a dive value */
static void try_to_fill_dive(struct dive *dive, const char *name, char *buf, struct parser_state *state) static void try_to_fill_dive(struct dive *dive, const char *name, char *buf, struct parser_state *state)
{ {
cylinder_t *cyl = dive->cylinders.nr > 0 ? get_cylinder(dive, dive->cylinders.nr - 1) : NULL; cylinder_t *cyl = !dive->cylinders.empty() ? &dive->cylinders.back() : NULL;
weightsystem_t *ws = dive->weightsystems.nr > 0 ? weightsystem_t *ws = dive->weightsystems.nr > 0 ?
&dive->weightsystems.weightsystems[dive->weightsystems.nr - 1] : NULL; &dive->weightsystems.weightsystems[dive->weightsystems.nr - 1] : NULL;
pressure_t p; pressure_t p;
@ -1356,7 +1355,7 @@ static void try_to_fill_dive(struct dive *dive, const char *name, char *buf, str
return; return;
if (MATCH_STATE("workpressure.cylinder", pressure, &cyl->type.workingpressure)) if (MATCH_STATE("workpressure.cylinder", pressure, &cyl->type.workingpressure))
return; return;
if (MATCH("description.cylinder", utf8_string, (char **)&cyl->type.description)) if (MATCH("description.cylinder", utf8_string_std, &cyl->type.description))
return; return;
if (MATCH_STATE("start.cylinder", pressure, &cyl->start)) if (MATCH_STATE("start.cylinder", pressure, &cyl->start))
return; return;
@ -1798,7 +1797,6 @@ int parse_dlf_buffer(unsigned char *buffer, size_t size, struct divelog *log)
unsigned char event; unsigned char event;
bool found; bool found;
unsigned int time = 0; unsigned int time = 0;
int i;
char serial[6]; char serial[6];
struct battery_status { struct battery_status {
uint16_t volt1; uint16_t volt1;
@ -1971,11 +1969,10 @@ int parse_dlf_buffer(unsigned char *buffer, size_t size, struct divelog *log)
state.cur_event.type = SAMPLE_EVENT_GASCHANGE2; state.cur_event.type = SAMPLE_EVENT_GASCHANGE2;
state.cur_event.value = ptr[7] << 8 ^ ptr[6]; state.cur_event.value = ptr[7] << 8 ^ ptr[6];
found = false; for (const auto [i, cyl]: enumerated_range(state.cur_dive->cylinders)) {
for (i = 0; i < state.cur_dive->cylinders.nr; ++i) { if (cyl.gasmix.o2.permille == ptr[6] * 10 && cyl.gasmix.he.permille == ptr[7] * 10) {
const cylinder_t *cyl = get_cylinder(state.cur_dive.get(), i);
if (cyl->gasmix.o2.permille == ptr[6] * 10 && cyl->gasmix.he.permille == ptr[7] * 10) {
found = true; found = true;
state.cur_event.gas.index = i;
break; break;
} }
} }
@ -1984,9 +1981,7 @@ int parse_dlf_buffer(unsigned char *buffer, size_t size, struct divelog *log)
cyl->gasmix.o2.permille = ptr[6] * 10; cyl->gasmix.o2.permille = ptr[6] * 10;
cyl->gasmix.he.permille = ptr[7] * 10; cyl->gasmix.he.permille = ptr[7] * 10;
cylinder_end(&state); cylinder_end(&state);
state.cur_event.gas.index = state.cur_dive->cylinders.nr - 1; state.cur_event.gas.index = static_cast<int>(state.cur_dive->cylinders.size()) - 1;
} else {
state.cur_event.gas.index = i;
} }
break; break;
case 6: case 6:

View file

@ -335,7 +335,7 @@ void ws_end(struct parser_state *state)
*/ */
static int sanitize_sensor_id(const struct dive *d, int nr) static int sanitize_sensor_id(const struct dive *d, int nr)
{ {
return d && nr >= 0 && nr < d->cylinders.nr ? nr : NO_SENSOR; return d && nr >= 0 && static_cast<size_t>(nr) < d->cylinders.size() ? nr : NO_SENSOR;
} }
/* /*

View file

@ -19,6 +19,7 @@
#include "event.h" #include "event.h"
#include "interpolate.h" #include "interpolate.h"
#include "planner.h" #include "planner.h"
#include "range.h"
#include "subsurface-time.h" #include "subsurface-time.h"
#include "gettext.h" #include "gettext.h"
#include "libdivecomputer/parser.h" #include "libdivecomputer/parser.h"
@ -94,7 +95,7 @@ int get_cylinderid_at_time(struct dive *dive, struct divecomputer *dc, duration_
static int get_gasidx(struct dive *dive, struct gasmix mix) static int get_gasidx(struct dive *dive, struct gasmix mix)
{ {
return find_best_gasmix_match(mix, &dive->cylinders); return find_best_gasmix_match(mix, dive->cylinders);
} }
static void interpolate_transition(struct deco_state *ds, struct dive *dive, duration_t t0, duration_t t1, depth_t d0, depth_t d1, struct gasmix gasmix, o2pressure_t po2, enum divemode_t divemode) static void interpolate_transition(struct deco_state *ds, struct dive *dive, duration_t t0, duration_t t1, depth_t d0, depth_t d1, struct gasmix gasmix, o2pressure_t po2, enum divemode_t divemode)
@ -368,12 +369,12 @@ struct gaschanges {
static int setpoint_change(struct dive *dive, int cylinderid) static int setpoint_change(struct dive *dive, int cylinderid)
{ {
cylinder_t *cylinder = get_cylinder(dive, cylinderid); cylinder_t *cylinder = get_cylinder(dive, cylinderid);
if (!cylinder->type.description) if (cylinder->type.description.empty())
return 0; return 0;
if (!strncmp(cylinder->type.description, "SP ", 3)) { if (starts_with(cylinder->type.description, "SP ")) {
float sp; float sp;
sscanf(cylinder->type.description + 3, "%f", &sp); sscanf(cylinder->type.description.c_str() + 3, "%f", &sp);
return (int) (sp * 1000); return (int) (sp * 1000.0);
} else { } else {
return 0; return 0;
} }
@ -572,10 +573,9 @@ static bool trial_ascent(struct deco_state *ds, int wait_time, int trial_depth,
*/ */
static bool enough_gas(const struct dive *dive, int current_cylinder) static bool enough_gas(const struct dive *dive, int current_cylinder)
{ {
cylinder_t *cyl; if (current_cylinder < 0 || static_cast<size_t>(current_cylinder) >= dive->cylinders.size())
if (current_cylinder < 0 || current_cylinder >= dive->cylinders.nr)
return false; return false;
cyl = get_cylinder(dive, current_cylinder); const cylinder_t *cyl = get_cylinder(dive, current_cylinder);
if (!cyl->start.mbar) if (!cyl->start.mbar)
return true; return true;
@ -1086,7 +1086,7 @@ bool plan(struct deco_state *ds, struct diveplan *diveplan, struct dive *dive, i
// we had a fixed cylinder table: It uses an extra fake cylinder // we had a fixed cylinder table: It uses an extra fake cylinder
// past the regular cylinder table, which is not visible to the UI. // past the regular cylinder table, which is not visible to the UI.
// Fix this as soon as possible! // Fix this as soon as possible!
current_cylinder = dive->cylinders.nr; current_cylinder = static_cast<int>(dive->cylinders.size());
plan_add_segment(diveplan, prefs.surface_segment, 0, current_cylinder, 0, false, OC); plan_add_segment(diveplan, prefs.surface_segment, 0, current_cylinder, 0, false, OC);
} }
create_dive_from_plan(diveplan, dive, dc, is_planner); create_dive_from_plan(diveplan, dive, dc, is_planner);

View file

@ -16,6 +16,7 @@
#include "units.h" #include "units.h"
#include "divelist.h" #include "divelist.h"
#include "planner.h" #include "planner.h"
#include "range.h"
#include "gettext.h" #include "gettext.h"
#include "libdivecomputer/parser.h" #include "libdivecomputer/parser.h"
#include "qthelper.h" #include "qthelper.h"
@ -461,34 +462,33 @@ void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive, bool show_d
} }
/* Print gas consumption: This loop covers all cylinders */ /* Print gas consumption: This loop covers all cylinders */
for (int gasidx = 0; gasidx < dive->cylinders.nr; gasidx++) { for (auto [gasidx, cyl]: enumerated_range(dive->cylinders)) {
double volume, pressure, deco_volume, deco_pressure, mingas_volume, mingas_pressure, mingas_d_pressure, mingas_depth; double volume, pressure, deco_volume, deco_pressure, mingas_volume, mingas_pressure, mingas_d_pressure, mingas_depth;
const char *unit, *pressure_unit, *depth_unit; const char *unit, *pressure_unit, *depth_unit;
std::string temp; std::string temp;
std::string warning; std::string warning;
std::string mingas; std::string mingas;
cylinder_t *cyl = get_cylinder(dive, gasidx); if (cyl.cylinder_use == NOT_USED)
if (cyl->cylinder_use == NOT_USED)
continue; continue;
volume = get_volume_units(cyl->gas_used.mliter, NULL, &unit); volume = get_volume_units(cyl.gas_used.mliter, NULL, &unit);
deco_volume = get_volume_units(cyl->deco_gas_used.mliter, NULL, &unit); deco_volume = get_volume_units(cyl.deco_gas_used.mliter, NULL, &unit);
if (cyl->type.size.mliter) { if (cyl.type.size.mliter) {
int remaining_gas = lrint((double)cyl->end.mbar * cyl->type.size.mliter / 1000.0 / gas_compressibility_factor(cyl->gasmix, cyl->end.mbar / 1000.0)); int remaining_gas = lrint((double)cyl.end.mbar * cyl.type.size.mliter / 1000.0 / gas_compressibility_factor(cyl.gasmix, cyl.end.mbar / 1000.0));
double deco_pressure_mbar = isothermal_pressure(cyl->gasmix, 1.0, remaining_gas + cyl->deco_gas_used.mliter, double deco_pressure_mbar = isothermal_pressure(cyl.gasmix, 1.0, remaining_gas + cyl.deco_gas_used.mliter,
cyl->type.size.mliter) * 1000 - cyl->end.mbar; cyl.type.size.mliter) * 1000 - cyl.end.mbar;
deco_pressure = get_pressure_units(lrint(deco_pressure_mbar), &pressure_unit); deco_pressure = get_pressure_units(lrint(deco_pressure_mbar), &pressure_unit);
pressure = get_pressure_units(cyl->start.mbar - cyl->end.mbar, &pressure_unit); pressure = get_pressure_units(cyl.start.mbar - cyl.end.mbar, &pressure_unit);
/* Warn if the plan uses more gas than is available in a cylinder /* Warn if the plan uses more gas than is available in a cylinder
* This only works if we have working pressure for the cylinder * This only works if we have working pressure for the cylinder
* 10bar is a made up number - but it seemed silly to pretend you could breathe cylinder down to 0 */ * 10bar is a made up number - but it seemed silly to pretend you could breathe cylinder down to 0 */
if (cyl->end.mbar < 10000) if (cyl.end.mbar < 10000)
warning = format_string_std("<br/>\n&nbsp;&mdash; <span style='color: red;'>%s </span> %s", warning = format_string_std("<br/>\n&nbsp;&mdash; <span style='color: red;'>%s </span> %s",
translate("gettextFromC", "Warning:"), translate("gettextFromC", "Warning:"),
translate("gettextFromC", "this is more gas than available in the specified cylinder!")); translate("gettextFromC", "this is more gas than available in the specified cylinder!"));
else else
if (cyl->end.mbar / 1000.0 * cyl->type.size.mliter / gas_compressibility_factor(cyl->gasmix, cyl->end.mbar / 1000.0) if (cyl.end.mbar / 1000.0 * cyl.type.size.mliter / gas_compressibility_factor(cyl.gasmix, cyl.end.mbar / 1000.0)
< cyl->deco_gas_used.mliter) < cyl.deco_gas_used.mliter)
warning = format_string_std("<br/>\n&nbsp;&mdash; <span style='color: red;'>%s </span> %s", warning = format_string_std("<br/>\n&nbsp;&mdash; <span style='color: red;'>%s </span> %s",
translate("gettextFromC", "Warning:"), translate("gettextFromC", "Warning:"),
translate("gettextFromC", "not enough reserve for gas sharing on ascent!")); translate("gettextFromC", "not enough reserve for gas sharing on ascent!"));
@ -502,17 +502,17 @@ void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive, bool show_d
volume_t mingasv; volume_t mingasv;
mingasv.mliter = lrint(prefs.sacfactor / 100.0 * prefs.problemsolvingtime * prefs.bottomsac mingasv.mliter = lrint(prefs.sacfactor / 100.0 * prefs.problemsolvingtime * prefs.bottomsac
* depth_to_bar(lastbottomdp->depth.mm, dive) * depth_to_bar(lastbottomdp->depth.mm, dive)
+ prefs.sacfactor / 100.0 * cyl->deco_gas_used.mliter); + prefs.sacfactor / 100.0 * cyl.deco_gas_used.mliter);
/* Calculate minimum gas pressure for cyclinder. */ /* Calculate minimum gas pressure for cyclinder. */
lastbottomdp->minimum_gas.mbar = lrint(isothermal_pressure(cyl->gasmix, 1.0, lastbottomdp->minimum_gas.mbar = lrint(isothermal_pressure(cyl.gasmix, 1.0,
mingasv.mliter, cyl->type.size.mliter) * 1000); mingasv.mliter, cyl.type.size.mliter) * 1000);
/* Translate all results into correct units */ /* Translate all results into correct units */
mingas_volume = get_volume_units(mingasv.mliter, NULL, &unit); mingas_volume = get_volume_units(mingasv.mliter, NULL, &unit);
mingas_pressure = get_pressure_units(lastbottomdp->minimum_gas.mbar, &pressure_unit); mingas_pressure = get_pressure_units(lastbottomdp->minimum_gas.mbar, &pressure_unit);
mingas_d_pressure = get_pressure_units(lrint((double)cyl->end.mbar + deco_pressure_mbar - lastbottomdp->minimum_gas.mbar), &pressure_unit); mingas_d_pressure = get_pressure_units(lrint((double)cyl.end.mbar + deco_pressure_mbar - lastbottomdp->minimum_gas.mbar), &pressure_unit);
mingas_depth = get_depth_units(lastbottomdp->depth.mm, NULL, &depth_unit); mingas_depth = get_depth_units(lastbottomdp->depth.mm, NULL, &depth_unit);
/* Print it to results */ /* Print it to results */
if (cyl->start.mbar > lastbottomdp->minimum_gas.mbar) { if (cyl.start.mbar > lastbottomdp->minimum_gas.mbar) {
mingas = casprintf_loc("<br/>\n&nbsp;&mdash; <span style='color: %s;'>%s</span> (%s %.1fx%s/+%d%s@%.0f%s): " mingas = casprintf_loc("<br/>\n&nbsp;&mdash; <span style='color: %s;'>%s</span> (%s %.1fx%s/+%d%s@%.0f%s): "
"%.0f%s/%.0f%s<span style='color: %s;'>/&Delta;:%+.0f%s</span>", "%.0f%s/%.0f%s<span style='color: %s;'>/&Delta;:%+.0f%s</span>",
mingas_d_pressure > 0 ? "green" :"red", mingas_d_pressure > 0 ? "green" :"red",
@ -536,18 +536,18 @@ void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive, bool show_d
/* Print the gas consumption for every cylinder here to temp buffer. */ /* Print the gas consumption for every cylinder here to temp buffer. */
if (lrint(volume) > 0) { if (lrint(volume) > 0) {
temp = casprintf_loc(translate("gettextFromC", "%.0f%s/%.0f%s of <span style='color: red;'><b>%s</b></span> (%.0f%s/%.0f%s in planned ascent)"), temp = casprintf_loc(translate("gettextFromC", "%.0f%s/%.0f%s of <span style='color: red;'><b>%s</b></span> (%.0f%s/%.0f%s in planned ascent)"),
volume, unit, pressure, pressure_unit, gasname(cyl->gasmix), deco_volume, unit, deco_pressure, pressure_unit); volume, unit, pressure, pressure_unit, gasname(cyl.gasmix), deco_volume, unit, deco_pressure, pressure_unit);
} else { } else {
temp = casprintf_loc(translate("gettextFromC", "%.0f%s/%.0f%s of <span style='color: red;'><b>%s</b></span>"), temp = casprintf_loc(translate("gettextFromC", "%.0f%s/%.0f%s of <span style='color: red;'><b>%s</b></span>"),
volume, unit, pressure, pressure_unit, gasname(cyl->gasmix)); volume, unit, pressure, pressure_unit, gasname(cyl.gasmix));
} }
} else { } else {
if (lrint(volume) > 0) { if (lrint(volume) > 0) {
temp = casprintf_loc(translate("gettextFromC", "%.0f%s of <span style='color: red;'><b>%s</b></span> (%.0f%s during planned ascent)"), temp = casprintf_loc(translate("gettextFromC", "%.0f%s of <span style='color: red;'><b>%s</b></span> (%.0f%s during planned ascent)"),
volume, unit, gasname(cyl->gasmix), deco_volume, unit); volume, unit, gasname(cyl.gasmix), deco_volume, unit);
} else { } else {
temp = casprintf_loc(translate("gettextFromC", "%.0f%s of <span style='color: red;'><b>%s</b></span>"), temp = casprintf_loc(translate("gettextFromC", "%.0f%s of <span style='color: red;'><b>%s</b></span>"),
volume, unit, gasname(cyl->gasmix)); volume, unit, gasname(cyl.gasmix));
} }
} }
/* Gas consumption: Now finally print all strings to output */ /* Gas consumption: Now finally print all strings to output */

View file

@ -24,6 +24,7 @@
#include "libdivecomputer/version.h" #include "libdivecomputer/version.h"
#include "membuffer.h" #include "membuffer.h"
#include "qthelper.h" #include "qthelper.h"
#include "range.h"
#include "format.h" #include "format.h"
//#define DEBUG_GAS 1 //#define DEBUG_GAS 1
@ -216,7 +217,7 @@ int get_cylinder_index(const struct dive *dive, const struct event &ev)
report_info("Still looking up cylinder based on gas mix in get_cylinder_index()!"); report_info("Still looking up cylinder based on gas mix in get_cylinder_index()!");
mix = get_gasmix_from_event(dive, ev); mix = get_gasmix_from_event(dive, ev);
best = find_best_gasmix_match(mix, &dive->cylinders); best = find_best_gasmix_match(mix, dive->cylinders);
return best < 0 ? 0 : best; return best < 0 ? 0 : best;
} }
@ -259,12 +260,11 @@ static void calculate_max_limits_new(const struct dive *dive, const struct divec
int maxhr = 0, minhr = INT_MAX; int maxhr = 0, minhr = INT_MAX;
int mintemp = dive->mintemp.mkelvin; int mintemp = dive->mintemp.mkelvin;
int maxtemp = dive->maxtemp.mkelvin; int maxtemp = dive->maxtemp.mkelvin;
int cyl;
/* Get the per-cylinder maximum pressure if they are manual */ /* Get the per-cylinder maximum pressure if they are manual */
for (cyl = 0; cyl < dive->cylinders.nr; cyl++) { for (auto &cyl: dive->cylinders) {
int mbar_start = get_cylinder(dive, cyl)->start.mbar; int mbar_start = cyl.start.mbar;
int mbar_end = get_cylinder(dive, cyl)->end.mbar; int mbar_end = cyl.end.mbar;
if (mbar_start > maxpressure) if (mbar_start > maxpressure)
maxpressure = mbar_start; maxpressure = mbar_start;
if (mbar_end && mbar_end < minpressure) if (mbar_end && mbar_end < minpressure)
@ -364,7 +364,7 @@ static void insert_entry(struct plot_info &pi, int time, int depth, int sac)
static void populate_plot_entries(const struct dive *dive, const struct divecomputer *dc, struct plot_info &pi) static void populate_plot_entries(const struct dive *dive, const struct divecomputer *dc, struct plot_info &pi)
{ {
pi.nr_cylinders = dive->cylinders.nr; pi.nr_cylinders = static_cast<int>(dive->cylinders.size());
/* /*
* To avoid continuous reallocation, allocate the expected number of entries. * To avoid continuous reallocation, allocate the expected number of entries.
@ -494,26 +494,21 @@ static void populate_plot_entries(const struct dive *dive, const struct divecomp
*/ */
static int sac_between(const struct dive *dive, const struct plot_info &pi, int first, int last, const char gases[]) static int sac_between(const struct dive *dive, const struct plot_info &pi, int first, int last, const char gases[])
{ {
int i, airuse;
double pressuretime;
if (first == last) if (first == last)
return 0; return 0;
/* Get airuse for the set of cylinders over the range */ /* Get airuse for the set of cylinders over the range */
airuse = 0; int airuse = 0;
for (i = 0; i < pi.nr_cylinders; i++) { for (int i = 0; i < pi.nr_cylinders; i++) {
pressure_t a, b; pressure_t a, b;
cylinder_t *cyl;
int cyluse;
if (!gases[i]) if (!gases[i])
continue; continue;
a.mbar = get_plot_pressure(pi, first, i); a.mbar = get_plot_pressure(pi, first, i);
b.mbar = get_plot_pressure(pi, last, i); b.mbar = get_plot_pressure(pi, last, i);
cyl = get_cylinder(dive, i); const cylinder_t *cyl = get_cylinder(dive, i);
cyluse = gas_volume(cyl, a) - gas_volume(cyl, b); int cyluse = gas_volume(cyl, a) - gas_volume(cyl, b);
if (cyluse > 0) if (cyluse > 0)
airuse += cyluse; airuse += cyluse;
} }
@ -521,7 +516,7 @@ static int sac_between(const struct dive *dive, const struct plot_info &pi, int
return 0; return 0;
/* Calculate depthpressure integrated over time */ /* Calculate depthpressure integrated over time */
pressuretime = 0.0; double pressuretime = 0.0;
do { do {
const struct plot_data &entry = pi.entry[first]; const struct plot_data &entry = pi.entry[first];
const struct plot_data &next = pi.entry[first + 1]; const struct plot_data &next = pi.entry[first + 1];
@ -632,8 +627,8 @@ static void fill_sac(const struct dive *dive, struct plot_info &pi, int idx, con
*/ */
static void matching_gases(const struct dive *dive, struct gasmix gasmix, char gases[]) static void matching_gases(const struct dive *dive, struct gasmix gasmix, char gases[])
{ {
for (int i = 0; i < dive->cylinders.nr; i++) for (auto [i, cyl]: enumerated_range(dive->cylinders))
gases[i] = same_gasmix(gasmix, get_cylinder(dive, i)->gasmix); gases[i] = same_gasmix(gasmix, cyl.gasmix);
} }
static void calculate_sac(const struct dive *dive, const struct divecomputer *dc, struct plot_info &pi) static void calculate_sac(const struct dive *dive, const struct divecomputer *dc, struct plot_info &pi)
@ -1536,7 +1531,7 @@ std::vector<std::string> compare_samples(const struct dive *d, const struct plot
if (last_pressures[cylinder_index]) { if (last_pressures[cylinder_index]) {
bar_used[cylinder_index] += last_pressures[cylinder_index] - next_pressure; bar_used[cylinder_index] += last_pressures[cylinder_index] - next_pressure;
cylinder_t *cyl = get_cylinder(d, cylinder_index); const cylinder_t *cyl = get_cylinder(d, cylinder_index);
volumes_used[cylinder_index] += gas_volume(cyl, (pressure_t){ last_pressures[cylinder_index] }) - gas_volume(cyl, (pressure_t){ next_pressure }); volumes_used[cylinder_index] += gas_volume(cyl, (pressure_t){ last_pressures[cylinder_index] }) - gas_volume(cyl, (pressure_t){ next_pressure });
} }
@ -1589,7 +1584,7 @@ std::vector<std::string> compare_samples(const struct dive *d, const struct plot
total_bar_used += bar_used[cylinder_index]; total_bar_used += bar_used[cylinder_index];
total_volume_used += volumes_used[cylinder_index]; total_volume_used += volumes_used[cylinder_index];
cylinder_t *cyl = get_cylinder(d, cylinder_index); const cylinder_t *cyl = get_cylinder(d, cylinder_index);
if (cyl->type.size.mliter) { if (cyl->type.size.mliter) {
if (cylinder_volume.mliter && cylinder_volume.mliter != cyl->type.size.mliter) { if (cylinder_volume.mliter && cylinder_volume.mliter != cyl->type.size.mliter) {
cylindersizes_are_identical = false; cylindersizes_are_identical = false;

View file

@ -95,7 +95,7 @@ struct plot_info {
double maxpp = 0.0; double maxpp = 0.0;
bool waypoint_above_ceiling = false; bool waypoint_above_ceiling = false;
std::vector<plot_data> entry; std::vector<plot_data> entry;
std::vector<plot_pressure_data> pressures; /* cylinders.nr blocks of nr entries. */ std::vector<plot_pressure_data> pressures; /* cylinders.size() blocks of nr entries. */
plot_info(); plot_info();
~plot_info(); ~plot_info();

View file

@ -12,6 +12,7 @@
#include "version.h" #include "version.h"
#include "errorhelper.h" #include "errorhelper.h"
#include "planner.h" #include "planner.h"
#include "range.h"
#include "subsurface-time.h" #include "subsurface-time.h"
#include "gettextfromc.h" #include "gettextfromc.h"
#include "metadata.h" #include "metadata.h"
@ -357,11 +358,10 @@ static bool lessThan(const QPair<QString, int> &a, const QPair<QString, int> &b)
QVector<QPair<QString, int>> selectedDivesGasUsed() QVector<QPair<QString, int>> selectedDivesGasUsed()
{ {
int j;
QMap<QString, int> gasUsed; QMap<QString, int> gasUsed;
for (dive *d: getDiveSelection()) { for (dive *d: getDiveSelection()) {
std::vector<volume_t> diveGases = get_gas_used(d); std::vector<volume_t> diveGases = get_gas_used(d);
for (j = 0; j < d->cylinders.nr; j++) { for (size_t j = 0; j < d->cylinders.size(); j++) {
if (diveGases[j].mliter) { if (diveGases[j].mliter) {
QString gasName = gasname(get_cylinder(d, j)->gasmix); QString gasName = gasname(get_cylinder(d, j)->gasmix);
gasUsed[gasName] += diveGases[j].mliter; gasUsed[gasName] += diveGases[j].mliter;
@ -1189,16 +1189,15 @@ QString get_gas_string(struct gasmix gas)
QStringList get_dive_gas_list(const struct dive *d) QStringList get_dive_gas_list(const struct dive *d)
{ {
QStringList list; QStringList list;
for (int i = 0; i < d->cylinders.nr; i++) { for (auto [i, cyl]: enumerated_range(d->cylinders)) {
const cylinder_t *cyl = get_cylinder(d, i);
/* Check if we have the same gasmix two or more times /* Check if we have the same gasmix two or more times
* If yes return more verbose string */ * If yes return more verbose string */
int same_gas = same_gasmix_cylinder(cyl, i, d, true); int same_gas = same_gasmix_cylinder(cyl, i, d, true);
if (same_gas == -1) if (same_gas == -1)
list.push_back(get_gas_string(cyl->gasmix)); list.push_back(get_gas_string(cyl.gasmix));
else else
list.push_back(get_gas_string(cyl->gasmix) + QString(" (%1 %2 ").arg(gettextFromC::tr("cyl.")).arg(i + 1) + list.push_back(get_gas_string(cyl.gasmix) + QStringLiteral(" (%1 %2 ").arg(gettextFromC::tr("cyl.")).arg(i + 1) +
cyl->type.description + ")"); QString::fromStdString(cyl.type.description) + ")");
} }
return list; return list;
} }

View file

@ -141,28 +141,23 @@ static void put_gasmix(struct membuffer *b, struct gasmix mix)
static void save_cylinder_info(struct membuffer *b, struct dive *dive) static void save_cylinder_info(struct membuffer *b, struct dive *dive)
{ {
int i, nr; for (auto &cyl: dive->cylinders) {
int volume = cyl.type.size.mliter;
nr = nr_cylinders(dive); int use = cyl.cylinder_use;
for (i = 0; i < nr; i++) {
cylinder_t *cylinder = get_cylinder(dive, i);
int volume = cylinder->type.size.mliter;
const char *description = cylinder->type.description;
int use = cylinder->cylinder_use;
put_string(b, "cylinder"); put_string(b, "cylinder");
if (volume) if (volume)
put_milli(b, " vol=", volume, "l"); put_milli(b, " vol=", volume, "l");
put_pressure(b, cylinder->type.workingpressure, " workpressure=", "bar"); put_pressure(b, cyl.type.workingpressure, " workpressure=", "bar");
show_utf8(b, " description=", description, ""); show_utf8(b, " description=", cyl.type.description.c_str(), "");
strip_mb(b); strip_mb(b);
put_gasmix(b, cylinder->gasmix); put_gasmix(b, cyl.gasmix);
put_pressure(b, cylinder->start, " start=", "bar"); put_pressure(b, cyl.start, " start=", "bar");
put_pressure(b, cylinder->end, " end=", "bar"); put_pressure(b, cyl.end, " end=", "bar");
if (use > OC_GAS && use < NUM_GAS_USE) if (use > OC_GAS && use < NUM_GAS_USE)
show_utf8(b, " use=", cylinderuse_text[use], ""); show_utf8(b, " use=", cylinderuse_text[use], "");
if (cylinder->depth.mm != 0) if (cyl.depth.mm != 0)
put_milli(b, " depth=", cylinder->depth.mm, "m"); put_milli(b, " depth=", cyl.depth.mm, "m");
put_string(b, "\n"); put_string(b, "\n");
} }
} }

View file

@ -121,43 +121,40 @@ static void put_weightsystem_HTML(struct membuffer *b, const struct dive *dive)
static void put_cylinder_HTML(struct membuffer *b, const struct dive *dive) static void put_cylinder_HTML(struct membuffer *b, const struct dive *dive)
{ {
int i, nr;
const char *separator = "\"Cylinders\":["; const char *separator = "\"Cylinders\":[";
nr = nr_cylinders(dive);
if (!nr) if (dive->cylinders.empty())
put_string(b, separator); put_string(b, separator);
for (i = 0; i < nr; i++) { for (auto &cyl: dive->cylinders) {
cylinder_t *cylinder = get_cylinder(dive, i);
put_format(b, "%s{", separator); put_format(b, "%s{", separator);
separator = ", "; separator = ", ";
write_attribute(b, "Type", cylinder->type.description, ", "); write_attribute(b, "Type", cyl.type.description.c_str(), ", ");
if (cylinder->type.size.mliter) { if (cyl.type.size.mliter) {
int volume = cylinder->type.size.mliter; int volume = cyl.type.size.mliter;
if (prefs.units.volume == units::CUFT && cylinder->type.workingpressure.mbar) if (prefs.units.volume == units::CUFT && cyl.type.workingpressure.mbar)
volume = lrint(volume * bar_to_atm(cylinder->type.workingpressure.mbar / 1000.0)); volume = lrint(volume * bar_to_atm(cyl.type.workingpressure.mbar / 1000.0));
put_HTML_volume_units(b, volume, "\"Size\":\"", " \", "); put_HTML_volume_units(b, volume, "\"Size\":\"", " \", ");
} else { } else {
write_attribute(b, "Size", "--", ", "); write_attribute(b, "Size", "--", ", ");
} }
put_HTML_pressure_units(b, cylinder->type.workingpressure, "\"WPressure\":\"", " \", "); put_HTML_pressure_units(b, cyl.type.workingpressure, "\"WPressure\":\"", " \", ");
if (cylinder->start.mbar) { if (cyl.start.mbar) {
put_HTML_pressure_units(b, cylinder->start, "\"SPressure\":\"", " \", "); put_HTML_pressure_units(b, cyl.start, "\"SPressure\":\"", " \", ");
} else { } else {
write_attribute(b, "SPressure", "--", ", "); write_attribute(b, "SPressure", "--", ", ");
} }
if (cylinder->end.mbar) { if (cyl.end.mbar) {
put_HTML_pressure_units(b, cylinder->end, "\"EPressure\":\"", " \", "); put_HTML_pressure_units(b, cyl.end, "\"EPressure\":\"", " \", ");
} else { } else {
write_attribute(b, "EPressure", "--", ", "); write_attribute(b, "EPressure", "--", ", ");
} }
if (cylinder->gasmix.o2.permille) { if (cyl.gasmix.o2.permille) {
put_format(b, "\"O2\":\"%u.%u%%\",", FRACTION_TUPLE(cylinder->gasmix.o2.permille, 10)); put_format(b, "\"O2\":\"%u.%u%%\",", FRACTION_TUPLE(cyl.gasmix.o2.permille, 10));
put_format(b, "\"He\":\"%u.%u%%\"", FRACTION_TUPLE(cylinder->gasmix.he.permille, 10)); put_format(b, "\"He\":\"%u.%u%%\"", FRACTION_TUPLE(cyl.gasmix.he.permille, 10));
} else { } else {
write_attribute(b, "O2", "Air", ""); write_attribute(b, "O2", "Air", "");
} }

View file

@ -177,28 +177,22 @@ static void put_gasmix(struct membuffer *b, struct gasmix mix)
static void save_cylinder_info(struct membuffer *b, struct dive *dive) static void save_cylinder_info(struct membuffer *b, struct dive *dive)
{ {
int i, nr; for (auto &cyl: dive->cylinders) {
int volume = cyl.type.size.mliter;
nr = nr_cylinders(dive); int use = cyl.cylinder_use;
for (i = 0; i < nr; i++) {
cylinder_t *cylinder = get_cylinder(dive, i);
int volume = cylinder->type.size.mliter;
const char *description = cylinder->type.description;
int use = cylinder->cylinder_use;
put_format(b, " <cylinder"); put_format(b, " <cylinder");
if (volume) if (volume)
put_milli(b, " size='", volume, " l'"); put_milli(b, " size='", volume, " l'");
put_pressure(b, cylinder->type.workingpressure, " workpressure='", " bar'"); put_pressure(b, cyl.type.workingpressure, " workpressure='", " bar'");
show_utf8(b, description, " description='", "'", 1); show_utf8(b, cyl.type.description.c_str(), " description='", "'", 1);
put_gasmix(b, cylinder->gasmix); put_gasmix(b, cyl.gasmix);
put_pressure(b, cylinder->start, " start='", " bar'"); put_pressure(b, cyl.start, " start='", " bar'");
put_pressure(b, cylinder->end, " end='", " bar'"); put_pressure(b, cyl.end, " end='", " bar'");
if (use > OC_GAS && use < NUM_GAS_USE) if (use > OC_GAS && use < NUM_GAS_USE)
show_utf8(b, cylinderuse_text[use], " use='", "'", 1); show_utf8(b, cylinderuse_text[use], " use='", "'", 1);
if (cylinder->depth.mm != 0) if (cyl.depth.mm != 0)
put_milli(b, " depth='", cylinder->depth.mm, " m'"); put_milli(b, " depth='", cyl.depth.mm, " m'");
put_format(b, " />\n"); put_format(b, " />\n");
} }
} }

View file

@ -9,6 +9,7 @@
#include "divelog.h" #include "divelog.h"
#include "event.h" #include "event.h"
#include "gettext.h" #include "gettext.h"
#include "range.h"
#include "sample.h" #include "sample.h"
#include "subsurface-time.h" #include "subsurface-time.h"
#include "trip.h" #include "trip.h"
@ -273,15 +274,14 @@ bool has_gaschange_event(const struct dive *dive, const struct divecomputer *dc,
bool is_cylinder_used(const struct dive *dive, int idx) bool is_cylinder_used(const struct dive *dive, int idx)
{ {
cylinder_t *cyl; if (idx < 0 || static_cast<size_t>(idx) >= dive->cylinders.size())
if (idx < 0 || idx >= dive->cylinders.nr)
return false; return false;
cyl = get_cylinder(dive, idx); const cylinder_t &cyl = dive->cylinders[idx];
if ((cyl->start.mbar - cyl->end.mbar) > SOME_GAS) if ((cyl.start.mbar - cyl.end.mbar) > SOME_GAS)
return true; return true;
if ((cyl->sample_start.mbar - cyl->sample_end.mbar) > SOME_GAS) if ((cyl.sample_start.mbar - cyl.sample_end.mbar) > SOME_GAS)
return true; return true;
for (auto &dc: dive->dcs) { for (auto &dc: dive->dcs) {
@ -295,7 +295,7 @@ bool is_cylinder_used(const struct dive *dive, int idx)
bool is_cylinder_prot(const struct dive *dive, int idx) bool is_cylinder_prot(const struct dive *dive, int idx)
{ {
if (idx < 0 || idx >= dive->cylinders.nr) if (idx < 0 || static_cast<size_t>(idx) >= dive->cylinders.size())
return false; return false;
return std::any_of(dive->dcs.begin(), dive->dcs.end(), return std::any_of(dive->dcs.begin(), dive->dcs.end(),
@ -303,18 +303,17 @@ bool is_cylinder_prot(const struct dive *dive, int idx)
{ return has_gaschange_event(dive, &dc, idx); }); { return has_gaschange_event(dive, &dc, idx); });
} }
/* Returns a vector with dive->cylinders.nr entries */ /* Returns a vector with dive->cylinders.size() entries */
std::vector<volume_t> get_gas_used(struct dive *dive) std::vector<volume_t> get_gas_used(struct dive *dive)
{ {
std::vector<volume_t> gases(dive->cylinders.nr); std::vector<volume_t> gases(dive->cylinders.size());
for (int idx = 0; idx < dive->cylinders.nr; idx++) { for (auto [idx, cyl]: enumerated_range(dive->cylinders)) {
cylinder_t *cyl = get_cylinder(dive, idx);
pressure_t start, end; pressure_t start, end;
start = cyl->start.mbar ? cyl->start : cyl->sample_start; start = cyl.start.mbar ? cyl.start : cyl.sample_start;
end = cyl->end.mbar ? cyl->end : cyl->sample_end; end = cyl.end.mbar ? cyl.end : cyl.sample_end;
if (end.mbar && start.mbar > end.mbar) if (end.mbar && start.mbar > end.mbar)
gases[idx].mliter = gas_volume(cyl, start) - gas_volume(cyl, end); gases[idx].mliter = gas_volume(&cyl, start) - gas_volume(&cyl, end);
else else
gases[idx].mliter = 0; gases[idx].mliter = 0;
} }
@ -327,7 +326,7 @@ std::vector<volume_t> get_gas_used(struct dive *dive)
static std::pair<volume_t, volume_t> get_gas_parts(struct gasmix mix, volume_t vol, int o2_in_topup) static std::pair<volume_t, volume_t> get_gas_parts(struct gasmix mix, volume_t vol, int o2_in_topup)
{ {
if (gasmix_is_air(mix)) if (gasmix_is_air(mix))
return { {0}, {0} }; return { volume_t() , volume_t() };
volume_t air = { (int)lrint(((double)vol.mliter * get_n2(mix)) / (1000 - o2_in_topup)) }; 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 he = { (int)lrint(((double)vol.mliter * get_he(mix)) / 1000.0) };

View file

@ -4,6 +4,7 @@
#include "event.h" #include "event.h"
#include "format.h" #include "format.h"
#include "qthelper.h" #include "qthelper.h"
#include "range.h"
#include "subsurface-string.h" #include "subsurface-string.h"
#include "trip.h" #include "trip.h"
#include <QDateTime> #include <QDateTime>
@ -13,23 +14,21 @@
enum returnPressureSelector { START_PRESSURE, END_PRESSURE }; enum returnPressureSelector { START_PRESSURE, END_PRESSURE };
static QLocale loc; static QLocale loc;
static QString getPressures(const struct dive *dive, int i, enum returnPressureSelector ret) static QString getPressures(const cylinder_t &cyl, enum returnPressureSelector ret)
{ {
const cylinder_t *cyl = get_cylinder(dive, i);
QString fmt;
if (ret == START_PRESSURE) { if (ret == START_PRESSURE) {
if (cyl->start.mbar) if (cyl.start.mbar)
fmt = get_pressure_string(cyl->start, true); return get_pressure_string(cyl.start, true);
else if (cyl->sample_start.mbar) else if (cyl.sample_start.mbar)
fmt = get_pressure_string(cyl->sample_start, true); return get_pressure_string(cyl.sample_start, true);
} }
if (ret == END_PRESSURE) { if (ret == END_PRESSURE) {
if (cyl->end.mbar) if (cyl.end.mbar)
fmt = get_pressure_string(cyl->end, true); return get_pressure_string(cyl.end, true);
else if(cyl->sample_end.mbar) else if (cyl.sample_end.mbar)
fmt = get_pressure_string(cyl->sample_end, true); return get_pressure_string(cyl.sample_end, true);
} }
return fmt; return QString();
} }
QString formatSac(const dive *d) QString formatSac(const dive *d)
@ -77,9 +76,9 @@ QString format_gps_decimal(const dive *d)
QStringList formatGetCylinder(const dive *d) QStringList formatGetCylinder(const dive *d)
{ {
QStringList getCylinder; QStringList getCylinder;
for (int i = 0; i < d->cylinders.nr; i++) { for (auto [i, cyl]: enumerated_range(d->cylinders)) {
if (is_cylinder_used(d, i)) if (is_cylinder_used(d, i))
getCylinder << get_cylinder(d, i)->type.description; getCylinder << QString::fromStdString(cyl.type.description);
} }
return getCylinder; return getCylinder;
} }
@ -87,9 +86,9 @@ QStringList formatGetCylinder(const dive *d)
QStringList formatStartPressure(const dive *d) QStringList formatStartPressure(const dive *d)
{ {
QStringList startPressure; QStringList startPressure;
for (int i = 0; i < d->cylinders.nr; i++) { for (auto [i, cyl]: enumerated_range(d->cylinders)) {
if (is_cylinder_used(d, i)) if (is_cylinder_used(d, i))
startPressure << getPressures(d, i, START_PRESSURE); startPressure << getPressures(cyl, START_PRESSURE);
} }
return startPressure; return startPressure;
} }
@ -97,9 +96,9 @@ QStringList formatStartPressure(const dive *d)
QStringList formatEndPressure(const dive *d) QStringList formatEndPressure(const dive *d)
{ {
QStringList endPressure; QStringList endPressure;
for (int i = 0; i < d->cylinders.nr; i++) { for (auto [i, cyl]: enumerated_range(d->cylinders)) {
if (is_cylinder_used(d, i)) if (is_cylinder_used(d, i))
endPressure << getPressures(d, i, END_PRESSURE); endPressure << getPressures(cyl, END_PRESSURE);
} }
return endPressure; return endPressure;
} }
@ -107,9 +106,9 @@ QStringList formatEndPressure(const dive *d)
QStringList formatFirstGas(const dive *d) QStringList formatFirstGas(const dive *d)
{ {
QStringList gas; QStringList gas;
for (int i = 0; i < d->cylinders.nr; i++) { for (auto [i, cyl]: enumerated_range(d->cylinders)) {
if (is_cylinder_used(d, i)) if (is_cylinder_used(d, i))
gas << get_gas_string(get_cylinder(d, i)->gasmix); gas << get_gas_string(cyl.gasmix);
} }
return gas; return gas;
} }
@ -133,20 +132,14 @@ static void addStringToSortedList(QStringList &l, const std::string &s)
l.insert(it, qs); l.insert(it, qs);
} }
// Safely treat null-strings. Remove once everyhting is converted to std::string
static std::string c_to_std(const char *s)
{
return s ? std::string(s) : std::string();
}
QStringList formatFullCylinderList() QStringList formatFullCylinderList()
{ {
QStringList cylinders; QStringList cylinders;
struct dive *d; struct dive *d;
int i = 0; int i = 0;
for_each_dive (i, d) { for_each_dive (i, d) {
for (int j = 0; j < d->cylinders.nr; j++) for (const cylinder_t &cyl: d->cylinders)
addStringToSortedList(cylinders, c_to_std(get_cylinder(d, j)->type.description)); addStringToSortedList(cylinders, cyl.type.description);
} }
for (const auto &ti: tank_info_table) for (const auto &ti: tank_info_table)
@ -155,25 +148,22 @@ QStringList formatFullCylinderList()
return cylinders; return cylinders;
} }
static QString formattedCylinder(const struct dive *dive, int idx) static QString formattedCylinder(const cylinder_t &cyl)
{ {
const cylinder_t *cyl = get_cylinder(dive, idx); const std::string &desc = cyl.type.description;
const char *desc = cyl->type.description; QString fmt = !desc.empty() ? QString::fromStdString(desc) : gettextFromC::tr("unknown");
QString fmt = desc ? QString(desc) : gettextFromC::tr("unknown"); fmt += ", " + get_volume_string(cyl.type.size, true);
fmt += ", " + get_volume_string(cyl->type.size, true); fmt += ", " + get_pressure_string(cyl.type.workingpressure, true);
fmt += ", " + get_pressure_string(cyl->type.workingpressure, true); fmt += ", " + get_pressure_string(cyl.start, false) + " - " + get_pressure_string(cyl.end, true);
fmt += ", " + get_pressure_string(cyl->start, false) + " - " + get_pressure_string(cyl->end, true); fmt += ", " + get_gas_string(cyl.gasmix);
fmt += ", " + get_gas_string(cyl->gasmix);
return fmt; return fmt;
} }
QStringList formatCylinders(const dive *d) QStringList formatCylinders(const dive *d)
{ {
QStringList cylinders; QStringList cylinders;
for (int i = 0; i < d->cylinders.nr; i++) { for (const cylinder_t &cyl: d->cylinders)
QString cyl = formattedCylinder(d, i); cylinders << formattedCylinder(cyl);
cylinders << cyl;
}
return cylinders; return cylinders;
} }
@ -182,14 +172,14 @@ QString formatGas(const dive *d)
/*WARNING: here should be the gastlist, returned /*WARNING: here should be the gastlist, returned
* from the get_gas_string function or this is correct? * from the get_gas_string function or this is correct?
*/ */
QString gas, gases; QString gases;
for (int i = 0; i < d->cylinders.nr; i++) { for (auto [i, cyl]: enumerated_range(d->cylinders)) {
if (!is_cylinder_used(d, i)) if (!is_cylinder_used(d, i))
continue; continue;
gas = get_cylinder(d, i)->type.description; QString gas = QString::fromStdString(cyl.type.description);
if (!gas.isEmpty()) if (!gas.isEmpty())
gas += QChar(' '); gas += QChar(' ');
gas += gasname(get_cylinder(d, i)->gasmix); gas += gasname(cyl.gasmix);
// if has a description and if such gas is not already present // if has a description and if such gas is not already present
if (!gas.isEmpty() && gases.indexOf(gas) == -1) { if (!gas.isEmpty() && gases.indexOf(gas) == -1) {
if (!gases.isEmpty()) if (!gases.isEmpty())

View file

@ -335,7 +335,7 @@ void uemis::parse_divelog_binary(std::string_view base64, struct dive *dive)
u_sample = (uemis_sample *)(data.data() + i); u_sample = (uemis_sample *)(data.data() + i);
while ((i <= data.size()) && (data[i] != 0 || data[i + 1] != 0)) { while ((i <= data.size()) && (data[i] != 0 || data[i + 1] != 0)) {
if (u_sample->active_tank != active) { if (u_sample->active_tank != active) {
if (u_sample->active_tank >= dive->cylinders.nr) { if (u_sample->active_tank >= static_cast<int>(dive->cylinders.size())) {
report_info("got invalid sensor #%d was #%d", u_sample->active_tank, active); report_info("got invalid sensor #%d was #%d", u_sample->active_tank, active);
} else { } else {
active = u_sample->active_tank; active = u_sample->active_tank;

View file

@ -298,7 +298,7 @@ void ProfileWidget::cylindersChanged(struct dive *changed, int pos)
// If we're editing the current dive we have to update the // If we're editing the current dive we have to update the
// cylinders of the edited dive. // cylinders of the edited dive.
if (editedDive) { if (editedDive) {
copy_cylinders(&d->cylinders, &editedDive.get()->cylinders); editedDive.get()->cylinders = d->cylinders;
// TODO: Holy moly that function sends too many signals. Fix it! // TODO: Holy moly that function sends too many signals. Fix it!
DivePlannerPointsModel::instance()->loadFromDive(editedDive.get(), dc); DivePlannerPointsModel::instance()->loadFromDive(editedDive.get(), dc);
} }

View file

@ -23,6 +23,7 @@
#include "profile-widget/profilewidget2.h" #include "profile-widget/profilewidget2.h"
#include "commands/command.h" #include "commands/command.h"
#include "core/metadata.h" #include "core/metadata.h"
#include "core/range.h"
#include "core/tag.h" #include "core/tag.h"
void RenumberDialog::buttonClicked(QAbstractButton *button) void RenumberDialog::buttonClicked(QAbstractButton *button)
@ -348,11 +349,10 @@ void DiveComponentSelection::buttonClicked(QAbstractButton *button)
text << "\n"; text << "\n";
} }
if (what->cylinders) { if (what->cylinders) {
int cyl;
text << tr("Cylinders:\n"); text << tr("Cylinders:\n");
for (cyl = 0; cyl < current_dive->cylinders.nr; cyl++) { for (auto [idx, cyl]: enumerated_range(current_dive->cylinders)) {
if (is_cylinder_used(current_dive, cyl)) if (is_cylinder_used(current_dive, idx))
text << get_cylinder(current_dive, cyl)->type.description << " " << gasname(get_cylinder(current_dive, cyl)->gasmix) << "\n"; text << QString::fromStdString(cyl.type.description) << " " << gasname(cyl.gasmix) << "\n";
} }
} }
if (what->weights) { if (what->weights) {

View file

@ -126,14 +126,14 @@ void TabDiveInformation::updateProfile()
std::vector<volume_t> gases = get_gas_used(currentDive); std::vector<volume_t> gases = get_gas_used(currentDive);
QString volumes; QString volumes;
std::vector<int> mean(currentDive->cylinders.nr), duration(currentDive->cylinders.nr); std::vector<int> mean(currentDive->cylinders.size()), duration(currentDive->cylinders.size());
struct divecomputer *currentdc = parent.getCurrentDC(); struct divecomputer *currentdc = parent.getCurrentDC();
if (currentdc && currentDive->cylinders.nr >= 0) if (currentdc && !currentDive->cylinders.empty())
per_cylinder_mean_depth(currentDive, currentdc, mean.data(), duration.data()); per_cylinder_mean_depth(currentDive, currentdc, mean.data(), duration.data());
volume_t sac; volume_t sac;
QString gaslist, SACs, separator; QString gaslist, SACs, separator;
for (int i = 0; i < currentDive->cylinders.nr; i++) { for (size_t i = 0; i < currentDive->cylinders.size(); i++) {
if (!is_cylinder_used(currentDive, i)) if (!is_cylinder_used(currentDive, i))
continue; continue;
gaslist.append(separator); volumes.append(separator); SACs.append(separator); gaslist.append(separator); volumes.append(separator); SACs.append(separator);
@ -154,7 +154,7 @@ void TabDiveInformation::updateProfile()
ui->diveTimeText->setText(get_dive_duration_string(currentDive->duration.seconds, tr("h"), tr("min"), tr("sec"), ui->diveTimeText->setText(get_dive_duration_string(currentDive->duration.seconds, tr("h"), tr("min"), tr("sec"),
" ", currentDive->dcs[0].divemode == FREEDIVE)); " ", currentDive->dcs[0].divemode == FREEDIVE));
ui->sacText->setText(currentDive->cylinders.nr > 0 && mean[0] && currentDive->dcs[0].divemode != CCR ? std::move(SACs) : QString()); ui->sacText->setText(!currentDive->cylinders.empty() && mean[0] && currentDive->dcs[0].divemode != CCR ? std::move(SACs) : QString());
if (currentDive->surface_pressure.mbar == 0) { if (currentDive->surface_pressure.mbar == 0) {
ui->atmPressVal->clear(); // If no atm pressure for dive then clear text box ui->atmPressVal->clear(); // If no atm pressure for dive then clear text box

View file

@ -303,9 +303,9 @@ static int findEnd(const QList<token> &tokenList, int from, int to, token_t star
static std::vector<const cylinder_t *> cylinderList(const dive *d) static std::vector<const cylinder_t *> cylinderList(const dive *d)
{ {
std::vector<const cylinder_t *> res; std::vector<const cylinder_t *> res;
res.reserve(d->cylinders.nr); res.reserve(d->cylinders.size());
for (int i = 0; i < d->cylinders.nr; ++i) for (auto &cyl: d->cylinders)
res.push_back(&d->cylinders.cylinders[i]); res.push_back(&cyl);
return res; return res;
} }
@ -481,7 +481,7 @@ QVariant TemplateLayout::getValue(QString list, QString property, const State &s
return QVariant(); return QVariant();
const cylinder_t *cylinder = *state.currentCylinderObject; const cylinder_t *cylinder = *state.currentCylinderObject;
if (property == "description") { if (property == "description") {
return cylinder->type.description; return QString::fromStdString(cylinder->type.description);
} else if (property == "size") { } else if (property == "size") {
return get_volume_string(cylinder->type.size, true); return get_volume_string(cylinder->type.size, true);
} else if (property == "workingPressure") { } else if (property == "workingPressure") {

View file

@ -1295,7 +1295,7 @@ void QMLManager::commitChanges(QString diveId, QString number, QString date, QSt
break; break;
} }
} }
get_or_create_cylinder(d, j)->type.description = copy_qstring(usedCylinder[k]); get_or_create_cylinder(d, j)->type.description = usedCylinder[k].toStdString();
get_cylinder(d, j)->type.size.mliter = size; get_cylinder(d, j)->type.size.mliter = size;
get_cylinder(d, j)->type.workingpressure.mbar = wp; get_cylinder(d, j)->type.workingpressure.mbar = wp;
k++; k++;

View file

@ -602,7 +602,10 @@ void DiveGasPressureItem::replot(const dive *d, int fromIn, int toIn, bool in_pl
bool showDescriptions = false; bool showDescriptions = false;
for (int cyl = 0; cyl < pInfo.nr_cylinders; cyl++) { for (int cyl = 0; cyl < pInfo.nr_cylinders; cyl++) {
showDescriptions = showDescriptions || same_gasmix_cylinder(get_cylinder(d, cyl), cyl, d, true) != -1; const cylinder_t *c = get_cylinder(d, cyl);
if (!c)
continue;
showDescriptions = showDescriptions || (c && same_gasmix_cylinder(*c, cyl, d, true) != -1);
if (act_segments[cyl].polygon.empty()) if (act_segments[cyl].polygon.empty())
continue; continue;
act_segments[cyl].cyl = cyl; act_segments[cyl].cyl = cyl;
@ -655,7 +658,7 @@ void DiveGasPressureItem::plotGasValue(double mbar, double sec, const cylinder_t
QString gas = get_gas_string(cylinder->gasmix); QString gas = get_gas_string(cylinder->gasmix);
QString label; QString label;
if (showDescription) if (showDescription)
label = QStringLiteral("(%1) %2").arg(cylinder->type.description, gas); label = QStringLiteral("(%1) %2").arg(QString::fromStdString(cylinder->type.description), gas);
else else
label = gas; label = gas;
auto text = std::make_unique<DiveTextItem>(dpr, 1.0, align, this); auto text = std::make_unique<DiveTextItem>(dpr, 1.0, align, this);

View file

@ -502,13 +502,11 @@ struct int ProfileWidget2::getEntryFromPos(QPointF pos)
#ifndef SUBSURFACE_MOBILE #ifndef SUBSURFACE_MOBILE
/// Prints cylinder information for display. /// Prints cylinder information for display.
/// eg : "Cyl 1 (AL80 EAN32)" /// eg : "Cyl 1 (AL80 EAN32)"
static QString printCylinderDescription(int i, const cylinder_t *cylinder) static QString printCylinderDescription(int i, const cylinder_t &cylinder)
{ {
QString label = gettextFromC::tr("Cyl") + QString(" %1").arg(i+1); QString label = gettextFromC::tr("Cyl") + QString(" %1").arg(i+1);
if( cylinder != NULL ) { QString mix = get_gas_string(cylinder.gasmix);
QString mix = get_gas_string(cylinder->gasmix); label += QString(" (%2 %3)").arg(QString::fromStdString(cylinder.type.description)).arg(mix);
label += QString(" (%2 %3)").arg(cylinder->type.description).arg(mix);
}
return label; return label;
} }
@ -562,18 +560,16 @@ void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event)
if (d && item && item->ev.is_gaschange()) { if (d && item && item->ev.is_gaschange()) {
int eventTime = item->ev.time.seconds; int eventTime = item->ev.time.seconds;
QMenu *gasChange = m.addMenu(tr("Edit Gas Change")); QMenu *gasChange = m.addMenu(tr("Edit Gas Change"));
for (int i = 0; i < d->cylinders.nr; i++) { for (auto [i, cyl]: enumerated_range(d->cylinders)) {
const cylinder_t *cylinder = get_cylinder(d, i); QString label = printCylinderDescription(i, cyl);
QString label = printCylinderDescription(i, cylinder); gasChange->addAction(label, [this, idx = i, eventTime] { addGasSwitch(idx, eventTime); });
gasChange->addAction(label, [this, i, eventTime] { addGasSwitch(i, eventTime); });
} }
} else if (d && d->cylinders.nr > 1) { } else if (d && d->cylinders.size() > 1) {
// if we have more than one gas, offer to switch to another one // if we have more than one gas, offer to switch to another one
QMenu *gasChange = m.addMenu(tr("Add gas change")); QMenu *gasChange = m.addMenu(tr("Add gas change"));
for (int i = 0; i < d->cylinders.nr; i++) { for (auto [i, cyl]: enumerated_range(d->cylinders)) {
const cylinder_t *cylinder = get_cylinder(d, i); QString label = printCylinderDescription(i, cyl);
QString label = printCylinderDescription(i, cylinder); gasChange->addAction(label, [this, idx = i, seconds] { addGasSwitch(idx, seconds); });
gasChange->addAction(label, [this, i, seconds] { addGasSwitch(i, seconds); });
} }
} }
m.addAction(tr("Add setpoint change"), [this, seconds]() { ProfileWidget2::addSetpointChange(seconds); }); m.addAction(tr("Add setpoint change"), [this, seconds]() { ProfileWidget2::addSetpointChange(seconds); });
@ -763,7 +759,7 @@ void ProfileWidget2::splitDive(int seconds)
void ProfileWidget2::addGasSwitch(int tank, int seconds) void ProfileWidget2::addGasSwitch(int tank, int seconds)
{ {
if (!d || tank < 0 || tank >= d->cylinders.nr) if (!d || tank < 0 || static_cast<size_t>(tank) >= d->cylinders.size())
return; return;
Command::addGasSwitch(mutable_dive(), dc, seconds, tank); Command::addGasSwitch(mutable_dive(), dc, seconds, tank);
@ -923,7 +919,7 @@ void ProfileWidget2::repositionDiveHandlers()
QLineF line(p1, p2); QLineF line(p1, p2);
QPointF pos = line.pointAt(0.5); QPointF pos = line.pointAt(0.5);
gases[i]->setPos(pos); gases[i]->setPos(pos);
if (datapoint.cylinderid >= 0 && datapoint.cylinderid < d->cylinders.nr) if (datapoint.cylinderid >= 0 && datapoint.cylinderid < static_cast<int>(d->cylinders.size()))
gases[i]->setText(get_gas_string(get_cylinder(d, datapoint.cylinderid)->gasmix)); gases[i]->setText(get_gas_string(get_cylinder(d, datapoint.cylinderid)->gasmix));
else else
gases[i]->setText(QString()); gases[i]->setText(QString());

View file

@ -76,7 +76,7 @@ void TankItem::setData(const struct dive *d, const struct divecomputer *dc, int
return; return;
// Bail if there are no cylinders // Bail if there are no cylinders
if (d->cylinders.nr <= 0) if (d->cylinders.empty())
return; return;
// start with the first gasmix and at the start of the plotted range // start with the first gasmix and at the start of the plotted range

View file

@ -6,6 +6,7 @@
#include "core/color.h" #include "core/color.h"
#include "qt-models/diveplannermodel.h" #include "qt-models/diveplannermodel.h"
#include "core/gettextfromc.h" #include "core/gettextfromc.h"
#include "core/range.h"
#include "core/sample.h" #include "core/sample.h"
#include "core/selection.h" #include "core/selection.h"
#include "core/subsurface-qt/divelistnotifier.h" #include "core/subsurface-qt/divelistnotifier.h"
@ -140,7 +141,7 @@ int CylindersModel::calcNumRows() const
if (!d) if (!d)
return 0; return 0;
if (inPlanner || prefs.include_unused_tanks) if (inPlanner || prefs.include_unused_tanks)
return d->cylinders.nr; return static_cast<int>(d->cylinders.size());
return first_hidden_cylinder(d); return first_hidden_cylinder(d);
} }
@ -192,7 +193,7 @@ QVariant CylindersModel::data(const QModelIndex &index, int role) const
case Qt::EditRole: case Qt::EditRole:
switch (index.column()) { switch (index.column()) {
case TYPE: case TYPE:
return QString(cyl->type.description); return QString::fromStdString(cyl->type.description);
case SIZE: case SIZE:
if (cyl->type.size.mliter) if (cyl->type.size.mliter)
return get_cylinder_string(cyl); return get_cylinder_string(cyl);
@ -326,10 +327,9 @@ bool CylindersModel::setData(const QModelIndex &index, const QVariant &value, in
switch (index.column()) { switch (index.column()) {
case TYPE: { case TYPE: {
QString type = value.toString(); std::string type = value.toString().toStdString();
if (!same_string(qPrintable(type), tempCyl.type.description)) { if (type != tempCyl.type.description) {
free((void *)tempCyl.type.description); tempCyl.type.description = type;
tempCyl.type.description = strdup(qPrintable(type));
dataChanged(index, index); dataChanged(index, index);
} }
return true; return true;
@ -361,8 +361,6 @@ bool CylindersModel::setData(const QModelIndex &index, const QVariant &value, in
QString vString = value.toString(); QString vString = value.toString();
bool changed = vString != data(index, role).toString(); bool changed = vString != data(index, role).toString();
std::string newType; // If we allocate a new type string, this makes sure that it is freed at the end of the function
// First, we make a shallow copy of the old cylinder. Then we modify the fields inside that copy. // First, we make a shallow copy of the old cylinder. Then we modify the fields inside that copy.
// At the end, we either place an EditCylinder undo command (EquipmentTab) or copy the cylinder back (planner). // At the end, we either place an EditCylinder undo command (EquipmentTab) or copy the cylinder back (planner).
// Yes, this is not ideal, but the pragmatic thing to do for now. // Yes, this is not ideal, but the pragmatic thing to do for now.
@ -374,8 +372,7 @@ bool CylindersModel::setData(const QModelIndex &index, const QVariant &value, in
Command::EditCylinderType type = Command::EditCylinderType::TYPE; Command::EditCylinderType type = Command::EditCylinderType::TYPE;
switch (index.column()) { switch (index.column()) {
case TYPE: case TYPE:
newType = qPrintable(vString); cyl.type.description = vString.toStdString();
cyl.type.description = newType.c_str();
type = Command::EditCylinderType::TYPE; type = Command::EditCylinderType::TYPE;
break; break;
case SIZE: case SIZE:
@ -473,10 +470,7 @@ bool CylindersModel::setData(const QModelIndex &index, const QVariant &value, in
if (inPlanner) { if (inPlanner) {
// In the planner - simply overwrite the cylinder in the dive with the modified cylinder. // In the planner - simply overwrite the cylinder in the dive with the modified cylinder.
// We have only made a shallow copy, therefore copy the new cylinder first. *get_cylinder(d, row) = cyl;
cylinder_t copy = clone_cylinder(cyl);
std::swap(copy, *get_cylinder(d, row));
free_cylinder(copy);
dataChanged(index, index); dataChanged(index, index);
} else { } else {
// On the EquipmentTab - place an editCylinder command. // On the EquipmentTab - place an editCylinder command.
@ -496,10 +490,10 @@ void CylindersModel::add()
{ {
if (!d) if (!d)
return; return;
int row = d->cylinders.nr; int row = static_cast<int>(d->cylinders.size());
cylinder_t cyl = create_new_manual_cylinder(d); cylinder_t cyl = create_new_manual_cylinder(d);
beginInsertRows(QModelIndex(), row, row); beginInsertRows(QModelIndex(), row, row);
add_cylinder(&d->cylinders, row, cyl); add_cylinder(&d->cylinders, row, std::move(cyl));
++numRows; ++numRows;
endInsertRows(); endInsertRows();
emit dataChanged(createIndex(row, 0), createIndex(row, COLUMNS - 1)); emit dataChanged(createIndex(row, 0), createIndex(row, COLUMNS - 1));
@ -552,7 +546,7 @@ void CylindersModel::remove(QModelIndex index)
--numRows; --numRows;
endRemoveRows(); endRemoveRows();
std::vector<int> mapping = get_cylinder_map_for_remove(d->cylinders.nr + 1, index.row()); std::vector<int> mapping = get_cylinder_map_for_remove(static_cast<int>(d->cylinders.size() + 1), index.row());
cylinder_renumber(d, mapping.data()); cylinder_renumber(d, mapping.data());
DivePlannerPointsModel::instance()->cylinderRenumber(mapping.data()); DivePlannerPointsModel::instance()->cylinderRenumber(mapping.data());
} }
@ -612,21 +606,18 @@ void CylindersModel::updateNumRows()
// Only invoked from planner. // Only invoked from planner.
void CylindersModel::moveAtFirst(int cylid) void CylindersModel::moveAtFirst(int cylid)
{ {
if (!d || cylid <= 0 || cylid >= d->cylinders.nr) if (!d || cylid <= 0 || cylid >= static_cast<int>(d->cylinders.size()))
return; return;
cylinder_t temp_cyl; cylinder_t temp_cyl;
beginMoveRows(QModelIndex(), cylid, cylid, QModelIndex(), 0); beginMoveRows(QModelIndex(), cylid, cylid, QModelIndex(), 0);
memmove(&temp_cyl, get_cylinder(d, cylid), sizeof(temp_cyl)); move_in_range(d->cylinders, cylid, cylid + 1, 0);
for (int i = cylid - 1; i >= 0; i--)
memmove(get_cylinder(d, i + 1), get_cylinder(d, i), sizeof(temp_cyl));
memmove(get_cylinder(d, 0), &temp_cyl, sizeof(temp_cyl));
// Create a mapping of cylinder indices: // Create a mapping of cylinder indices:
// 1) Fill mapping[0]..mapping[cyl] with 0..index // 1) Fill mapping[0]..mapping[cyl] with 0..index
// 2) Set mapping[cyl] to 0 // 2) Set mapping[cyl] to 0
// 3) Fill mapping[cyl+1]..mapping[end] with cyl.. // 3) Fill mapping[cyl+1]..mapping[end] with cyl..
std::vector<int> mapping(d->cylinders.nr); std::vector<int> mapping(d->cylinders.size());
std::iota(mapping.begin(), mapping.begin() + cylid, 1); std::iota(mapping.begin(), mapping.begin() + cylid, 1);
mapping[cylid] = 0; mapping[cylid] = 0;
std::iota(mapping.begin() + (cylid + 1), mapping.end(), cylid); std::iota(mapping.begin() + (cylid + 1), mapping.end(), cylid);
@ -644,12 +635,11 @@ void CylindersModel::updateDecoDepths(pressure_t olddecopo2)
pressure_t decopo2; pressure_t decopo2;
decopo2.mbar = prefs.decopo2; decopo2.mbar = prefs.decopo2;
for (int i = 0; i < d->cylinders.nr; i++) { for (auto &cyl: d->cylinders) {
cylinder_t *cyl = get_cylinder(d, i);
/* If the gas's deco MOD matches the old pO2, it will have been automatically calculated and should be updated. /* If the gas's deco MOD matches the old pO2, it will have been automatically calculated and should be updated.
* If they don't match, we should leave the user entered depth as it is */ * If they don't match, we should leave the user entered depth as it is */
if (cyl->depth.mm == gas_mod(cyl->gasmix, olddecopo2, d, M_OR_FT(3, 10)).mm) { if (cyl.depth.mm == gas_mod(cyl.gasmix, olddecopo2, d, M_OR_FT(3, 10)).mm) {
cyl->depth = gas_mod(cyl->gasmix, decopo2, d, M_OR_FT(3, 10)); cyl.depth = gas_mod(cyl.gasmix, decopo2, d, M_OR_FT(3, 10));
} }
} }
emit dataChanged(createIndex(0, 0), createIndex(numRows - 1, COLUMNS - 1)); emit dataChanged(createIndex(0, 0), createIndex(numRows - 1, COLUMNS - 1));
@ -671,23 +661,22 @@ bool CylindersModel::updateBestMixes()
// Check if any of the cylinders are best mixes, update if needed // Check if any of the cylinders are best mixes, update if needed
bool gasUpdated = false; bool gasUpdated = false;
for (int i = 0; i < d->cylinders.nr; i++) { for (auto &cyl: d->cylinders) {
cylinder_t *cyl = get_cylinder(d, i); if (cyl.bestmix_o2) {
if (cyl->bestmix_o2) { cyl.gasmix.o2 = best_o2(d->maxdepth, d, inPlanner);
cyl->gasmix.o2 = best_o2(d->maxdepth, d, inPlanner);
// fO2 + fHe must not be greater than 1 // fO2 + fHe must not be greater than 1
if (get_o2(cyl->gasmix) + get_he(cyl->gasmix) > 1000) if (get_o2(cyl.gasmix) + get_he(cyl.gasmix) > 1000)
cyl->gasmix.he.permille = 1000 - get_o2(cyl->gasmix); cyl.gasmix.he.permille = 1000 - get_o2(cyl.gasmix);
pressure_t modpO2; pressure_t modpO2;
modpO2.mbar = prefs.decopo2; modpO2.mbar = prefs.decopo2;
cyl->depth = gas_mod(cyl->gasmix, modpO2, d, M_OR_FT(3, 10)); cyl.depth = gas_mod(cyl.gasmix, modpO2, d, M_OR_FT(3, 10));
gasUpdated = true; gasUpdated = true;
} }
if (cyl->bestmix_he) { if (cyl.bestmix_he) {
cyl->gasmix.he = best_he(d->maxdepth, d, prefs.o2narcotic, cyl->gasmix.o2); cyl.gasmix.he = best_he(d->maxdepth, d, prefs.o2narcotic, cyl.gasmix.o2);
// fO2 + fHe must not be greater than 1 // fO2 + fHe must not be greater than 1
if (get_o2(cyl->gasmix) + get_he(cyl->gasmix) > 1000) if (get_o2(cyl.gasmix) + get_he(cyl.gasmix) > 1000)
cyl->gasmix.o2.permille = 1000 - get_he(cyl->gasmix); cyl.gasmix.o2.permille = 1000 - get_he(cyl.gasmix);
gasUpdated = true; gasUpdated = true;
} }
} }
@ -727,7 +716,7 @@ void CylindersModel::initTempCyl(int row)
return; return;
tempRow = row; tempRow = row;
tempCyl = clone_cylinder(*cyl); tempCyl = *cyl;
dataChanged(index(row, TYPE), index(row, USE)); dataChanged(index(row, TYPE), index(row, USE));
} }
@ -738,7 +727,7 @@ void CylindersModel::clearTempCyl()
return; return;
int oldRow = tempRow; int oldRow = tempRow;
tempRow = -1; tempRow = -1;
free_cylinder(tempCyl); tempCyl = cylinder_t();
dataChanged(index(oldRow, TYPE), index(oldRow, USE)); dataChanged(index(oldRow, TYPE), index(oldRow, USE));
} }
@ -752,7 +741,7 @@ void CylindersModel::commitTempCyl(int row)
if (!cyl) if (!cyl)
return; return;
// Only submit a command if the type changed // Only submit a command if the type changed
if (!same_string(cyl->type.description, tempCyl.type.description) || gettextFromC::tr(cyl->type.description) != QString(tempCyl.type.description)) { if (cyl->type.description != tempCyl.type.description || gettextFromC::tr(cyl->type.description.c_str()) != QString::fromStdString(tempCyl.type.description)) {
if (inPlanner) { if (inPlanner) {
std::swap(*cyl, tempCyl); std::swap(*cyl, tempCyl);
} else { } else {
@ -760,6 +749,6 @@ void CylindersModel::commitTempCyl(int row)
emit divesEdited(count); emit divesEdited(count);
} }
} }
free_cylinder(tempCyl); tempCyl = cylinder_t();
tempRow = -1; tempRow = -1;
} }

View file

@ -195,13 +195,13 @@ void DivePlannerPointsModel::loadFromDive(dive *dIn, int dcNrIn)
// setup the cylinder widget accordingly // setup the cylinder widget accordingly
void DivePlannerPointsModel::setupCylinders() void DivePlannerPointsModel::setupCylinders()
{ {
clear_cylinder_table(&d->cylinders); d->cylinders.clear();
if (mode == PLAN && current_dive) { if (mode == PLAN && current_dive) {
// take the displayed cylinders from the selected dive as starting point // take the displayed cylinders from the selected dive as starting point
copy_used_cylinders(current_dive, d, !prefs.include_unused_tanks); copy_used_cylinders(current_dive, d, !prefs.include_unused_tanks);
reset_cylinders(d, true); reset_cylinders(d, true);
if (d->cylinders.nr > 0) { if (!d->cylinders.empty()) {
cylinders.updateDive(d, dcNr); cylinders.updateDive(d, dcNr);
return; // We have at least one cylinder return; // We have at least one cylinder
} }
@ -281,13 +281,14 @@ QVariant DivePlannerPointsModel::data(const QModelIndex &index, int role) const
case GAS: case GAS:
/* Check if we have the same gasmix two or more times /* Check if we have the same gasmix two or more times
* If yes return more verbose string */ * If yes return more verbose string */
int same_gas = same_gasmix_cylinder(get_cylinder(d, p.cylinderid), p.cylinderid, d, true); const cylinder_t &cyl = d->cylinders[p.cylinderid];
int same_gas = same_gasmix_cylinder(cyl, p.cylinderid, d, true);
if (same_gas == -1) if (same_gas == -1)
return get_gas_string(get_cylinder(d, p.cylinderid)->gasmix); return get_gas_string(cyl.gasmix);
else else
return get_gas_string(get_cylinder(d, p.cylinderid)->gasmix) + return get_gas_string(cyl.gasmix) +
QString(" (%1 %2 ").arg(tr("cyl.")).arg(p.cylinderid + 1) + QString(" (%1 %2 ").arg(tr("cyl.")).arg(p.cylinderid + 1) +
get_cylinder(d, p.cylinderid)->type.description + ")"; QString::fromStdString(cyl.type.description) + ")";
} }
} else if (role == Qt::DecorationRole) { } else if (role == Qt::DecorationRole) {
switch (index.column()) { switch (index.column()) {
@ -602,6 +603,7 @@ void DivePlannerPointsModel::setAscratestopsDisplay(int rate)
qPrefDivePlanner::set_ascratestops(lrint(rate * unit_factor())); qPrefDivePlanner::set_ascratestops(lrint(rate * unit_factor()));
emitDataChanged(); emitDataChanged();
} }
int DivePlannerPointsModel::ascratestopsDisplay() const int DivePlannerPointsModel::ascratestopsDisplay() const
{ {
return lrint((float)prefs.ascratestops / unit_factor()); return lrint((float)prefs.ascratestops / unit_factor());
@ -1028,11 +1030,9 @@ void DivePlannerPointsModel::createTemporaryPlan()
// Get the user-input and calculate the dive info // Get the user-input and calculate the dive info
free_dps(&diveplan); free_dps(&diveplan);
for (int i = 0; i < d->cylinders.nr; i++) { for (auto [i, cyl]: enumerated_range(d->cylinders)) {
cylinder_t *cyl = get_cylinder(d, i); if (cyl.depth.mm && cyl.cylinder_use == OC_GAS)
if (cyl->depth.mm && cyl->cylinder_use == OC_GAS) { plan_add_segment(&diveplan, 0, cyl.depth.mm, i, 0, false, OC);
plan_add_segment(&diveplan, 0, cyl->depth.mm, i, 0, false, OC);
}
} }
int lastIndex = -1; int lastIndex = -1;

View file

@ -151,12 +151,9 @@ static void calculateDive(struct dive *dive, Stats &stats)
} }
// EAN dive ? // EAN dive ?
for (int j = 0; j < dive->cylinders.nr; ++j) { if (std::any_of(dive->cylinders.begin(), dive->cylinders.end(), [] (auto &cyl)
if (get_cylinder(dive, j)->gasmix.o2.permille > 210) { { return cyl.gasmix.o2.permille > 210; }))
stats.divesEAN++; stats.divesEAN++;
break;
}
}
} }
// Returns a (first_dive, last_dive) pair // Returns a (first_dive, last_dive) pair

View file

@ -336,7 +336,7 @@ QVariant DiveTripModelBase::diveData(const struct dive *d, int column, int role)
case SUIT: case SUIT:
return QString(d->suit); return QString(d->suit);
case CYLINDER: case CYLINDER:
return d->cylinders.nr > 0 ? QString(get_cylinder(d, 0)->type.description) : QString(); return !d->cylinders.empty() ? QString::fromStdString(d->cylinders[0].type.description) : QString();
case SAC: case SAC:
return displaySac(d, prefs.units.show_units_table); return displaySac(d, prefs.units.show_units_table);
case OTU: case OTU:
@ -1721,6 +1721,11 @@ static int strCmp(const char *s1, const char *s2)
return QString::localeAwareCompare(QString(s1), QString(s2)); // TODO: avoid copy return QString::localeAwareCompare(QString(s1), QString(s2)); // TODO: avoid copy
} }
static int strCmp(const std::string &s1, const std::string &s2)
{
return QString::localeAwareCompare(QString::fromStdString(s1), QString::fromStdString(s2)); // TODO: avoid copy
}
bool DiveTripModelList::lessThan(const QModelIndex &i1, const QModelIndex &i2) const bool DiveTripModelList::lessThan(const QModelIndex &i1, const QModelIndex &i2) const
{ {
// We assume that i1.column() == i2.column(). // We assume that i1.column() == i2.column().
@ -1750,9 +1755,9 @@ bool DiveTripModelList::lessThan(const QModelIndex &i1, const QModelIndex &i2) c
case SUIT: case SUIT:
return lessThanHelper(strCmp(d1->suit, d2->suit), row_diff); return lessThanHelper(strCmp(d1->suit, d2->suit), row_diff);
case CYLINDER: case CYLINDER:
if (d1->cylinders.nr > 0 && d2->cylinders.nr > 0) if (!d1->cylinders.empty() && !d2->cylinders.empty())
return lessThanHelper(strCmp(get_cylinder(d1, 0)->type.description, get_cylinder(d2, 0)->type.description), row_diff); return lessThanHelper(strCmp(d1->cylinders[0].type.description, d2->cylinders[0].type.description), row_diff);
return d1->cylinders.nr - d2->cylinders.nr < 0; return d1->cylinders.size() < d2->cylinders.size();
case GAS: case GAS:
return lessThanHelper(nitrox_sort_value(d1) - nitrox_sort_value(d2), row_diff); return lessThanHelper(nitrox_sort_value(d1) - nitrox_sort_value(d2), row_diff);
case SAC: case SAC:
@ -1764,19 +1769,19 @@ bool DiveTripModelList::lessThan(const QModelIndex &i1, const QModelIndex &i2) c
case TAGS: { case TAGS: {
std::string s1 = taglist_get_tagstring(d1->tag_list); std::string s1 = taglist_get_tagstring(d1->tag_list);
std::string s2 = taglist_get_tagstring(d2->tag_list); std::string s2 = taglist_get_tagstring(d2->tag_list);
int diff = strCmp(s1.c_str(), s2.c_str()); int diff = strCmp(s1, s2);
return lessThanHelper(diff, row_diff); return lessThanHelper(diff, row_diff);
} }
case PHOTOS: case PHOTOS:
return lessThanHelper(countPhotos(d1) - countPhotos(d2), row_diff); return lessThanHelper(countPhotos(d1) - countPhotos(d2), row_diff);
case COUNTRY: case COUNTRY:
return lessThanHelper(strCmp(get_dive_country(d1).c_str(), get_dive_country(d2).c_str()), row_diff); return lessThanHelper(strCmp(get_dive_country(d1), get_dive_country(d2)), row_diff);
case BUDDIES: case BUDDIES:
return lessThanHelper(strCmp(d1->buddy, d2->buddy), row_diff); return lessThanHelper(strCmp(d1->buddy, d2->buddy), row_diff);
case DIVEGUIDE: case DIVEGUIDE:
return lessThanHelper(strCmp(d1->diveguide, d2->diveguide), row_diff); return lessThanHelper(strCmp(d1->diveguide, d2->diveguide), row_diff);
case LOCATION: case LOCATION:
return lessThanHelper(strCmp(get_dive_location(d1).c_str(), get_dive_location(d2).c_str()), row_diff); return lessThanHelper(strCmp(get_dive_location(d1), get_dive_location(d2)), row_diff);
case NOTES: case NOTES:
return lessThanHelper(strCmp(d1->notes, d2->notes), row_diff); return lessThanHelper(strCmp(d1->notes, d2->notes), row_diff);
case DIVEMODE: case DIVEMODE:

View file

@ -449,7 +449,7 @@ static void smtk_build_tank_info(MdbHandle *mdb, cylinder_t *tank, char *idx)
for (i = 1; i <= atoi(idx); i++) for (i = 1; i <= atoi(idx); i++)
table.fetch_row(); table.fetch_row();
tank->type.description = copy_string(table.get_data(1)); tank->type.description = table.get_data(1);
tank->type.size.mliter = lrint(strtod(table.get_data(2), NULL) * 1000); tank->type.size.mliter = lrint(strtod(table.get_data(2), NULL) * 1000);
tank->type.workingpressure.mbar = lrint(strtod(table.get_data(4), NULL) * 1000); tank->type.workingpressure.mbar = lrint(strtod(table.get_data(4), NULL) * 1000);
} }
@ -472,9 +472,9 @@ static bool is_same_cylinder(cylinder_t *cyl_a, cylinder_t *cyl_b)
if (!(abs(cyl_a->end.mbar - cyl_b->end.mbar) <= 100)) if (!(abs(cyl_a->end.mbar - cyl_b->end.mbar) <= 100))
return false; return false;
// different names (none of them null) // different names (none of them null)
if (!same_string(cyl_a->type.description, "---") && if (cyl_a->type.description != "---" &&
!same_string(cyl_b->type.description, "---") && cyl_b->type.description != "---" &&
!same_string(cyl_a->type.description, cyl_b->type.description)) cyl_a->type.description != cyl_b->type.description)
return false; return false;
// Cylinders are most probably the same // Cylinders are most probably the same
return true; return true;
@ -495,9 +495,8 @@ static void merge_cylinder_type(cylinder_type_t *src, cylinder_type_t *dst)
dst->size.mliter = src->size.mliter; dst->size.mliter = src->size.mliter;
if (!dst->workingpressure.mbar) if (!dst->workingpressure.mbar)
dst->workingpressure.mbar = src->workingpressure.mbar; dst->workingpressure.mbar = src->workingpressure.mbar;
if (!dst->description || same_string(dst->description, "---")) { if (dst->description.empty() || dst->description == "---") {
dst->description = src->description; dst->description = std::move(src->description);
src->description = NULL;
} }
} }
@ -532,7 +531,7 @@ static void smtk_clean_cylinders(struct dive *d)
cyl = base + tanks - 1; cyl = base + tanks - 1;
while (cyl != base) { while (cyl != base) {
if (same_string(cyl->type.description, "---") && cyl->start.mbar == 0 && cyl->end.mbar == 0) if (cyl->type.description == "---" && cyl->start.mbar == 0 && cyl->end.mbar == 0)
remove_cylinder(d, i); remove_cylinder(d, i);
else else
if (is_same_cylinder(cyl, cyl - 1)) { if (is_same_cylinder(cyl, cyl - 1)) {

View file

@ -1553,9 +1553,9 @@ struct GasTypeBinner : public MultiBinner<GasTypeBinner, GasTypeBin> {
} }
std::vector<gas_bin_t> to_bin_values(const dive *d) const { std::vector<gas_bin_t> to_bin_values(const dive *d) const {
std::vector<gas_bin_t> res; std::vector<gas_bin_t> res;
res.reserve(d->cylinders.nr); res.reserve(d->cylinders.size());
for (int i = 0; i < d->cylinders.nr; ++i) { for (auto &cyl: d->cylinders) {
struct gasmix mix = d->cylinders.cylinders[i].gasmix; struct gasmix mix = cyl.gasmix;
if (gasmix_is_invalid(mix)) if (gasmix_is_invalid(mix))
continue; continue;
// Add dive to each bin only once. // Add dive to each bin only once.
@ -1591,9 +1591,9 @@ struct GasTypeGeneralBinner : public MultiBinner<GasTypeGeneralBinner, IntBin> {
} }
std::vector<int> to_bin_values(const dive *d) const { std::vector<int> to_bin_values(const dive *d) const {
std::vector<int> res; std::vector<int> res;
res.reserve(d->cylinders.nr); res.reserve(d->cylinders.size());
for (int i = 0; i < d->cylinders.nr; ++i) { for (auto &cyl: d->cylinders) {
struct gasmix mix = d->cylinders.cylinders[i].gasmix; struct gasmix mix = cyl.gasmix;
if (gasmix_is_invalid(mix)) if (gasmix_is_invalid(mix))
continue; continue;
res.push_back(gasmix_to_type(mix)); res.push_back(gasmix_to_type(mix));
@ -1619,9 +1619,9 @@ struct GasTypeVariable : public StatsVariableTemplate<StatsVariable::Type::Discr
QString diveCategories(const dive *d) const override { QString diveCategories(const dive *d) const override {
QString res; QString res;
std::vector<gasmix> mixes; // List multiple cylinders only once std::vector<gasmix> mixes; // List multiple cylinders only once
mixes.reserve(d->cylinders.nr); mixes.reserve(d->cylinders.size());
for (int i = 0; i < d->cylinders.nr; ++i) { for (auto &cyl: d->cylinders) {
struct gasmix mix = d->cylinders.cylinders[i].gasmix; struct gasmix mix = cyl.gasmix;
if (gasmix_is_invalid(mix)) if (gasmix_is_invalid(mix))
continue; continue;
if (std::find_if(mixes.begin(), mixes.end(), if (std::find_if(mixes.begin(), mixes.end(),
@ -1648,7 +1648,7 @@ struct GasTypeVariable : public StatsVariableTemplate<StatsVariable::Type::Discr
// - max_he: get cylinder with maximum he content, otherwise with maximum o2 content // - max_he: get cylinder with maximum he content, otherwise with maximum o2 content
static int get_gas_content(const struct dive *d, bool he, bool max_he) static int get_gas_content(const struct dive *d, bool he, bool max_he)
{ {
if (d->cylinders.nr <= 0) if (d->cylinders.empty())
return invalid_value<int>(); return invalid_value<int>();
// If sorting be He, the second sort criterion is O2 descending, because // If sorting be He, the second sort criterion is O2 descending, because
// we are interested in the "bottom gas": highest He and lowest O2. // we are interested in the "bottom gas": highest He and lowest O2.
@ -1657,7 +1657,7 @@ static int get_gas_content(const struct dive *d, bool he, bool max_he)
std::make_tuple(get_he(c2.gasmix), -get_o2(c2.gasmix)); } std::make_tuple(get_he(c2.gasmix), -get_o2(c2.gasmix)); }
: [] (const cylinder_t &c1, const cylinder_t &c2) : [] (const cylinder_t &c1, const cylinder_t &c2)
{ return get_o2(c1.gasmix) < get_o2(c2.gasmix); }; { return get_o2(c1.gasmix) < get_o2(c2.gasmix); };
auto it = std::max_element(d->cylinders.cylinders, d->cylinders.cylinders + d->cylinders.nr, comp); auto it = std::max_element(d->cylinders.begin(), d->cylinders.end(), comp);
return he ? get_he(it->gasmix) : get_o2(it->gasmix); return he ? get_he(it->gasmix) : get_o2(it->gasmix);
} }
@ -1798,9 +1798,9 @@ struct WeightsystemVariable : public StatsVariableTemplate<StatsVariable::Type::
static std::vector<QString> cylinder_types(const dive *d) static std::vector<QString> cylinder_types(const dive *d)
{ {
std::vector<QString> res; std::vector<QString> res;
res.reserve(d->cylinders.nr); res.reserve(d->cylinders.size());
for (int i = 0; i < d->cylinders.nr; ++i) for (auto &cyl: d->cylinders)
add_to_vector_unique(res, QString(d->cylinders.cylinders[i].type.description).trimmed()); add_to_vector_unique(res, QString::fromStdString(cyl.type.description).trimmed());
return res; return res;
} }