core: use C++ structures for tanksystem info

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2024-05-03 23:18:45 +02:00 committed by bstoeger
parent 1af00703b3
commit 3c1401785b
13 changed files with 93 additions and 123 deletions

View file

@ -1319,7 +1319,8 @@ EditCylinder::EditCylinder(int index, cylinder_t cylIn, EditCylinderType typeIn,
void EditCylinder::redo()
{
for (size_t i = 0; i < dives.size(); ++i) {
set_tank_info_data(&tank_info_table, cyl[i].type.description, cyl[i].type.size, cyl[i].type.workingpressure);
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]);
emit diveListNotifier.cylinderEdited(dives[i], indexes[i]);

View file

@ -130,14 +130,11 @@ static int dtrak_prepare_data(int model, device_data_t &dev_data)
* Just get the first in the user's list for given size.
* Reaching the end of the list means there is no tank of this size.
*/
static const char *cyl_type_by_size(int size)
static std::string cyl_type_by_size(int size)
{
for (int i = 0; i < tank_info_table.nr; ++i) {
const struct tank_info *ti = &tank_info_table.infos[i];
if (ti->ml == size)
return ti->name;
}
return "";
auto it = std::find_if(tank_info_table.begin(), tank_info_table.end(),
[size] (const tank_info &info) { return info.ml == size; });
return it != tank_info_table.end() ? it->name : std::string();
}
/*
@ -337,8 +334,9 @@ static char *dt_dive_parser(unsigned char *runner, struct dive *dt_dive, struct
read_bytes(2);
if (tmp_2bytes != 0x7FFF) {
cylinder_t cyl = empty_cylinder;
std::string desc = cyl_type_by_size(tmp_2bytes * 10);
cyl.type.size.mliter = tmp_2bytes * 10;
cyl.type.description = cyl_type_by_size(tmp_2bytes * 10);
cyl.type.description = desc.c_str();
cyl.start.mbar = 200000;
cyl.gasmix.he.permille = 0;
cyl.gasmix.o2.permille = 210;

View file

@ -1290,7 +1290,7 @@ extern "C" struct dive *fixup_dive(struct dive *dive)
fixup_airtemp(dive);
for (i = 0; i < dive->cylinders.nr; i++) {
cylinder_t *cyl = get_cylinder(dive, i);
add_cylinder_description(&cyl->type);
add_cylinder_description(cyl->type);
if (same_rounded_pressure(cyl->sample_start, cyl->start))
cyl->start.mbar = 0;
if (same_rounded_pressure(cyl->sample_end, cyl->end))

View file

@ -1285,7 +1285,7 @@ void clear_dive_file_data()
min_datafile_version = 0;
clear_git_id();
reset_tank_info_table(&tank_info_table);
reset_tank_info_table(tank_info_table);
/* Inform frontend of reset data. This should reset all the models. */
emit_reset_signal();

View file

@ -52,11 +52,6 @@ extern "C" void copy_cylinders(const struct cylinder_table *s, struct cylinder_t
add_cloned_cylinder(d, s->cylinders[i]);
}
static void free_tank_info(struct tank_info info)
{
free((void *)info.name);
}
/* weightsystem table functions */
//static MAKE_GET_IDX(weightsystem_table, weightsystem_t, weightsystems)
static MAKE_GROW_TABLE(weightsystem_table, weightsystem_t, weightsystems)
@ -77,12 +72,6 @@ static MAKE_REMOVE_FROM(cylinder_table, cylinders)
//MAKE_REMOVE(cylinder_table, cylinder_t, cylinder)
MAKE_CLEAR_TABLE(cylinder_table, cylinders, cylinder)
/* tank_info table functions */
static MAKE_GROW_TABLE(tank_info_table, tank_info_t, infos)
static MAKE_ADD_TO(tank_info_table, tank_info_t, infos)
//static MAKE_REMOVE_FROM(tank_info_table, infos)
MAKE_CLEAR_TABLE(tank_info_table, infos, tank_info)
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")
};
@ -97,28 +86,24 @@ extern "C" enum cylinderuse cylinderuse_from_text(const char *text)
}
/* Add a metric or an imperial tank info structure. Copies the passed-in string. */
extern "C" void add_tank_info_metric(struct tank_info_table *table, const char *name, int ml, int bar)
static void add_tank_info_metric(std::vector<tank_info> &table, const std::string &name, int ml, int bar)
{
struct tank_info info = { strdup(name), .ml = ml, .bar = bar };
add_to_tank_info_table(table, table->nr, info);
table.push_back(tank_info{ name, .ml = ml, .bar = bar });
}
extern "C" void add_tank_info_imperial(struct tank_info_table *table, const char *name, int cuft, int psi)
static void add_tank_info_imperial(std::vector<tank_info> &table, const std::string &name, int cuft, int psi)
{
struct tank_info info = { strdup(name), .cuft = cuft, .psi = psi };
add_to_tank_info_table(table, table->nr, info);
table.push_back(tank_info{ name, .cuft = cuft, .psi = psi });
}
static struct tank_info *get_tank_info(struct tank_info_table *table, const char *name)
struct tank_info *get_tank_info(std::vector<tank_info> &table, const std::string &name)
{
for (int i = 0; i < table->nr; ++i) {
if (same_string(table->infos[i].name, name))
return &table->infos[i];
}
return NULL;
auto it = std::find_if(table.begin(), table.end(), [&name](const tank_info &info)
{ return info.name == name; });
return it != table.end() ? &*it : nullptr;
}
extern "C" void set_tank_info_data(struct tank_info_table *table, const char *name, volume_t size, pressure_t working_pressure)
void set_tank_info_data(std::vector<tank_info> &table, const std::string &name, volume_t size, pressure_t working_pressure)
{
struct tank_info *info = get_tank_info(table, name);
if (info) {
@ -135,38 +120,38 @@ extern "C" void set_tank_info_data(struct tank_info_table *table, const char *na
}
}
extern "C" void extract_tank_info(const struct tank_info *info, volume_t *size, pressure_t *working_pressure)
std::pair<volume_t, pressure_t> extract_tank_info(const struct tank_info &info)
{
working_pressure->mbar = info->bar != 0 ? info->bar * 1000 : psi_to_mbar(info->psi);
if (info->ml != 0)
size->mliter = info->ml;
else if (working_pressure->mbar != 0)
size->mliter = lrint(cuft_to_l(info->cuft) * 1000 / mbar_to_atm(working_pressure->mbar));
pressure_t working_pressure {
static_cast<int32_t>(info.bar != 0 ? info.bar * 1000 : psi_to_mbar(info.psi))
};
volume_t size { 0 };
if (info.ml != 0)
size.mliter = info.ml;
else if (working_pressure.mbar != 0)
size.mliter = lrint(cuft_to_l(info.cuft) * 1000 / mbar_to_atm(working_pressure.mbar));
return std::make_pair(size, working_pressure);
}
extern "C" bool get_tank_info_data(struct tank_info_table *table, const char *name, volume_t *size, pressure_t *working_pressure)
std::pair<volume_t, pressure_t> get_tank_info_data(const std::vector<tank_info> &table, const std::string &name)
{
struct tank_info *info = get_tank_info(table, name);
if (info) {
extract_tank_info(info, size, working_pressure);
return true;
}
return false;
// Here, we would need a const version of get_tank_info().
auto it = std::find_if(table.begin(), table.end(), [&name](const tank_info &info)
{ return info.name == name; });
return it != table.end() ? extract_tank_info(*it)
: std::make_pair(volume_t{0}, pressure_t{0});
}
/* placeholders for a few functions that we need to redesign for the Qt UI */
extern "C" void add_cylinder_description(const cylinder_type_t *type)
void add_cylinder_description(const cylinder_type_t &type)
{
const char *desc = type->description;
if (empty_string(desc))
std::string desc = type.description ? type.description : std::string();
if (desc.empty())
return;
for (int i = 0; i < tank_info_table.nr; i++) {
if (strcmp(tank_info_table.infos[i].name, desc) == 0)
return;
}
add_tank_info_metric(&tank_info_table, desc, type->size.mliter,
type->workingpressure.mbar / 1000);
if (std::any_of(tank_info_table.begin(), tank_info_table.end(),
[&type](const tank_info &info) { return info.name == type.description; }))
return;
add_tank_info_metric(tank_info_table, desc, type.size.mliter,
type.workingpressure.mbar / 1000);
}
void add_weightsystem_description(const weightsystem_t &weightsystem)
@ -289,7 +274,7 @@ extern "C" int find_best_gasmix_match(struct gasmix mix, const struct cylinder_t
* we should pick up any other names from the dive
* logs directly.
*/
static void add_default_tank_infos(struct tank_info_table *table)
static void add_default_tank_infos(std::vector<tank_info> &table)
{
/* Size-only metric cylinders */
add_tank_info_metric(table, "10.0", 10000, 0);
@ -341,10 +326,10 @@ static void add_default_tank_infos(struct tank_info_table *table)
add_tank_info_metric(table, "D20 232 bar", 40000, 232);
}
struct tank_info_table tank_info_table;
extern "C" void reset_tank_info_table(struct tank_info_table *table)
std::vector<tank_info> tank_info_table;
void reset_tank_info_table(std::vector<tank_info> &table)
{
clear_tank_info_table(table);
table.clear();
if (prefs.display_default_tank_infos)
add_default_tank_infos(table);
@ -353,7 +338,7 @@ extern "C" void reset_tank_info_table(struct tank_info_table *table)
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);
add_cylinder_description(cyl->type);
}
}
}
@ -478,17 +463,16 @@ extern "C" void fill_default_cylinder(const struct dive *dive, cylinder_t *cyl)
if (!cyl_name)
return;
for (int i = 0; i < tank_info_table.nr; ++i) {
struct tank_info *ti = &tank_info_table.infos[i];
if (strcmp(ti->name, cyl_name) == 0) {
cyl->type.description = strdup(ti->name);
if (ti->ml) {
cyl->type.size.mliter = ti->ml;
cyl->type.workingpressure.mbar = ti->bar * 1000;
for (auto &ti: tank_info_table) {
if (ti.name == cyl_name) {
cyl->type.description = strdup(ti.name.c_str());
if (ti.ml) {
cyl->type.size.mliter = ti.ml;
cyl->type.workingpressure.mbar = ti.bar * 1000;
} else {
cyl->type.workingpressure.mbar = psi_to_mbar(ti->psi);
if (ti->psi)
cyl->type.size.mliter = lrint(cuft_to_l(ti->cuft) * 1000 / bar_to_atm(psi_to_bar(ti->psi)));
cyl->type.workingpressure.mbar = psi_to_mbar(ti.psi);
if (ti.psi)
cyl->type.size.mliter = lrint(cuft_to_l(ti.cuft) * 1000 / bar_to_atm(psi_to_bar(ti.psi)));
}
// MOD of air
cyl->depth = gas_mod(cyl->gasmix, pO2, dive, 1);

View file

@ -81,7 +81,6 @@ 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_or_create_cylinder(struct dive *d, int idx);
extern void add_cylinder_description(const cylinder_type_t *);
extern bool same_weightsystem(weightsystem_t w1, weightsystem_t w2);
extern void remove_cylinder(struct dive *dive, int idx);
extern void remove_weightsystem(struct dive *dive, int idx);
@ -108,25 +107,6 @@ extern void add_cylinder(struct cylinder_table *, int idx, cylinder_t cyl);
void get_gas_string(struct gasmix gasmix, char *text, int len);
const char *gasname(struct gasmix gasmix);
typedef struct tank_info {
const char *name;
int cuft, ml, psi, bar;
} tank_info_t;
struct tank_info_table {
int nr, allocated;
struct tank_info *infos;
};
extern struct tank_info_table tank_info_table;
extern void reset_tank_info_table(struct tank_info_table *table);
extern void clear_tank_info_table(struct tank_info_table *table);
extern void add_tank_info_metric(struct tank_info_table *table, const char *name, int ml, int bar);
extern void add_tank_info_imperial(struct tank_info_table *table, const char *name, int cuft, int psi);
extern void extract_tank_info(const struct tank_info *info, volume_t *size, pressure_t *working_pressure);
extern bool get_tank_info_data(struct tank_info_table *table, const char *name, volume_t *size, pressure_t *pressure);
extern void set_tank_info_data(struct tank_info_table *table, const char *name, volume_t size, pressure_t working_pressure);
#ifdef __cplusplus
}
@ -142,6 +122,19 @@ extern std::vector<ws_info> ws_info_table;
extern weight_t get_weightsystem_weight(const std::string &name); // returns 0 if not found
extern void add_weightsystem_description(const weightsystem_t &);
struct tank_info {
std::string name;
int cuft, ml, psi, bar;
};
extern std::vector<tank_info> tank_info_table;
extern struct tank_info *get_tank_info(std::vector<tank_info> &table, const std::string &name);
extern void set_tank_info_data(std::vector<tank_info> &table, const std::string &name, volume_t size, pressure_t working_pressure);
extern std::pair<volume_t, pressure_t> extract_tank_info(const struct tank_info &info);
extern std::pair<volume_t, pressure_t> get_tank_info_data(const std::vector<tank_info> &table, const std::string &name);
extern void add_cylinder_description(const cylinder_type_t &);
extern void reset_tank_info_table(std::vector<tank_info> &table);
#endif
#endif // EQUIPMENT_H

View file

@ -116,21 +116,21 @@ QStringList formatFirstGas(const dive *d)
// Add string to sorted QStringList, if it doesn't already exist and
// it isn't the empty string.
static void addStringToSortedList(QStringList &l, const char *s)
static void addStringToSortedList(QStringList &l, const std::string &s)
{
if (empty_string(s))
if (s.empty())
return;
// Do a binary search for the string. lower_bound() returns an iterator
// to either the searched-for element or the next higher element if it
// doesn't exist.
QString qs(s);
QString qs = QString::fromStdString(s);
auto it = std::lower_bound(l.begin(), l.end(), qs); // TODO: use locale-aware sorting
if (it != l.end() && *it == s)
if (it != l.end() && *it == qs)
return;
// Add new string at sorted position
l.insert(it, s);
l.insert(it, qs);
}
QStringList formatFullCylinderList()
@ -143,8 +143,8 @@ QStringList formatFullCylinderList()
addStringToSortedList(cylinders, get_cylinder(d, j)->type.description);
}
for (int ti = 0; ti < tank_info_table.nr; ti++)
addStringToSortedList(cylinders, tank_info_table.infos[ti].name);
for (const auto &ti: tank_info_table)
addStringToSortedList(cylinders, ti.name);
return cylinders;
}

View file

@ -219,9 +219,7 @@ void TankInfoDelegate::setModelData(QWidget *, QAbstractItemModel *model, const
return;
}
volume_t tankSize = {0};
pressure_t tankPressure = {0};
get_tank_info_data(&tank_info_table, qPrintable(cylinderName), &tankSize, &tankPressure);
auto [tankSize, tankPressure] = get_tank_info_data(tank_info_table, cylinderName.toStdString());
mymodel->setData(IDX(CylindersModel::TYPE), cylinderName, CylindersModel::TEMP_ROLE);
mymodel->setData(IDX(CylindersModel::WORKINGPRESS), tankPressure.mbar, CylindersModel::TEMP_ROLE);
mymodel->setData(IDX(CylindersModel::SIZE), tankSize.mliter, CylindersModel::TEMP_ROLE);

View file

@ -26,11 +26,12 @@ void PreferencesEquipment::refreshSettings()
ui->include_unused_tanks->setChecked(prefs.include_unused_tanks);
ui->display_default_tank_infos->setChecked(prefs.display_default_tank_infos);
ui->default_cylinder->clear();
for (int i = 0; i < tank_info_table.nr; i++) {
const tank_info &ti = tank_info_table.infos[i];
ui->default_cylinder->addItem(ti.name);
if (qPrefEquipment::default_cylinder() == ti.name)
int i = 0;
for (const tank_info &ti: tank_info_table) {
ui->default_cylinder->addItem(QString::fromStdString(ti.name));
if (qPrefEquipment::default_cylinder() == QString::fromStdString(ti.name))
ui->default_cylinder->setCurrentIndex(i);
++i;
}
}
@ -45,5 +46,5 @@ void PreferencesEquipment::syncSettings()
// reset the tank_info_table. It is somewhat questionable
// to do this here. Moreover, it is a bit crude, as this
// will be called for *any* preferences change.
reset_tank_info_table(&tank_info_table);
reset_tank_info_table(tank_info_table);
}

View file

@ -1283,9 +1283,8 @@ void QMLManager::commitChanges(QString diveId, QString number, QString date, QSt
if (state != "add" && !is_cylinder_used(d, j))
continue;
for (int i = 0; i < tank_info_table.nr; i++) {
const tank_info &ti = tank_info_table.infos[i];
if (ti.name == usedCylinder[k] ) {
for (const tank_info &ti: tank_info_table) {
if (ti.name == usedCylinder[k].toStdString()) {
if (ti.ml > 0){
size = ti.ml;
wp = ti.bar * 1000;

View file

@ -7,15 +7,13 @@
QVariant TankInfoModel::data(const QModelIndex &index, int role) const
{
if (index.row() < 0 || index.row() >= tank_info_table.nr)
if (index.row() < 0 || index.row() >= (int)tank_info_table.size())
return QVariant();
if (role == Qt::FontRole)
return defaultModelFont();
if (role == Qt::DisplayRole || role == Qt::EditRole) {
const struct tank_info &info = tank_info_table.infos[index.row()];
volume_t size = {0};
pressure_t pressure = {0};
extract_tank_info(&info, &size, &pressure);
const struct tank_info &info = tank_info_table[index.row()];
auto [size, pressure] = extract_tank_info(info);
switch (index.column()) {
case BAR:
@ -23,7 +21,7 @@ QVariant TankInfoModel::data(const QModelIndex &index, int role) const
case ML:
return size.mliter;
case DESCRIPTION:
return info.name;
return QString::fromStdString(info.name);
}
}
return QVariant();
@ -31,7 +29,7 @@ QVariant TankInfoModel::data(const QModelIndex &index, int role) const
int TankInfoModel::rowCount(const QModelIndex&) const
{
return tank_info_table.nr;
return (int)tank_info_table.size();
}
TankInfoModel::TankInfoModel(QObject *parent) : CleanerTableModel(parent)

View file

@ -79,7 +79,7 @@ int main(int argc, char **argv)
CheckCloudConnection ccc;
ccc.pickServer();
fill_computer_list();
reset_tank_info_table(&tank_info_table);
reset_tank_info_table(tank_info_table);
parse_xml_init();
taglist_init_global();
init_ui();
@ -114,7 +114,6 @@ int main(int argc, char **argv)
qPref::sync();
free_prefs();
clear_tank_info_table(&tank_info_table);
return 0;
}

View file

@ -61,7 +61,7 @@ int main(int argc, char **argv)
CheckCloudConnection ccc;
ccc.pickServer();
fill_computer_list();
reset_tank_info_table(&tank_info_table);
reset_tank_info_table(tank_info_table);
parse_xml_init();
taglist_init_global();
@ -101,7 +101,6 @@ int main(int argc, char **argv)
qPref::sync();
free_prefs();
clear_tank_info_table(&tank_info_table);
return 0;
}