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
put_format(&buf, "\n%% Gas use information:\n");
qty_cyl = 0;
for (i = 0; i < dive->cylinders.nr; i++){
const cylinder_t &cyl = *get_cylinder(dive, i);
if (is_cylinder_used(dive, i) || (prefs.include_unused_tanks && cyl.type.description)){
put_format(&buf, "\\def\\%scyl%cdescription{%s}\n", ssrf, 'a' + i, cyl.type.description);
for (int i = 0; i < static_cast<int>(dive->cylinders.size()); i++){
const cylinder_t &cyl = dive->cylinders[i];
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.c_str());
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%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"));
// 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.
if (dives.count() < 2) {
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),
tags(nullptr)
{
memset(&cylinders, 0, sizeof(cylinders));
memset(&weightsystems, 0, sizeof(weightsystems));
if (what.notes)
notes = data->notes;
@ -656,14 +655,14 @@ PasteState::PasteState(dive *dIn, const dive *data, dive_components what) : d(dI
if (what.tags)
tags = taglist_copy(data->tag_list);
if (what.cylinders) {
copy_cylinders(&data->cylinders, &cylinders);
cylinders = data->cylinders;
// Paste cylinders is "special":
// 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.
// 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) {
const cylinder_t &src = *get_cylinder(d, i);
cylinder_t &dst = cylinders.cylinders[i];
for (size_t i = 0; i < d->cylinders.size() && i < cylinders.size(); ++i) {
const cylinder_t &src = d->cylinders[i];
cylinder_t &dst = cylinders[i];
dst.gasmix = src.gasmix;
dst.start = src.start;
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_he = src.bestmix_he;
}
for (int i = d->cylinders.nr; i < cylinders.nr; ++i) {
cylinder_t &cyl = cylinders.cylinders[i];
for (size_t i = d->cylinders.size(); i < cylinders.size(); ++i) {
cylinder_t &cyl = cylinders[i];
cyl.start.mbar = 0;
cyl.end.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()
{
taglist_free(tags);
clear_cylinder_table(&cylinders);
clear_weightsystem_table(&weightsystems);
free(weightsystems.weightsystems);
}
@ -803,7 +801,6 @@ ReplanDive::ReplanDive(dive *source) : d(current_dive),
duration({0}),
salinity(0)
{
memset(&cylinders, 0, sizeof(cylinders));
if (!d)
return;
@ -828,7 +825,6 @@ ReplanDive::ReplanDive(dive *source) : d(current_dive),
ReplanDive::~ReplanDive()
{
clear_cylinder_table(&cylinders);
free(notes);
}
@ -1124,7 +1120,6 @@ AddCylinder::AddCylinder(bool currentDiveOnly) :
AddCylinder::~AddCylinder()
{
free_cylinder(cyl);
}
bool AddCylinder::workToBeDone()
@ -1148,7 +1143,7 @@ void AddCylinder::redo()
for (dive *d: dives) {
int index = first_hidden_cylinder(d);
indexes.push_back(index);
add_cylinder(&d->cylinders, index, clone_cylinder(cyl));
add_cylinder(&d->cylinders, index, cyl);
update_cylinder_related_info(d);
emit diveListNotifier.cylinderAdded(d, index);
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)
{
return same_string(cyl1.type.description, cyl2.type.description) &&
cyl1.cylinder_use == cyl2.cylinder_use;
return std::tie(cyl1.cylinder_use, cyl1.type.description) ==
std::tie(cyl2.cylinder_use, cyl2.type.description);
}
static bool same_cylinder_size(const cylinder_t &cyl1, const cylinder_t &cyl2)
{
return cyl1.type.size.mliter == cyl2.type.size.mliter &&
cyl1.type.workingpressure.mbar == cyl2.type.workingpressure.mbar;
return std::tie(cyl1.type.size.mliter, cyl1.type.workingpressure.mbar) ==
std::tie(cyl2.type.size.mliter, cyl2.type.workingpressure.mbar);
}
// Flags for comparing cylinders
@ -1177,7 +1172,7 @@ EditCylinderBase::EditCylinderBase(int index, bool currentDiveOnly, bool nonProt
EditDivesBase(currentDiveOnly)
{
// 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();
return;
}
@ -1189,12 +1184,12 @@ EditCylinderBase::EditCylinderBase(int index, bool currentDiveOnly, bool nonProt
cyl.reserve(dives.size());
for (dive *d: dives) {
if (index >= d->cylinders.nr)
if (index >= static_cast<int>(d->cylinders.size()))
continue;
if (nonProtectedOnly && is_cylinder_prot(d, index))
continue;
// 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 &&
(!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
@ -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
// a cylinder to several dives as the spot will potentially be different in different dives
indexes.push_back(index);
cyl.push_back(clone_cylinder(cylinder));
cyl.push_back(cylinder);
}
dives = std::move(divesNew);
}
EditCylinderBase::~EditCylinderBase()
{
for (cylinder_t c: cyl)
free_cylinder(c);
}
bool EditCylinderBase::workToBeDone()
@ -1235,8 +1228,8 @@ RemoveCylinder::RemoveCylinder(int index, bool currentDiveOnly) :
void RemoveCylinder::undo()
{
for (size_t i = 0; i < dives.size(); ++i) {
std::vector<int> mapping = get_cylinder_map_for_add(dives[i]->cylinders.nr, indexes[i]);
add_cylinder(&dives[i]->cylinders, indexes[i], clone_cylinder(cyl[i]));
std::vector<int> mapping = get_cylinder_map_for_add(dives[i]->cylinders.size(), indexes[i]);
add_cylinder(&dives[i]->cylinders, indexes[i], cyl[i]);
cylinder_renumber(dives[i], &mapping[0]);
update_cylinder_related_info(dives[i]);
emit diveListNotifier.cylinderAdded(dives[i], indexes[i]);
@ -1247,7 +1240,7 @@ void RemoveCylinder::undo()
void RemoveCylinder::redo()
{
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]);
cylinder_renumber(dives[i], &mapping[0]);
update_cylinder_related_info(dives[i]);
@ -1282,15 +1275,12 @@ EditCylinder::EditCylinder(int index, cylinder_t cylIn, EditCylinderType typeIn,
else
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
for (int i = 0; i < (int)indexes.size(); ++i) {
switch (type) {
case EditCylinderType::TYPE:
free((void *)cyl[i].type.description);
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;
break;
case EditCylinderType::PRESSURE:
@ -1301,7 +1291,7 @@ EditCylinder::EditCylinder(int index, cylinder_t cylIn, EditCylinderType typeIn,
cyl[i].gasmix = cylIn.gasmix;
cyl[i].bestmix_o2 = cylIn.bestmix_o2;
cyl[i].bestmix_he = cylIn.bestmix_he;
sanitize_gasmix(&cyl[i].gasmix);
sanitize_gasmix(cyl[i].gasmix);
break;
}
}
@ -1310,7 +1300,7 @@ EditCylinder::EditCylinder(int index, cylinder_t cylIn, EditCylinderType typeIn,
void EditCylinder::redo()
{
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);
std::swap(*get_cylinder(dives[i], indexes[i]), cyl[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_COMMANDER:
if (config.type == TYPE_GEMINI) {
cylinder_t cyl;
dc->model = "Gemini";
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
+ log[CMD_O2_PERCENT + 1]) * 10;
cyl.gasmix.he.permille = 0;
add_cylinder(&dive->cylinders, 0, cyl);
add_cylinder(&dive->cylinders, 0, std::move(cyl));
} else {
dc->model = "Commander";
dc->deviceid = array_uint32_le(buf + 0x31e); // serial no
for (g = 0; g < 2; g++) {
cylinder_t cyl;
fill_default_cylinder(dive.get(), &cyl);
cylinder_t cyl = default_cylinder(dive.get());
cyl.gasmix.o2.permille = (log[CMD_O2_PERCENT + g * 2] / 256
+ log[CMD_O2_PERCENT + g * 2 + 1]) * 10;
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->deviceid = array_uint32_le(buf + 0x31e); // serial no
for (g = 0; g < 4; g++) {
cylinder_t cyl;
fill_default_cylinder(dive.get(), &cyl);
cylinder_t cyl = default_cylinder(dive.get());
cyl.gasmix.o2.permille =
(log[EMC_O2_PERCENT + g * 2] / 256
+ log[EMC_O2_PERCENT + g * 2 + 1]) * 10;
cyl.gasmix.he.permille =
(log[EMC_HE_PERCENT + g * 2] / 256
+ 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];

View file

@ -334,14 +334,13 @@ static char *dt_dive_parser(unsigned char *runner, struct dive *dt_dive, struct
read_bytes(2);
if (tmp_2bytes != 0x7FFF) {
cylinder_t cyl;
std::string desc = cyl_type_by_size(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.gasmix.he.permille = 0;
cyl.gasmix.o2.permille = 210;
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.
*/
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));
/*
@ -548,10 +547,10 @@ static char *dt_dive_parser(unsigned char *runner, struct dive *dt_dive, struct
free(compl_buffer);
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 =
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;
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;
else
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)->gas_used.mliter / get_cylinder(dt_dive, 0)->type.size.mliter) * 1000);
}

View file

@ -17,6 +17,7 @@
#include "errorhelper.h"
#include "event.h"
#include "extradata.h"
#include "format.h"
#include "interpolate.h"
#include "qthelper.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 */
/* 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. */
//if (idx < 0 || idx >= dive->cylinders.nr) {
if (idx < 0 || idx >= dive->cylinders.nr + 1 || idx >= dive->cylinders.allocated) {
//if (idx < 0 || idx >= dive->cylinders.size()) {
if (idx < 0 || static_cast<size_t>(idx) >= dive->cylinders.size() + 1) {
report_error("Unknown cylinder index: %d", idx);
return;
}
@ -135,9 +136,7 @@ struct gasmix get_gasmix_from_event(const struct dive *dive, const struct event
if (ev.is_gaschange()) {
int index = ev.gas.index;
// FIXME: The planner uses one past cylinder-count to signify "surface air". Remove in due course.
if (index == dive->cylinders.nr)
return gasmix_air;
if (index >= 0 && index < dive->cylinders.nr)
if (index >= 0 && static_cast<size_t>(index) < dive->cylinders.size() + 1)
return get_cylinder(dive, index)->gasmix;
return ev.gas.mix;
}
@ -176,8 +175,7 @@ static void free_dive_structures(struct dive *d)
free(d->suit);
/* free tags, additional dive computers, and pictures */
taglist_free(d->tag_list);
clear_cylinder_table(&d->cylinders);
free(d->cylinders.cylinders);
d->cylinders.clear();
clear_weightsystem_table(&d->weightsystems);
free(d->weightsystems.weightsystems);
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;
* 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
* so we can ignore those */
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,
* so all the strings and the structured lists */
*d = *s;
memset(&d->cylinders, 0, sizeof(d->cylinders));
memset(&d->weightsystems, 0, sizeof(d->weightsystems));
memset(&d->pictures, 0, sizeof(d->pictures));
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->notes = copy_string(s->notes);
d->suit = copy_string(s->suit);
copy_cylinders(&s->cylinders, &d->cylinders);
copy_weights(&s->weightsystems, &d->weightsystems);
copy_pictures(&s->pictures, &d->pictures);
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)
{
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)
{
int i;
if (!s || !d)
return;
clear_cylinder_table(&d->cylinders);
for (i = 0; i < s->cylinders.nr; i++) {
d->cylinders.clear();
for (auto [i, cyl]: enumerated_range(s->cylinders)) {
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? */
#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;
start_mbar = cyl->start.mbar ?: cyl->sample_start.mbar;
end_mbar = cyl->end.mbar ?: cyl->sample_end.mbar;
start_mbar = cyl.start.mbar ?: cyl.sample_start.mbar;
end_mbar = cyl.end.mbar ?: cyl.sample_end.mbar;
// More than 5 bar used? This matches statistics.cpp
// heuristics
@ -369,10 +359,10 @@ static bool cylinder_used(const cylinder_t *cyl)
/* Get list of used cylinders. Returns the number of used cylinders. */
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++) {
used[i] = cylinder_used(get_cylinder(dive, i));
for (auto [i, cyl]: enumerated_range(dive->cylinders)) {
used[i] = cylinder_used(cyl);
if (used[i])
num++;
}
@ -384,8 +374,8 @@ static bool has_unknown_used_cylinders(const struct dive *dive, const struct div
const bool used_cylinders[], int num)
{
int idx;
auto used_and_unknown = std::make_unique<bool[]>(dive->cylinders.nr);
std::copy(used_cylinders, used_cylinders + dive->cylinders.nr, used_and_unknown.get());
auto used_and_unknown = std::make_unique<bool[]>(dive->cylinders.size());
std::copy(used_cylinders, used_cylinders + dive->cylinders.size(), used_and_unknown.get());
/* We know about using the O2 cylinder in a CCR dive */
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)
{
int i;
int32_t lasttime = 0;
int lastdepth = 0;
int idx = 0;
int num_used_cylinders;
if (dive->cylinders.nr <= 0)
if (dive->cylinders.empty())
return;
for (i = 0; i < dive->cylinders.nr; i++)
for (size_t i = 0; i < dive->cylinders.size(); i++)
mean[i] = duration[i] = 0;
if (!dc)
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
* 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());
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
* and duration
*/
for (i = 0; i < dive->cylinders.nr; i++) {
for (size_t i = 0; i < dive->cylinders.size(); i++) {
if (used_cylinders[i]) {
mean[i] = dc->meandepth.mm;
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);
event_loop loop("gaschange");
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) {
int32_t time = it->time.seconds;
int depth = it->depth.mm;
@ -494,7 +483,7 @@ void per_cylinder_mean_depth(const struct dive *dive, struct divecomputer *dc, i
lastdepth = depth;
lasttime = time;
}
for (i = 0; i < dive->cylinders.nr; i++) {
for (size_t i = 0; i < dive->cylinders.size(); i++) {
if (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 res = 0;
if (!dive->cylinders.nr)
if (dive->cylinders.empty())
return -1;
if (dc) {
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)
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)
@ -598,22 +587,18 @@ void update_setpoint_events(const struct dive *dive, struct divecomputer *dc)
* cylinder name is independent from the gasmix, and different
* 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? */
if (type->description)
if (!type.description.empty())
return;
bar = type->workingpressure.mbar / 1000.0;
cuft = ml_to_cuft(type->size.mliter);
double bar = type.workingpressure.mbar / 1000.0;
double cuft = ml_to_cuft(type.size.mliter);
cuft *= bar_to_atm(bar);
psi = lrint(to_PSI(type->workingpressure));
int psi = lrint(to_PSI(type.workingpressure));
const char *fmt;
switch (psi) {
case 2300 ... 2500: /* 2400 psi: LP tank */
fmt = "LP%d";
@ -633,12 +618,7 @@ static void match_standard_cylinder(cylinder_type_t *type)
default:
return;
}
len = snprintf(buffer, sizeof(buffer), fmt, (int)lrint(cuft));
p = (char *)malloc(len + 1);
if (!p)
return;
memcpy(p, buffer, len + 1);
type->description = p;
type.description = format_string_std(fmt, (int)lrint(cuft));
}
/*
@ -651,14 +631,14 @@ static void match_standard_cylinder(cylinder_type_t *type)
* We internally use physical size only. But we save the workingpressure
* 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 (!type->workingpressure.mbar)
if (!type.workingpressure.mbar)
return;
/* No size either? Nothing to go on */
if (!type->size.mliter)
if (!type.size.mliter)
return;
/* 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)
{
int i;
for (i = 0; i < dive->cylinders.nr; i++) {
sanitize_gasmix(&get_cylinder(dive, i)->gasmix);
sanitize_cylinder_type(&get_cylinder(dive, i)->type);
for (auto &cyl :dive->cylinders) {
sanitize_gasmix(cyl.gasmix);
sanitize_cylinder_type(cyl.type);
}
}
@ -935,19 +913,19 @@ static void simplify_dc_pressures(struct divecomputer &dc)
/* Do we need a sensor -> cylinder mapping? */
static void fixup_start_pressure(struct dive *dive, int idx, pressure_t p)
{
if (idx >= 0 && idx < dive->cylinders.nr) {
cylinder_t *cyl = get_cylinder(dive, idx);
if (p.mbar && !cyl->sample_start.mbar)
cyl->sample_start = p;
if (idx >= 0 && static_cast<size_t>(idx) < dive->cylinders.size()) {
cylinder_t &cyl = dive->cylinders[idx];
if (p.mbar && !cyl.sample_start.mbar)
cyl.sample_start = p;
}
}
static void fixup_end_pressure(struct dive *dive, int idx, pressure_t p)
{
if (idx >= 0 && idx < dive->cylinders.nr) {
cylinder_t *cyl = get_cylinder(dive, idx);
if (p.mbar && !cyl->sample_end.mbar)
cyl->sample_end = p;
if (idx >= 0 && static_cast<size_t>(idx) < dive->cylinders.size()) {
cylinder_t &cyl = dive->cylinders[idx];
if (p.mbar && !cyl.sample_end.mbar)
cyl.sample_end = p;
}
}
@ -1003,13 +981,13 @@ static bool validate_gaschange(struct dive *dive, struct event &event)
if (event.gas.index >= 0)
return true;
index = find_best_gasmix_match(event.gas.mix, &dive->cylinders);
if (index < 0 || index >= dive->cylinders.nr)
index = find_best_gasmix_match(event.gas.mix, dive->cylinders);
if (index < 0 || static_cast<size_t>(index) >= dive->cylinders.size())
return false;
/* Fix up the event to have the right information */
event.gas.index = index;
event.gas.mix = get_cylinder(dive, index)->gasmix;
event.gas.mix = dive->cylinders[index].gasmix;
/* Convert to odd libdivecomputer format */
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
sensor_mask >>= dive->cylinders.nr;
sensor_mask >>= dive->cylinders.size();
// Do we need to add empty cylinders?
while (sensor_mask) {
@ -1160,13 +1138,12 @@ struct dive *fixup_dive(struct dive *dive)
fixup_duration(dive);
fixup_watertemp(dive);
fixup_airtemp(dive);
for (i = 0; i < dive->cylinders.nr; i++) {
cylinder_t *cyl = get_cylinder(dive, i);
add_cylinder_description(cyl->type);
if (same_rounded_pressure(cyl->sample_start, cyl->start))
cyl->start.mbar = 0;
if (same_rounded_pressure(cyl->sample_end, cyl->end))
cyl->end.mbar = 0;
for (auto &cyl: dive->cylinders) {
add_cylinder_description(cyl.type);
if (same_rounded_pressure(cyl.sample_start, cyl.start))
cyl.start.mbar = 0;
if (same_rounded_pressure(cyl.sample_end, cyl.end))
cyl.end.mbar = 0;
}
update_cylinder_related_info(dive);
for (i = 0; i < dive->weightsystems.nr; i++) {
@ -1487,12 +1464,9 @@ pick_b:
* 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 cylinder_index;
for (cylinder_index = 0; cylinder_index < dive->cylinders.nr; cylinder_index++) {
if (get_cylinder(dive, cylinder_index)->cylinder_use == cylinder_use_type)
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
auto it = std::find_if(dive->cylinders.begin(), dive->cylinders.end(), [cylinder_use_type]
(auto &cyl) { return cyl.cylinder_use == cylinder_use_type; });
return it != dive->cylinders.end() ? it - dive->cylinders.begin() : -1;
}
/* 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);
}
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;
for (int i = 0; i < dive->cylinders.nr; i++) {
struct gasmix mygas = cyl.gasmix;
for (auto [i, cyl]: enumerated_range(dive->cylinders)) {
if (i == cylid)
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))
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[])
{
int i;
for (i = 0; i < dive->cylinders.nr; i++) {
const cylinder_t *target;
for (auto [i, target]: enumerated_range(dive->cylinders)) {
if (!try_match[i])
continue;
target = get_cylinder(dive, i);
if (!same_gasmix(cyl->gasmix, target->gasmix))
if (!same_gasmix(cyl->gasmix, target.gasmix))
continue;
if (cyl->cylinder_use != target->cylinder_use)
if (cyl->cylinder_use != target.cylinder_use)
continue;
if (different_manual_pressures(cyl, target))
if (different_manual_pressures(cyl, &target))
continue;
/* 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;
if (!a->type.workingpressure.mbar)
a->type.workingpressure.mbar = b->type.workingpressure.mbar;
if (empty_string(a->type.description))
a->type.description = copy_string(b->type.description);
if (a->type.description.empty())
a->type.description = b->type.description;
/* If either cylinder has manually entered pressures, try to merge them.
* 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;
}
static bool cylinder_has_data(const cylinder_t *cyl)
static bool cylinder_has_data(const cylinder_t &cyl)
{
return !cyl->type.size.mliter &&
!cyl->type.workingpressure.mbar &&
!cyl->type.description &&
!cyl->gasmix.o2.permille &&
!cyl->gasmix.he.permille &&
!cyl->start.mbar &&
!cyl->end.mbar &&
!cyl->sample_start.mbar &&
!cyl->sample_end.mbar &&
!cyl->gas_used.mliter &&
!cyl->deco_gas_used.mliter;
return !cyl.type.size.mliter &&
!cyl.type.workingpressure.mbar &&
cyl.type.description.empty() &&
!cyl.gasmix.o2.permille &&
!cyl.gasmix.he.permille &&
!cyl.start.mbar &&
!cyl.end.mbar &&
!cyl.sample_start.mbar &&
!cyl.sample_end.mbar &&
!cyl.gas_used.mliter &&
!cyl.deco_gas_used.mliter;
}
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;
/* 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;
/* 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,
int mapping_a[], int mapping_b[])
{
int i;
int max_cylinders = a->cylinders.nr + b->cylinders.nr;
size_t max_cylinders = a->cylinders.size() + b->cylinders.size();
auto used_in_a = 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);
std::fill(try_to_match.get(), try_to_match.get() + max_cylinders, false);
/* First, clear all cylinders in destination */
clear_cylinder_table(&res->cylinders);
res->cylinders.clear();
/* Clear all cylinder mappings */
std::fill(mapping_a, mapping_a + a->cylinders.nr, -1);
std::fill(mapping_b, mapping_b + b->cylinders.nr, -1);
std::fill(mapping_a, mapping_a + a->cylinders.size(), -1);
std::fill(mapping_b, mapping_b + b->cylinders.size(), -1);
/* 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_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'.
* These are also potential matches for 'b' to use.
*/
for (i = 0; i < max_cylinders; i++) {
int res_nr = res->cylinders.nr;
for (size_t i = 0; i < max_cylinders; i++) {
size_t res_nr = res->cylinders.size();
if (!used_in_a[i])
continue;
mapping_a[i] = res_nr;
mapping_a[i] = static_cast<int>(res_nr);
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
* 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;
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 */
if (j < 0) {
int res_nr = res->cylinders.nr;
mapping_b[i] = res_nr;
add_cloned_cylinder(&res->cylinders, *get_cylinder(b, i));
size_t res_nr = res->cylinders.size();
mapping_b[i] = static_cast<int>(res_nr);
res->cylinders.push_back(b->cylinders[i]);
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);
/* 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 */
auto cylinders_map_a = std::make_unique<int[]>(std::max(1, a->cylinders.nr));
auto cylinders_map_b = std::make_unique<int[]>(std::max(1, b->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(size_t(1), b->cylinders.size()));
merge_cylinders(res, a, b, cylinders_map_a.get(), cylinders_map_b.get());
merge_equipment(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_maxtemp = d->maxtemp.mkelvin;
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;
dc->maxdepth.mm = 0;
@ -2465,12 +2433,11 @@ static void force_fixup_dive(struct dive *d)
d->duration.seconds = 0;
d->maxtemp.mkelvin = 0;
d->mintemp.mkelvin = 0;
for (int i = 0; i < d->cylinders.nr; i++) {
cylinder_t *cyl = get_cylinder(d, i);
old_pressures[i].start = cyl->start;
old_pressures[i].end = cyl->end;
cyl->start.mbar = 0;
cyl->end.mbar = 0;
for (auto [i, cyl]: enumerated_range(d->cylinders)) {
old_pressures[i].start = cyl.start;
old_pressures[i].end = cyl.end;
cyl.start.mbar = 0;
cyl.end.mbar = 0;
}
fixup_dive(d);
@ -2489,11 +2456,11 @@ static void force_fixup_dive(struct dive *d)
if (!d->duration.seconds)
d->duration = old_duration;
for (int i = 0; i < d->cylinders.nr; i++) {
if (!get_cylinder(d, i)->start.mbar)
get_cylinder(d, i)->start = old_pressures[i].start;
if (!get_cylinder(d, i)->end.mbar)
get_cylinder(d, i)->end = old_pressures[i].end;
for (auto [i, cyl]: enumerated_range(d->cylinders)) {
if (!cyl.start.mbar)
cyl.start = old_pressures[i].start;
if (!cyl.end.mbar)
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")
{
/* if there is no cylinder, return air */
if (dive.cylinders.nr <= 0)
if (dive.cylinders.empty())
return;
/* 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)
{
/* if there is no cylinder, return air */
if (dive.cylinders.nr <= 0)
if (dive.cylinders.empty())
return last;
while (ev && ev->time.seconds <= time) {

View file

@ -30,7 +30,7 @@ struct dive {
struct dive_site *dive_site = nullptr;
char *notes = nullptr;
char *diveguide = nullptr, *buddy = nullptr;
struct cylinder_table cylinders = { };
struct cylinder_table cylinders;
struct weightsystem_table weightsystems = { };
char *suit = nullptr;
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 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? */
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 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 int nr_cylinders(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);

View file

@ -32,19 +32,17 @@
*/
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;
for (i = 0; i < dive->cylinders.nr; i++) {
const cylinder_t *cyl = get_cylinder(dive, i);
int o2 = get_o2(cyl->gasmix);
int he = get_he(cyl->gasmix);
for (auto [i, cyl]: enumerated_range(dive->cylinders)) {
int o2 = get_o2(cyl.gasmix);
int he = get_he(cyl.gasmix);
if (!is_cylinder_used(dive, i))
continue;
if (cyl->cylinder_use == OXYGEN)
if (cyl.cylinder_use == OXYGEN)
continue;
if (cyl->cylinder_use == NOT_USED)
if (cyl.cylinder_use == NOT_USED)
continue;
if (o2 > maxo2)
maxo2 = o2;
@ -337,12 +335,11 @@ static double calculate_airuse(const struct dive *dive)
if (dive->dcs[0].divemode == CCR)
return 0.0;
for (int i = 0; i < dive->cylinders.nr; i++) {
for (auto [i, cyl]: enumerated_range(dive->cylinders)) {
pressure_t start, end;
const cylinder_t *cyl = get_cylinder(dive, i);
start = cyl->start.mbar ? cyl->start : cyl->sample_start;
end = cyl->end.mbar ? cyl->end : cyl->sample_end;
start = cyl.start.mbar ? cyl.start : cyl.sample_start;
end = cyl.end.mbar ? cyl.end : cyl.sample_end;
if (!end.mbar || start.mbar <= end.mbar) {
// 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.
@ -354,7 +351,7 @@ static double calculate_airuse(const struct dive *dive)
continue;
}
airuse += gas_volume(cyl, start) - gas_volume(cyl, end);
airuse += gas_volume(&cyl, start) - gas_volume(&cyl, end);
}
return airuse / 1000.0;
}

View file

@ -18,9 +18,43 @@
#include "divelog.h"
#include "errorhelper.h"
#include "pref.h"
#include "range.h"
#include "subsurface-string.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
* 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.
@ -31,12 +65,6 @@ void free_weightsystem(weightsystem_t ws)
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)
{
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]);
}
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 */
//static MAKE_GET_IDX(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_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] = {
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)
{
std::string desc = type.description ? type.description : std::string();
const std::string &desc = type.description;
if (desc.empty())
return;
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;
add_tank_info_metric(tank_info_table, desc, type.size.mliter,
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));
}
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;
res.type.description = copy_string(res.type.description);
return res;
add_to_weightsystem_table(t, t->nr, clone_weightsystem(ws));
}
void add_cylinder(struct cylinder_table *t, int idx, cylinder_t cyl)
{
add_to_cylinder_table(t, idx, 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));
t->insert(t->begin() + idx, std::move(cyl));
}
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);
}
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;
for (i = 0; i < cylinders->nr; i++) {
const cylinder_t *match;
int distance;
match = cylinders->cylinders + i;
distance = gasmix_distance(mix, match->gasmix);
for (auto [i, match]: enumerated_range(cylinders)) {
int distance = gasmix_distance(mix, match.gasmix);
if (distance >= score)
continue;
best = i;
@ -336,10 +327,8 @@ void reset_tank_info_table(std::vector<tank_info> &table)
/* Add cylinders from dive list */
for (int i = 0; i < divelog.dives->nr; ++i) {
const struct dive *dive = divelog.dives->dives[i];
for (int j = 0; j < dive->cylinders.nr; j++) {
const cylinder_t *cyl = get_cylinder(dive, j);
add_cylinder_description(cyl->type);
}
for (auto &cyl: dive->cylinders)
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)
{
remove_from_cylinder_table(&dive->cylinders, idx);
dive->cylinders.erase(dive->cylinders.begin() + 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};
for (int i = 0; i < dive->cylinders.nr; i++) {
cylinder_t *cyl = get_cylinder(dive, i);
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));
for (cylinder_t &cyl: dive->cylinders) {
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));
if (track_gas)
cyl->start.mbar = cyl->end.mbar = cyl->type.workingpressure.mbar;
cyl->gas_used.mliter = 0;
cyl->deco_gas_used.mliter = 0;
cyl.start.mbar = cyl.end.mbar = cyl.type.workingpressure.mbar;
cyl.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.description = s->type.description ? strdup(s->type.description) : NULL;
d->gasmix = s->gasmix;
d->depth = s->depth;
d->cylinder_use = s->cylinder_use;
d->manually_added = true;
d.type = s.type;
d.gasmix = s.gasmix;
d.depth = s.depth;
d.cylinder_use = s.cylinder_use;
d.manually_added = true;
}
/* copy the equipment data part of the cylinders but keep pressures */
void copy_cylinder_types(const struct dive *s, struct dive *d)
{
int i;
if (!s || !d)
return;
for (i = 0; i < s->cylinders.nr && i < d->cylinders.nr; i++)
copy_cylinder_type(get_cylinder(s, i), get_cylinder(d, i));
for (size_t i = 0; i < s->cylinders.size() && i < d->cylinders.size(); i++)
copy_cylinder_type(s->cylinders[i], d->cylinders[i]);
for ( ; i < s->cylinders.nr; i++)
add_cloned_cylinder(&d->cylinders, *get_cylinder(s, i));
for (size_t i = d->cylinders.size(); i < s->cylinders.size(); i++)
d->cylinders.push_back(s->cylinders[i]);
}
cylinder_t *add_empty_cylinder(struct cylinder_table *t)
{
cylinder_t cyl;
cyl.type.description = strdup("");
add_cylinder(t, t->nr, cyl);
return &t->cylinders[t->nr - 1];
t->emplace_back();
return &t->back();
}
/* access to cylinders is controlled by two functions:
* - get_cylinder() returns the cylinder of a dive and supposes that
* 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.
* Multiple cylinders might be created if the index is bigger than the
* 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
* 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) {
report_info("Warning: accessing invalid cylinder %d (%d existing)", idx, d->cylinders.nr);
return NULL;
}
return &d->cylinders.cylinders[idx];
return &d->cylinders[idx];
}
const cylinder_t *get_cylinder(const struct dive *d, int idx)
{
return &d->cylinders[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);
return NULL;
}
while (idx >= d->cylinders.nr)
while (static_cast<size_t>(idx) >= d->cylinders.size())
add_empty_cylinder(&d->cylinders);
return &d->cylinders.cylinders[idx];
return &d->cylinders[idx];
}
/* if a default cylinder is set, use that */
@ -465,7 +447,7 @@ void fill_default_cylinder(const struct dive *dive, cylinder_t *cyl)
return;
for (auto &ti: tank_info_table) {
if (ti.name == cyl_name) {
cyl->type.description = strdup(ti.name.c_str());
cyl->type.description = ti.name;
if (ti.ml) {
cyl->type.size.mliter = ti.ml;
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 cyl;
fill_default_cylinder(d, &cyl);
cylinder_t cyl = default_cylinder(d);
cyl.start = cyl.type.workingpressure;
cyl.cylinder_use = OC_GAS;
return cyl;
@ -500,7 +488,7 @@ cylinder_t create_new_manual_cylinder(const struct dive *d)
void add_default_cylinder(struct dive *d)
{
// Only add if there are no cylinders yet
if (d->cylinders.nr > 0)
if (!d->cylinders.empty())
return;
cylinder_t cyl;
@ -508,7 +496,7 @@ void add_default_cylinder(struct dive *d)
cyl = create_new_cylinder(d);
} else {
// roughly an AL80
cyl.type.description = strdup(translate("gettextFromC", "unknown"));
cyl.type.description = translate("gettextFromC", "unknown");
cyl.type.size.mliter = 11100;
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))
return true;
const cylinder_t *cyl = &d->cylinders.cylinders[i];
if (cyl->start.mbar || cyl->sample_start.mbar ||
cyl->end.mbar || cyl->sample_end.mbar)
const cylinder_t &cyl = d->cylinders[i];
if (cyl.start.mbar || cyl.sample_start.mbar ||
cyl.end.mbar || cyl.sample_end.mbar)
return true;
if (cyl->manually_added)
if (cyl.manually_added)
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. */
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))
--res;
return res;
return static_cast<int>(res);
}
#ifdef DEBUG_CYL
@ -551,7 +539,7 @@ void dump_cylinders(struct dive *dive, bool verbose)
for (int i = 0; i < dive->cylinders; 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(" 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) {

View file

@ -17,7 +17,7 @@ struct cylinder_type_t
{
volume_t size;
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
@ -32,17 +32,23 @@ struct cylinder_t
enum cylinderuse cylinder_use = OC_GAS;
bool bestmix_o2 = false;
bool bestmix_he = false;
cylinder_t();
~cylinder_t();
};
/* Table of cylinders. Attention: this stores cylinders,
* *not* pointers to cylinders. This has two crucial consequences:
* 1) Pointers to cylinders are not stable. They may be
* invalidated if the table is reallocated.
* 2) add_cylinder(), etc. take ownership of the
* cylinder. Notably of the description string. */
struct cylinder_table {
int nr, allocated;
cylinder_t *cylinders;
/* Table of cylinders.
* This is a crazy class: it is basically a std::vector<>, but overrides
* the [] accessor functions and allows out-of-bound accesses.
* This is used in the planner, which uses "max_index + 1" for the
* surface air cylinder.
* Note: an out-of-bound access returns a reference to an object with
* static linkage that MUST NOT be written into.
* Yes, this is all very mad, but it grew historically.
*/
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
@ -68,16 +74,13 @@ struct weightsystem_table {
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_cylinders(const struct cylinder_table *s, struct cylinder_table *d);
extern weightsystem_t clone_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 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 void add_cloned_cylinder(struct cylinder_table *t, cylinder_t cyl);
extern cylinder_t *get_cylinder(const struct dive *d, int idx);
extern cylinder_t *get_cylinder(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 bool same_weightsystem(weightsystem_t w1, weightsystem_t w2);
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 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 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 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 void add_default_cylinder(struct dive *dive);
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);
/* Cylinder table functions */
extern void clear_cylinder_table(struct cylinder_table *);
extern void add_cylinder(struct cylinder_table *, int idx, cylinder_t cyl);
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)
{
QStringList cylinderTypes;
for (int i = 0; i < d->cylinders.nr; ++i)
cylinderTypes.push_back(d->cylinders.cylinders[i].type.description);
for (const cylinder_t &cyl: d->cylinders)
cylinderTypes.push_back(QString::fromStdString(cyl.type.description));
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)
{
for (int i = 0; i < d->cylinders.nr; ++i) {
const cylinder_t &cyl = d->cylinders.cylinders[i];
if (cyl.type.size.mliter && check_numerical_range(c, cyl.type.size.mliter))
return true;
}
return false;
return std::any_of(d->cylinders.begin(), d->cylinders.end(), [&c](auto &cyl)
{ return cyl.type.size.mliter &&
check_numerical_range(c, cyl.type.size.mliter); });
}
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) {
const cylinder_t &cyl = d->cylinders.cylinders[i];
if (check_numerical_range(c, get_gas_component_fraction(cyl.gasmix, component).permille))
return true;
}
return false;
return std::any_of(d->cylinders.begin(), d->cylinders.end(), [&c, &component](auto &cyl)
{ return check_numerical_range(c, get_gas_component_fraction(cyl.gasmix, component).permille); });
}
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);
for (const tag_entry *tag = d->tag_list; tag; tag = tag->next)
tokenize(QString::fromStdString(tag->tag->name), res);
for (int i = 0; i < d->cylinders.nr; ++i) {
const cylinder_t &cyl = *get_cylinder(d, i);
tokenize(QString(cyl.type.description), res);
}
for (auto &cyl: d->cylinders)
tokenize(QString::fromStdString(cyl.type.description), res);
for (int i = 0; i < d->weightsystems.nr; ++i) {
const weightsystem_t &ws = d->weightsystems.weightsystems[i];
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);
}
void sanitize_gasmix(struct gasmix *mix)
void sanitize_gasmix(struct gasmix &mix)
{
unsigned int o2, he;
o2 = get_o2(*mix);
he = get_he(*mix);
o2 = get_o2(mix);
he = get_he(mix);
/* Regular air: leave empty */
if (!he) {
if (!o2)
return;
/* 20.8% to 21% O2 is just air */
if (gasmix_is_air(*mix)) {
mix->o2.permille = 0;
if (gasmix_is_air(mix)) {
mix.o2.permille = 0;
return;
}
}
@ -62,7 +62,7 @@ void sanitize_gasmix(struct gasmix *mix)
if (o2 <= 1000 && he <= 1000 && o2 + he <= 1000)
return;
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)

View file

@ -58,7 +58,7 @@ struct gas_pressures {
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 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);

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)
{
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;
size_t current = std::string::npos;
int missing_pr = 0, dense = 1;
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;
/* 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;
char *lineptr;
int prev_time = 0;
cylinder_t cyl;
struct divecomputer *dc;
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].no_o2sensors = 2;
cyl.cylinder_use = OXYGEN;
cyl.type.size.mliter = 3000;
cyl.type.workingpressure.mbar = 200000;
cyl.type.description = "3l Mk6";
cyl.gasmix.o2.permille = 1000;
cyl.manually_added = true;
cyl.bestmix_o2 = 0;
cyl.bestmix_he = 0;
add_cloned_cylinder(&dive->cylinders, cyl);
{
cylinder_t cyl;
cyl.cylinder_use = OXYGEN;
cyl.type.size.mliter = 3000;
cyl.type.workingpressure.mbar = 200000;
cyl.type.description = "3l Mk6";
cyl.gasmix.o2.permille = 1000;
cyl.manually_added = true;
cyl.bestmix_o2 = 0;
cyl.bestmix_he = 0;
dive->cylinders.push_back(std::move(cyl));
}
cyl.cylinder_use = DILUENT;
cyl.type.size.mliter = 3000;
cyl.type.workingpressure.mbar = 200000;
cyl.type.description = "3l Mk6";
value = parse_mkvi_value(memtxt.data(), "Helium percentage");
he = atoi(value.c_str());
value = parse_mkvi_value(memtxt.data(), "Nitrogen percentage");
cyl.gasmix.o2.permille = (100 - atoi(value.c_str()) - he) * 10;
cyl.gasmix.he.permille = he * 10;
add_cloned_cylinder(&dive->cylinders, cyl);
{
cylinder_t cyl;
cyl.cylinder_use = DILUENT;
cyl.type.size.mliter = 3000;
cyl.type.workingpressure.mbar = 200000;
cyl.type.description = "3l Mk6";
value = parse_mkvi_value(memtxt.data(), "Helium percentage");
he = atoi(value.c_str());
value = parse_mkvi_value(memtxt.data(), "Nitrogen percentage");
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");
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->pressure[0].mbar = pressure * 100;
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;
int o2 = get_o2(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;
// Find the cylinder index
int index;
bool found = false;
for (index = 0; index < state->cur_dive->cylinders.nr; ++index) {
const cylinder_t *cyl = get_cylinder(state->cur_dive.get(), index);
if (cyl->gasmix.o2.permille == o2 && cyl->gasmix.he.permille == he) {
found = true;
break;
}
}
if (!found) {
auto it = std::find_if(state->cur_dive->cylinders.begin(), state->cur_dive->cylinders.end(),
[o2, he](auto &cyl)
{ return cyl.gasmix.o2.permille == o2 && cyl.gasmix.he.permille == he; });
if (it == state->cur_dive->cylinders.end()) {
// Cylinder not found, creating a new one
cyl = cylinder_start(state);
cyl->gasmix.o2.permille = o2;
cyl->gasmix.he.permille = he;
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;
}
@ -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));
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));
if (data[3]) {
if (data[3])
state->cur_sample->setpoint.mbar = lrint(permissive_strtod(data[3], NULL) * 1000);
}
if (data[4])
state->cur_sample->ndl.seconds = atoi(data[4]) * 60;
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;
}
clear_cylinder_table(&dive->cylinders);
dive->cylinders.clear();
for (i = 0; i < std::max(ngases, ntanks); i++) {
cylinder_t cyl;
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);
break;
}
cyl.type.description = copy_string(name_buffer);
cyl.type.description = name_buffer;
cyl.type.size.mliter = lrint(cuft_to_l(rounded_size) * 1000 /
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);
}
/* whatever happens, make sure there is a name for the cylinder */
if (empty_string(cyl.type.description))
cyl.type.description = strdup(translate("gettextFromC", "unknown"));
if (cyl.type.description.empty())
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;
}

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 */
for (i = 0; i < 1; i++) {
cylinder_t cyl;
fill_default_cylinder(dive.get(), &cyl);
cylinder_t cyl = default_cylinder(dive.get());
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;
}
if (!strcmp(key, "description")) {
cylinder->type.description = strdup(value.c_str());
cylinder->type.description = value;
return;
}
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);
}
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)
@ -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)
{
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 "picture.h"
#include "qthelper.h"
#include "range.h"
#include "sample.h"
#include "tag.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());
*cyl_use = use;
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. */
cylinder_t cyl;
if (MATCH("tanktype", utf8_string, (char **)&cyl.type.description)) {
cylinder_t *cyl0 = get_or_create_cylinder(dive, 0);
free((void *)cyl0->type.description);
cyl0->type.description = cyl.type.description;
if (MATCH("tanktype", utf8_string_std, &cyl.type.description)) {
get_or_create_cylinder(dive, 0)->type.description = std::move(cyl.type.description);
return 1;
}
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 */
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 ?
&dive->weightsystems.weightsystems[dive->weightsystems.nr - 1] : NULL;
pressure_t p;
@ -1356,7 +1355,7 @@ static void try_to_fill_dive(struct dive *dive, const char *name, char *buf, str
return;
if (MATCH_STATE("workpressure.cylinder", pressure, &cyl->type.workingpressure))
return;
if (MATCH("description.cylinder", utf8_string, (char **)&cyl->type.description))
if (MATCH("description.cylinder", utf8_string_std, &cyl->type.description))
return;
if (MATCH_STATE("start.cylinder", pressure, &cyl->start))
return;
@ -1798,7 +1797,6 @@ int parse_dlf_buffer(unsigned char *buffer, size_t size, struct divelog *log)
unsigned char event;
bool found;
unsigned int time = 0;
int i;
char serial[6];
struct battery_status {
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.value = ptr[7] << 8 ^ ptr[6];
found = false;
for (i = 0; i < state.cur_dive->cylinders.nr; ++i) {
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) {
for (const auto [i, cyl]: enumerated_range(state.cur_dive->cylinders)) {
if (cyl.gasmix.o2.permille == ptr[6] * 10 && cyl.gasmix.he.permille == ptr[7] * 10) {
found = true;
state.cur_event.gas.index = i;
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.he.permille = ptr[7] * 10;
cylinder_end(&state);
state.cur_event.gas.index = state.cur_dive->cylinders.nr - 1;
} else {
state.cur_event.gas.index = i;
state.cur_event.gas.index = static_cast<int>(state.cur_dive->cylinders.size()) - 1;
}
break;
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)
{
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 "interpolate.h"
#include "planner.h"
#include "range.h"
#include "subsurface-time.h"
#include "gettext.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)
{
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)
@ -368,12 +369,12 @@ struct gaschanges {
static int setpoint_change(struct dive *dive, int cylinderid)
{
cylinder_t *cylinder = get_cylinder(dive, cylinderid);
if (!cylinder->type.description)
if (cylinder->type.description.empty())
return 0;
if (!strncmp(cylinder->type.description, "SP ", 3)) {
if (starts_with(cylinder->type.description, "SP ")) {
float sp;
sscanf(cylinder->type.description + 3, "%f", &sp);
return (int) (sp * 1000);
sscanf(cylinder->type.description.c_str() + 3, "%f", &sp);
return (int) (sp * 1000.0);
} else {
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)
{
cylinder_t *cyl;
if (current_cylinder < 0 || current_cylinder >= dive->cylinders.nr)
if (current_cylinder < 0 || static_cast<size_t>(current_cylinder) >= dive->cylinders.size())
return false;
cyl = get_cylinder(dive, current_cylinder);
const cylinder_t *cyl = get_cylinder(dive, current_cylinder);
if (!cyl->start.mbar)
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
// past the regular cylinder table, which is not visible to the UI.
// 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);
}
create_dive_from_plan(diveplan, dive, dc, is_planner);

View file

@ -16,6 +16,7 @@
#include "units.h"
#include "divelist.h"
#include "planner.h"
#include "range.h"
#include "gettext.h"
#include "libdivecomputer/parser.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 */
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;
const char *unit, *pressure_unit, *depth_unit;
std::string temp;
std::string warning;
std::string mingas;
cylinder_t *cyl = get_cylinder(dive, gasidx);
if (cyl->cylinder_use == NOT_USED)
if (cyl.cylinder_use == NOT_USED)
continue;
volume = get_volume_units(cyl->gas_used.mliter, NULL, &unit);
deco_volume = get_volume_units(cyl->deco_gas_used.mliter, NULL, &unit);
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));
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;
volume = get_volume_units(cyl.gas_used.mliter, NULL, &unit);
deco_volume = get_volume_units(cyl.deco_gas_used.mliter, NULL, &unit);
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));
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;
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
* 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 */
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",
translate("gettextFromC", "Warning:"),
translate("gettextFromC", "this is more gas than available in the specified cylinder!"));
else
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)
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)
warning = format_string_std("<br/>\n&nbsp;&mdash; <span style='color: red;'>%s </span> %s",
translate("gettextFromC", "Warning:"),
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;
mingasv.mliter = lrint(prefs.sacfactor / 100.0 * prefs.problemsolvingtime * prefs.bottomsac
* 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. */
lastbottomdp->minimum_gas.mbar = lrint(isothermal_pressure(cyl->gasmix, 1.0,
mingasv.mliter, cyl->type.size.mliter) * 1000);
lastbottomdp->minimum_gas.mbar = lrint(isothermal_pressure(cyl.gasmix, 1.0,
mingasv.mliter, cyl.type.size.mliter) * 1000);
/* Translate all results into correct units */
mingas_volume = get_volume_units(mingasv.mliter, NULL, &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);
/* 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): "
"%.0f%s/%.0f%s<span style='color: %s;'>/&Delta;:%+.0f%s</span>",
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. */
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)"),
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 {
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 {
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)"),
volume, unit, gasname(cyl->gasmix), deco_volume, unit);
volume, unit, gasname(cyl.gasmix), deco_volume, unit);
} else {
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 */

View file

@ -24,6 +24,7 @@
#include "libdivecomputer/version.h"
#include "membuffer.h"
#include "qthelper.h"
#include "range.h"
#include "format.h"
//#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()!");
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;
}
@ -259,12 +260,11 @@ static void calculate_max_limits_new(const struct dive *dive, const struct divec
int maxhr = 0, minhr = INT_MAX;
int mintemp = dive->mintemp.mkelvin;
int maxtemp = dive->maxtemp.mkelvin;
int cyl;
/* Get the per-cylinder maximum pressure if they are manual */
for (cyl = 0; cyl < dive->cylinders.nr; cyl++) {
int mbar_start = get_cylinder(dive, cyl)->start.mbar;
int mbar_end = get_cylinder(dive, cyl)->end.mbar;
for (auto &cyl: dive->cylinders) {
int mbar_start = cyl.start.mbar;
int mbar_end = cyl.end.mbar;
if (mbar_start > maxpressure)
maxpressure = mbar_start;
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)
{
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.
@ -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[])
{
int i, airuse;
double pressuretime;
if (first == last)
return 0;
/* Get airuse for the set of cylinders over the range */
airuse = 0;
for (i = 0; i < pi.nr_cylinders; i++) {
int airuse = 0;
for (int i = 0; i < pi.nr_cylinders; i++) {
pressure_t a, b;
cylinder_t *cyl;
int cyluse;
if (!gases[i])
continue;
a.mbar = get_plot_pressure(pi, first, i);
b.mbar = get_plot_pressure(pi, last, i);
cyl = get_cylinder(dive, i);
cyluse = gas_volume(cyl, a) - gas_volume(cyl, b);
const cylinder_t *cyl = get_cylinder(dive, i);
int cyluse = gas_volume(cyl, a) - gas_volume(cyl, b);
if (cyluse > 0)
airuse += cyluse;
}
@ -521,7 +516,7 @@ static int sac_between(const struct dive *dive, const struct plot_info &pi, int
return 0;
/* Calculate depthpressure integrated over time */
pressuretime = 0.0;
double pressuretime = 0.0;
do {
const struct plot_data &entry = pi.entry[first];
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[])
{
for (int i = 0; i < dive->cylinders.nr; i++)
gases[i] = same_gasmix(gasmix, get_cylinder(dive, i)->gasmix);
for (auto [i, cyl]: enumerated_range(dive->cylinders))
gases[i] = same_gasmix(gasmix, cyl.gasmix);
}
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]) {
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 });
}
@ -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_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 (cylinder_volume.mliter && cylinder_volume.mliter != cyl->type.size.mliter) {
cylindersizes_are_identical = false;

View file

@ -95,7 +95,7 @@ struct plot_info {
double maxpp = 0.0;
bool waypoint_above_ceiling = false;
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();

View file

@ -12,6 +12,7 @@
#include "version.h"
#include "errorhelper.h"
#include "planner.h"
#include "range.h"
#include "subsurface-time.h"
#include "gettextfromc.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()
{
int j;
QMap<QString, int> gasUsed;
for (dive *d: getDiveSelection()) {
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) {
QString gasName = gasname(get_cylinder(d, j)->gasmix);
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 list;
for (int i = 0; i < d->cylinders.nr; i++) {
const cylinder_t *cyl = get_cylinder(d, i);
for (auto [i, cyl]: enumerated_range(d->cylinders)) {
/* Check if we have the same gasmix two or more times
* If yes return more verbose string */
int same_gas = same_gasmix_cylinder(cyl, i, d, true);
if (same_gas == -1)
list.push_back(get_gas_string(cyl->gasmix));
list.push_back(get_gas_string(cyl.gasmix));
else
list.push_back(get_gas_string(cyl->gasmix) + QString(" (%1 %2 ").arg(gettextFromC::tr("cyl.")).arg(i + 1) +
cyl->type.description + ")");
list.push_back(get_gas_string(cyl.gasmix) + QStringLiteral(" (%1 %2 ").arg(gettextFromC::tr("cyl.")).arg(i + 1) +
QString::fromStdString(cyl.type.description) + ")");
}
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)
{
int i, nr;
nr = nr_cylinders(dive);
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;
for (auto &cyl: dive->cylinders) {
int volume = cyl.type.size.mliter;
int use = cyl.cylinder_use;
put_string(b, "cylinder");
if (volume)
put_milli(b, " vol=", volume, "l");
put_pressure(b, cylinder->type.workingpressure, " workpressure=", "bar");
show_utf8(b, " description=", description, "");
put_pressure(b, cyl.type.workingpressure, " workpressure=", "bar");
show_utf8(b, " description=", cyl.type.description.c_str(), "");
strip_mb(b);
put_gasmix(b, cylinder->gasmix);
put_pressure(b, cylinder->start, " start=", "bar");
put_pressure(b, cylinder->end, " end=", "bar");
put_gasmix(b, cyl.gasmix);
put_pressure(b, cyl.start, " start=", "bar");
put_pressure(b, cyl.end, " end=", "bar");
if (use > OC_GAS && use < NUM_GAS_USE)
show_utf8(b, " use=", cylinderuse_text[use], "");
if (cylinder->depth.mm != 0)
put_milli(b, " depth=", cylinder->depth.mm, "m");
if (cyl.depth.mm != 0)
put_milli(b, " depth=", cyl.depth.mm, "m");
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)
{
int i, nr;
const char *separator = "\"Cylinders\":[";
nr = nr_cylinders(dive);
if (!nr)
if (dive->cylinders.empty())
put_string(b, separator);
for (i = 0; i < nr; i++) {
cylinder_t *cylinder = get_cylinder(dive, i);
for (auto &cyl: dive->cylinders) {
put_format(b, "%s{", separator);
separator = ", ";
write_attribute(b, "Type", cylinder->type.description, ", ");
if (cylinder->type.size.mliter) {
int volume = cylinder->type.size.mliter;
if (prefs.units.volume == units::CUFT && cylinder->type.workingpressure.mbar)
volume = lrint(volume * bar_to_atm(cylinder->type.workingpressure.mbar / 1000.0));
write_attribute(b, "Type", cyl.type.description.c_str(), ", ");
if (cyl.type.size.mliter) {
int volume = cyl.type.size.mliter;
if (prefs.units.volume == units::CUFT && cyl.type.workingpressure.mbar)
volume = lrint(volume * bar_to_atm(cyl.type.workingpressure.mbar / 1000.0));
put_HTML_volume_units(b, volume, "\"Size\":\"", " \", ");
} else {
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) {
put_HTML_pressure_units(b, cylinder->start, "\"SPressure\":\"", " \", ");
if (cyl.start.mbar) {
put_HTML_pressure_units(b, cyl.start, "\"SPressure\":\"", " \", ");
} else {
write_attribute(b, "SPressure", "--", ", ");
}
if (cylinder->end.mbar) {
put_HTML_pressure_units(b, cylinder->end, "\"EPressure\":\"", " \", ");
if (cyl.end.mbar) {
put_HTML_pressure_units(b, cyl.end, "\"EPressure\":\"", " \", ");
} else {
write_attribute(b, "EPressure", "--", ", ");
}
if (cylinder->gasmix.o2.permille) {
put_format(b, "\"O2\":\"%u.%u%%\",", FRACTION_TUPLE(cylinder->gasmix.o2.permille, 10));
put_format(b, "\"He\":\"%u.%u%%\"", FRACTION_TUPLE(cylinder->gasmix.he.permille, 10));
if (cyl.gasmix.o2.permille) {
put_format(b, "\"O2\":\"%u.%u%%\",", FRACTION_TUPLE(cyl.gasmix.o2.permille, 10));
put_format(b, "\"He\":\"%u.%u%%\"", FRACTION_TUPLE(cyl.gasmix.he.permille, 10));
} else {
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)
{
int i, nr;
nr = nr_cylinders(dive);
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;
for (auto &cyl: dive->cylinders) {
int volume = cyl.type.size.mliter;
int use = cyl.cylinder_use;
put_format(b, " <cylinder");
if (volume)
put_milli(b, " size='", volume, " l'");
put_pressure(b, cylinder->type.workingpressure, " workpressure='", " bar'");
show_utf8(b, description, " description='", "'", 1);
put_gasmix(b, cylinder->gasmix);
put_pressure(b, cylinder->start, " start='", " bar'");
put_pressure(b, cylinder->end, " end='", " bar'");
put_pressure(b, cyl.type.workingpressure, " workpressure='", " bar'");
show_utf8(b, cyl.type.description.c_str(), " description='", "'", 1);
put_gasmix(b, cyl.gasmix);
put_pressure(b, cyl.start, " start='", " bar'");
put_pressure(b, cyl.end, " end='", " bar'");
if (use > OC_GAS && use < NUM_GAS_USE)
show_utf8(b, cylinderuse_text[use], " use='", "'", 1);
if (cylinder->depth.mm != 0)
put_milli(b, " depth='", cylinder->depth.mm, " m'");
if (cyl.depth.mm != 0)
put_milli(b, " depth='", cyl.depth.mm, " m'");
put_format(b, " />\n");
}
}

View file

@ -9,6 +9,7 @@
#include "divelog.h"
#include "event.h"
#include "gettext.h"
#include "range.h"
#include "sample.h"
#include "subsurface-time.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)
{
cylinder_t *cyl;
if (idx < 0 || idx >= dive->cylinders.nr)
if (idx < 0 || static_cast<size_t>(idx) >= dive->cylinders.size())
return false;
cyl = get_cylinder(dive, idx);
if ((cyl->start.mbar - cyl->end.mbar) > SOME_GAS)
const cylinder_t &cyl = dive->cylinders[idx];
if ((cyl.start.mbar - cyl.end.mbar) > SOME_GAS)
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;
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)
{
if (idx < 0 || idx >= dive->cylinders.nr)
if (idx < 0 || static_cast<size_t>(idx) >= dive->cylinders.size())
return false;
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); });
}
/* 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> gases(dive->cylinders.nr);
for (int idx = 0; idx < dive->cylinders.nr; idx++) {
cylinder_t *cyl = get_cylinder(dive, idx);
std::vector<volume_t> gases(dive->cylinders.size());
for (auto [idx, cyl]: enumerated_range(dive->cylinders)) {
pressure_t start, end;
start = cyl->start.mbar ? cyl->start : cyl->sample_start;
end = cyl->end.mbar ? cyl->end : cyl->sample_end;
start = cyl.start.mbar ? cyl.start : cyl.sample_start;
end = cyl.end.mbar ? cyl.end : cyl.sample_end;
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
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)
{
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 he = { (int)lrint(((double)vol.mliter * get_he(mix)) / 1000.0) };

View file

@ -4,6 +4,7 @@
#include "event.h"
#include "format.h"
#include "qthelper.h"
#include "range.h"
#include "subsurface-string.h"
#include "trip.h"
#include <QDateTime>
@ -13,23 +14,21 @@
enum returnPressureSelector { START_PRESSURE, END_PRESSURE };
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 (cyl->start.mbar)
fmt = get_pressure_string(cyl->start, true);
else if (cyl->sample_start.mbar)
fmt = get_pressure_string(cyl->sample_start, true);
if (cyl.start.mbar)
return get_pressure_string(cyl.start, true);
else if (cyl.sample_start.mbar)
return get_pressure_string(cyl.sample_start, true);
}
if (ret == END_PRESSURE) {
if (cyl->end.mbar)
fmt = get_pressure_string(cyl->end, true);
else if(cyl->sample_end.mbar)
fmt = get_pressure_string(cyl->sample_end, true);
if (cyl.end.mbar)
return get_pressure_string(cyl.end, true);
else if (cyl.sample_end.mbar)
return get_pressure_string(cyl.sample_end, true);
}
return fmt;
return QString();
}
QString formatSac(const dive *d)
@ -77,9 +76,9 @@ QString format_gps_decimal(const dive *d)
QStringList formatGetCylinder(const dive *d)
{
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))
getCylinder << get_cylinder(d, i)->type.description;
getCylinder << QString::fromStdString(cyl.type.description);
}
return getCylinder;
}
@ -87,9 +86,9 @@ QStringList formatGetCylinder(const dive *d)
QStringList formatStartPressure(const dive *d)
{
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))
startPressure << getPressures(d, i, START_PRESSURE);
startPressure << getPressures(cyl, START_PRESSURE);
}
return startPressure;
}
@ -97,9 +96,9 @@ QStringList formatStartPressure(const dive *d)
QStringList formatEndPressure(const dive *d)
{
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))
endPressure << getPressures(d, i, END_PRESSURE);
endPressure << getPressures(cyl, END_PRESSURE);
}
return endPressure;
}
@ -107,9 +106,9 @@ QStringList formatEndPressure(const dive *d)
QStringList formatFirstGas(const dive *d)
{
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))
gas << get_gas_string(get_cylinder(d, i)->gasmix);
gas << get_gas_string(cyl.gasmix);
}
return gas;
}
@ -133,20 +132,14 @@ static void addStringToSortedList(QStringList &l, const std::string &s)
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 cylinders;
struct dive *d;
int i = 0;
for_each_dive (i, d) {
for (int j = 0; j < d->cylinders.nr; j++)
addStringToSortedList(cylinders, c_to_std(get_cylinder(d, j)->type.description));
for (const cylinder_t &cyl: d->cylinders)
addStringToSortedList(cylinders, cyl.type.description);
}
for (const auto &ti: tank_info_table)
@ -155,25 +148,22 @@ QStringList formatFullCylinderList()
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 char *desc = cyl->type.description;
QString fmt = desc ? QString(desc) : gettextFromC::tr("unknown");
fmt += ", " + get_volume_string(cyl->type.size, true);
fmt += ", " + get_pressure_string(cyl->type.workingpressure, true);
fmt += ", " + get_pressure_string(cyl->start, false) + " - " + get_pressure_string(cyl->end, true);
fmt += ", " + get_gas_string(cyl->gasmix);
const std::string &desc = cyl.type.description;
QString fmt = !desc.empty() ? QString::fromStdString(desc) : gettextFromC::tr("unknown");
fmt += ", " + get_volume_string(cyl.type.size, true);
fmt += ", " + get_pressure_string(cyl.type.workingpressure, true);
fmt += ", " + get_pressure_string(cyl.start, false) + " - " + get_pressure_string(cyl.end, true);
fmt += ", " + get_gas_string(cyl.gasmix);
return fmt;
}
QStringList formatCylinders(const dive *d)
{
QStringList cylinders;
for (int i = 0; i < d->cylinders.nr; i++) {
QString cyl = formattedCylinder(d, i);
cylinders << cyl;
}
for (const cylinder_t &cyl: d->cylinders)
cylinders << formattedCylinder(cyl);
return cylinders;
}
@ -182,14 +172,14 @@ QString formatGas(const dive *d)
/*WARNING: here should be the gastlist, returned
* from the get_gas_string function or this is correct?
*/
QString gas, gases;
for (int i = 0; i < d->cylinders.nr; i++) {
QString gases;
for (auto [i, cyl]: enumerated_range(d->cylinders)) {
if (!is_cylinder_used(d, i))
continue;
gas = get_cylinder(d, i)->type.description;
QString gas = QString::fromStdString(cyl.type.description);
if (!gas.isEmpty())
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 (!gas.isEmpty() && gases.indexOf(gas) == -1) {
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);
while ((i <= data.size()) && (data[i] != 0 || data[i + 1] != 0)) {
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);
} else {
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
// cylinders of the edited dive.
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!
DivePlannerPointsModel::instance()->loadFromDive(editedDive.get(), dc);
}

View file

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

View file

@ -126,14 +126,14 @@ void TabDiveInformation::updateProfile()
std::vector<volume_t> gases = get_gas_used(currentDive);
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();
if (currentdc && currentDive->cylinders.nr >= 0)
if (currentdc && !currentDive->cylinders.empty())
per_cylinder_mean_depth(currentDive, currentdc, mean.data(), duration.data());
volume_t sac;
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))
continue;
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"),
" ", 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) {
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)
{
std::vector<const cylinder_t *> res;
res.reserve(d->cylinders.nr);
for (int i = 0; i < d->cylinders.nr; ++i)
res.push_back(&d->cylinders.cylinders[i]);
res.reserve(d->cylinders.size());
for (auto &cyl: d->cylinders)
res.push_back(&cyl);
return res;
}
@ -481,7 +481,7 @@ QVariant TemplateLayout::getValue(QString list, QString property, const State &s
return QVariant();
const cylinder_t *cylinder = *state.currentCylinderObject;
if (property == "description") {
return cylinder->type.description;
return QString::fromStdString(cylinder->type.description);
} else if (property == "size") {
return get_volume_string(cylinder->type.size, true);
} else if (property == "workingPressure") {

View file

@ -1295,7 +1295,7 @@ void QMLManager::commitChanges(QString diveId, QString number, QString date, QSt
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.workingpressure.mbar = wp;
k++;

View file

@ -602,7 +602,10 @@ void DiveGasPressureItem::replot(const dive *d, int fromIn, int toIn, bool in_pl
bool showDescriptions = false;
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())
continue;
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 label;
if (showDescription)
label = QStringLiteral("(%1) %2").arg(cylinder->type.description, gas);
label = QStringLiteral("(%1) %2").arg(QString::fromStdString(cylinder->type.description), gas);
else
label = gas;
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
/// Prints cylinder information for display.
/// 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);
if( cylinder != NULL ) {
QString mix = get_gas_string(cylinder->gasmix);
label += QString(" (%2 %3)").arg(cylinder->type.description).arg(mix);
}
QString mix = get_gas_string(cylinder.gasmix);
label += QString(" (%2 %3)").arg(QString::fromStdString(cylinder.type.description)).arg(mix);
return label;
}
@ -562,18 +560,16 @@ void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event)
if (d && item && item->ev.is_gaschange()) {
int eventTime = item->ev.time.seconds;
QMenu *gasChange = m.addMenu(tr("Edit Gas Change"));
for (int i = 0; i < d->cylinders.nr; i++) {
const cylinder_t *cylinder = get_cylinder(d, i);
QString label = printCylinderDescription(i, cylinder);
gasChange->addAction(label, [this, i, eventTime] { addGasSwitch(i, eventTime); });
for (auto [i, cyl]: enumerated_range(d->cylinders)) {
QString label = printCylinderDescription(i, cyl);
gasChange->addAction(label, [this, idx = i, eventTime] { addGasSwitch(idx, 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
QMenu *gasChange = m.addMenu(tr("Add gas change"));
for (int i = 0; i < d->cylinders.nr; i++) {
const cylinder_t *cylinder = get_cylinder(d, i);
QString label = printCylinderDescription(i, cylinder);
gasChange->addAction(label, [this, i, seconds] { addGasSwitch(i, seconds); });
for (auto [i, cyl]: enumerated_range(d->cylinders)) {
QString label = printCylinderDescription(i, cyl);
gasChange->addAction(label, [this, idx = i, seconds] { addGasSwitch(idx, 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)
{
if (!d || tank < 0 || tank >= d->cylinders.nr)
if (!d || tank < 0 || static_cast<size_t>(tank) >= d->cylinders.size())
return;
Command::addGasSwitch(mutable_dive(), dc, seconds, tank);
@ -923,7 +919,7 @@ void ProfileWidget2::repositionDiveHandlers()
QLineF line(p1, p2);
QPointF pos = line.pointAt(0.5);
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));
else
gases[i]->setText(QString());

View file

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

View file

@ -6,6 +6,7 @@
#include "core/color.h"
#include "qt-models/diveplannermodel.h"
#include "core/gettextfromc.h"
#include "core/range.h"
#include "core/sample.h"
#include "core/selection.h"
#include "core/subsurface-qt/divelistnotifier.h"
@ -140,7 +141,7 @@ int CylindersModel::calcNumRows() const
if (!d)
return 0;
if (inPlanner || prefs.include_unused_tanks)
return d->cylinders.nr;
return static_cast<int>(d->cylinders.size());
return first_hidden_cylinder(d);
}
@ -192,7 +193,7 @@ QVariant CylindersModel::data(const QModelIndex &index, int role) const
case Qt::EditRole:
switch (index.column()) {
case TYPE:
return QString(cyl->type.description);
return QString::fromStdString(cyl->type.description);
case SIZE:
if (cyl->type.size.mliter)
return get_cylinder_string(cyl);
@ -326,10 +327,9 @@ bool CylindersModel::setData(const QModelIndex &index, const QVariant &value, in
switch (index.column()) {
case TYPE: {
QString type = value.toString();
if (!same_string(qPrintable(type), tempCyl.type.description)) {
free((void *)tempCyl.type.description);
tempCyl.type.description = strdup(qPrintable(type));
std::string type = value.toString().toStdString();
if (type != tempCyl.type.description) {
tempCyl.type.description = type;
dataChanged(index, index);
}
return true;
@ -361,8 +361,6 @@ bool CylindersModel::setData(const QModelIndex &index, const QVariant &value, in
QString vString = value.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.
// 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.
@ -374,8 +372,7 @@ bool CylindersModel::setData(const QModelIndex &index, const QVariant &value, in
Command::EditCylinderType type = Command::EditCylinderType::TYPE;
switch (index.column()) {
case TYPE:
newType = qPrintable(vString);
cyl.type.description = newType.c_str();
cyl.type.description = vString.toStdString();
type = Command::EditCylinderType::TYPE;
break;
case SIZE:
@ -473,10 +470,7 @@ bool CylindersModel::setData(const QModelIndex &index, const QVariant &value, in
if (inPlanner) {
// 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.
cylinder_t copy = clone_cylinder(cyl);
std::swap(copy, *get_cylinder(d, row));
free_cylinder(copy);
*get_cylinder(d, row) = cyl;
dataChanged(index, index);
} else {
// On the EquipmentTab - place an editCylinder command.
@ -496,10 +490,10 @@ void CylindersModel::add()
{
if (!d)
return;
int row = d->cylinders.nr;
int row = static_cast<int>(d->cylinders.size());
cylinder_t cyl = create_new_manual_cylinder(d);
beginInsertRows(QModelIndex(), row, row);
add_cylinder(&d->cylinders, row, cyl);
add_cylinder(&d->cylinders, row, std::move(cyl));
++numRows;
endInsertRows();
emit dataChanged(createIndex(row, 0), createIndex(row, COLUMNS - 1));
@ -552,7 +546,7 @@ void CylindersModel::remove(QModelIndex index)
--numRows;
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());
DivePlannerPointsModel::instance()->cylinderRenumber(mapping.data());
}
@ -612,21 +606,18 @@ void CylindersModel::updateNumRows()
// Only invoked from planner.
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;
cylinder_t temp_cyl;
beginMoveRows(QModelIndex(), cylid, cylid, QModelIndex(), 0);
memmove(&temp_cyl, get_cylinder(d, cylid), sizeof(temp_cyl));
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));
move_in_range(d->cylinders, cylid, cylid + 1, 0);
// Create a mapping of cylinder indices:
// 1) Fill mapping[0]..mapping[cyl] with 0..index
// 2) Set mapping[cyl] to 0
// 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);
mapping[cylid] = 0;
std::iota(mapping.begin() + (cylid + 1), mapping.end(), cylid);
@ -644,12 +635,11 @@ void CylindersModel::updateDecoDepths(pressure_t olddecopo2)
pressure_t decopo2;
decopo2.mbar = prefs.decopo2;
for (int i = 0; i < d->cylinders.nr; i++) {
cylinder_t *cyl = get_cylinder(d, i);
for (auto &cyl: d->cylinders) {
/* 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 (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));
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));
}
}
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
bool gasUpdated = false;
for (int i = 0; i < d->cylinders.nr; i++) {
cylinder_t *cyl = get_cylinder(d, i);
if (cyl->bestmix_o2) {
cyl->gasmix.o2 = best_o2(d->maxdepth, d, inPlanner);
for (auto &cyl: d->cylinders) {
if (cyl.bestmix_o2) {
cyl.gasmix.o2 = best_o2(d->maxdepth, d, inPlanner);
// fO2 + fHe must not be greater than 1
if (get_o2(cyl->gasmix) + get_he(cyl->gasmix) > 1000)
cyl->gasmix.he.permille = 1000 - get_o2(cyl->gasmix);
if (get_o2(cyl.gasmix) + get_he(cyl.gasmix) > 1000)
cyl.gasmix.he.permille = 1000 - get_o2(cyl.gasmix);
pressure_t modpO2;
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;
}
if (cyl->bestmix_he) {
cyl->gasmix.he = best_he(d->maxdepth, d, prefs.o2narcotic, cyl->gasmix.o2);
if (cyl.bestmix_he) {
cyl.gasmix.he = best_he(d->maxdepth, d, prefs.o2narcotic, cyl.gasmix.o2);
// fO2 + fHe must not be greater than 1
if (get_o2(cyl->gasmix) + get_he(cyl->gasmix) > 1000)
cyl->gasmix.o2.permille = 1000 - get_he(cyl->gasmix);
if (get_o2(cyl.gasmix) + get_he(cyl.gasmix) > 1000)
cyl.gasmix.o2.permille = 1000 - get_he(cyl.gasmix);
gasUpdated = true;
}
}
@ -727,7 +716,7 @@ void CylindersModel::initTempCyl(int row)
return;
tempRow = row;
tempCyl = clone_cylinder(*cyl);
tempCyl = *cyl;
dataChanged(index(row, TYPE), index(row, USE));
}
@ -738,7 +727,7 @@ void CylindersModel::clearTempCyl()
return;
int oldRow = tempRow;
tempRow = -1;
free_cylinder(tempCyl);
tempCyl = cylinder_t();
dataChanged(index(oldRow, TYPE), index(oldRow, USE));
}
@ -752,7 +741,7 @@ void CylindersModel::commitTempCyl(int row)
if (!cyl)
return;
// 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) {
std::swap(*cyl, tempCyl);
} else {
@ -760,6 +749,6 @@ void CylindersModel::commitTempCyl(int row)
emit divesEdited(count);
}
}
free_cylinder(tempCyl);
tempCyl = cylinder_t();
tempRow = -1;
}

View file

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

View file

@ -151,12 +151,9 @@ static void calculateDive(struct dive *dive, Stats &stats)
}
// EAN dive ?
for (int j = 0; j < dive->cylinders.nr; ++j) {
if (get_cylinder(dive, j)->gasmix.o2.permille > 210) {
stats.divesEAN++;
break;
}
}
if (std::any_of(dive->cylinders.begin(), dive->cylinders.end(), [] (auto &cyl)
{ return cyl.gasmix.o2.permille > 210; }))
stats.divesEAN++;
}
// 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:
return QString(d->suit);
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:
return displaySac(d, prefs.units.show_units_table);
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
}
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
{
// We assume that i1.column() == i2.column().
@ -1750,9 +1755,9 @@ bool DiveTripModelList::lessThan(const QModelIndex &i1, const QModelIndex &i2) c
case SUIT:
return lessThanHelper(strCmp(d1->suit, d2->suit), row_diff);
case CYLINDER:
if (d1->cylinders.nr > 0 && d2->cylinders.nr > 0)
return lessThanHelper(strCmp(get_cylinder(d1, 0)->type.description, get_cylinder(d2, 0)->type.description), row_diff);
return d1->cylinders.nr - d2->cylinders.nr < 0;
if (!d1->cylinders.empty() && !d2->cylinders.empty())
return lessThanHelper(strCmp(d1->cylinders[0].type.description, d2->cylinders[0].type.description), row_diff);
return d1->cylinders.size() < d2->cylinders.size();
case GAS:
return lessThanHelper(nitrox_sort_value(d1) - nitrox_sort_value(d2), row_diff);
case SAC:
@ -1764,19 +1769,19 @@ bool DiveTripModelList::lessThan(const QModelIndex &i1, const QModelIndex &i2) c
case TAGS: {
std::string s1 = taglist_get_tagstring(d1->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);
}
case PHOTOS:
return lessThanHelper(countPhotos(d1) - countPhotos(d2), row_diff);
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:
return lessThanHelper(strCmp(d1->buddy, d2->buddy), row_diff);
case DIVEGUIDE:
return lessThanHelper(strCmp(d1->diveguide, d2->diveguide), row_diff);
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:
return lessThanHelper(strCmp(d1->notes, d2->notes), row_diff);
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++)
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.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))
return false;
// different names (none of them null)
if (!same_string(cyl_a->type.description, "---") &&
!same_string(cyl_b->type.description, "---") &&
!same_string(cyl_a->type.description, cyl_b->type.description))
if (cyl_a->type.description != "---" &&
cyl_b->type.description != "---" &&
cyl_a->type.description != cyl_b->type.description)
return false;
// Cylinders are most probably the same
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;
if (!dst->workingpressure.mbar)
dst->workingpressure.mbar = src->workingpressure.mbar;
if (!dst->description || same_string(dst->description, "---")) {
dst->description = src->description;
src->description = NULL;
if (dst->description.empty() || dst->description == "---") {
dst->description = std::move(src->description);
}
}
@ -532,7 +531,7 @@ static void smtk_clean_cylinders(struct dive *d)
cyl = base + tanks - 1;
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);
else
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> res;
res.reserve(d->cylinders.nr);
for (int i = 0; i < d->cylinders.nr; ++i) {
struct gasmix mix = d->cylinders.cylinders[i].gasmix;
res.reserve(d->cylinders.size());
for (auto &cyl: d->cylinders) {
struct gasmix mix = cyl.gasmix;
if (gasmix_is_invalid(mix))
continue;
// 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> res;
res.reserve(d->cylinders.nr);
for (int i = 0; i < d->cylinders.nr; ++i) {
struct gasmix mix = d->cylinders.cylinders[i].gasmix;
res.reserve(d->cylinders.size());
for (auto &cyl: d->cylinders) {
struct gasmix mix = cyl.gasmix;
if (gasmix_is_invalid(mix))
continue;
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 res;
std::vector<gasmix> mixes; // List multiple cylinders only once
mixes.reserve(d->cylinders.nr);
for (int i = 0; i < d->cylinders.nr; ++i) {
struct gasmix mix = d->cylinders.cylinders[i].gasmix;
mixes.reserve(d->cylinders.size());
for (auto &cyl: d->cylinders) {
struct gasmix mix = cyl.gasmix;
if (gasmix_is_invalid(mix))
continue;
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
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>();
// If sorting be He, the second sort criterion is O2 descending, because
// 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)); }
: [] (const cylinder_t &c1, const cylinder_t &c2)
{ 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);
}
@ -1798,9 +1798,9 @@ struct WeightsystemVariable : public StatsVariableTemplate<StatsVariable::Type::
static std::vector<QString> cylinder_types(const dive *d)
{
std::vector<QString> res;
res.reserve(d->cylinders.nr);
for (int i = 0; i < d->cylinders.nr; ++i)
add_to_vector_unique(res, QString(d->cylinders.cylinders[i].type.description).trimmed());
res.reserve(d->cylinders.size());
for (auto &cyl: d->cylinders)
add_to_vector_unique(res, QString::fromStdString(cyl.type.description).trimmed());
return res;
}