core: turn C dive-table into an owning table

This is a humongous commit, because it touches all parts of the
code. It removes the last user of our horrible TABLE macros, which
simulate std::vector<> in a very clumsy way.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2024-06-07 10:25:09 +02:00 committed by bstoeger
parent f00c30ad4a
commit b95ac3f79c
73 changed files with 1030 additions and 1230 deletions

View file

@ -10,7 +10,7 @@ ColumnLimit: 0
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 8
ContinuationIndentWidth: 8
ForEachMacros: [ 'for_each_dive', 'for_each_line' ]
ForEachMacros: [ 'for_each_line' ]
IndentFunctionDeclarationAfterType: false #personal taste, good for long methods
IndentWidth: 8
MaxEmptyLinesToKeep: 2

View file

@ -217,6 +217,7 @@ HEADERS += \
core/picture.h \
core/planner.h \
core/divesite.h \
core/divesitetable.h \
core/checkcloudconnection.h \
core/cochran.h \
core/color.h \
@ -246,6 +247,8 @@ HEADERS += \
core/subsurfacestartup.h \
core/subsurfacesysinfo.h \
core/taxonomy.h \
core/trip.h \
core/triptable.h \
core/uemis.h \
core/webservice.h \
core/windowtitleupdate.h \

View file

@ -41,12 +41,12 @@ static constexpr int profileScale = 4;
static constexpr int profileWidth = 800 * profileScale;
static constexpr int profileHeight = 600 * profileScale;
static void exportProfile(ProfileScene *profile, const struct dive *dive, const QString &filename)
static void exportProfile(ProfileScene &profile, const struct dive &dive, const QString &filename)
{
QImage image = QImage(QSize(profileWidth, profileHeight), QImage::Format_RGB32);
QPainter paint;
paint.begin(&image);
profile->draw(&paint, QRect(0, 0, profileWidth, profileHeight), dive, 0, nullptr, false);
profile.draw(&paint, QRect(0, 0, profileWidth, profileHeight), &dive, 0, nullptr, false);
image.save(filename);
}
@ -57,17 +57,15 @@ static std::unique_ptr<ProfileScene> getPrintProfile()
void exportProfile(QString filename, bool selected_only, ExportCallback &cb)
{
struct dive *dive;
int i;
int count = 0;
if (!filename.endsWith(".png", Qt::CaseInsensitive))
filename = filename.append(".png");
QFileInfo fi(filename);
int todo = selected_only ? amount_selected : divelog.dives->nr;
int todo = selected_only ? amount_selected : static_cast<int>(divelog.dives.size());
int done = 0;
auto profile = getPrintProfile();
for_each_dive (i, dive) {
for (auto &dive: divelog.dives) {
if (cb.canceled())
return;
if (selected_only && !dive->selected)
@ -75,7 +73,7 @@ void exportProfile(QString filename, bool selected_only, ExportCallback &cb)
cb.setProgress(done++ * 1000 / todo);
QString fn = count ? fi.path() + QDir::separator() + fi.completeBaseName().append(QString("-%1.").arg(count)) + fi.suffix()
: filename;
exportProfile(profile.get(), dive, fn);
exportProfile(*profile, *dive, fn);
++count;
}
}
@ -84,11 +82,9 @@ void export_TeX(const char *filename, bool selected_only, bool plain, ExportCall
{
FILE *f;
QDir texdir = QFileInfo(filename).dir();
struct dive *dive;
const struct units *units = get_units();
const char *unit;
const char *ssrf;
int i;
bool need_pagebreak = false;
membuffer buf;
@ -133,16 +129,16 @@ void export_TeX(const char *filename, bool selected_only, bool plain, ExportCall
put_format(&buf, "\n%%%%%%%%%% Begin Dive Data: %%%%%%%%%%\n");
int todo = selected_only ? amount_selected : divelog.dives->nr;
int todo = selected_only ? amount_selected : static_cast<int>(divelog.dives.size());
int done = 0;
auto profile = getPrintProfile();
for_each_dive (i, dive) {
for (auto &dive: divelog.dives) {
if (cb.canceled())
return;
if (selected_only && !dive->selected)
continue;
cb.setProgress(done++ * 1000 / todo);
exportProfile(profile.get(), dive, texdir.filePath(QString("profile%1.png").arg(dive->number)));
exportProfile(*profile, *dive, texdir.filePath(QString("profile%1.png").arg(dive->number)));
struct tm tm;
utc_mkdate(dive->when, &tm);
@ -150,7 +146,7 @@ void export_TeX(const char *filename, bool selected_only, bool plain, ExportCall
dive_site *site = dive->dive_site;
if (site)
country = taxonomy_get_country(site->taxonomy);
pressure_t delta_p = {.mbar = 0};
pressure_t delta_p;
QString star = "*";
QString viz = star.repeated(dive->visibility);
@ -201,9 +197,8 @@ void export_TeX(const char *filename, bool selected_only, bool plain, ExportCall
// Print cylinder data
put_format(&buf, "\n%% Gas use information:\n");
int qty_cyl = 0;
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())){
for (auto [i, cyl]: enumerated_range(dive->cylinders)) {
if (is_cylinder_used(dive.get(), 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);
@ -270,13 +265,11 @@ void export_TeX(const char *filename, bool selected_only, bool plain, ExportCall
void export_depths(const char *filename, bool selected_only)
{
FILE *f;
struct dive *dive;
int i;
const char *unit = NULL;
membuffer buf;
for_each_dive (i, dive) {
for (auto &dive: divelog.dives) {
if (selected_only && !dive->selected)
continue;

View file

@ -66,7 +66,7 @@ QString diveNumberOrDate(struct dive *d)
QString getListOfDives(const std::vector<struct dive*> &dives)
{
QString listOfDives;
if ((int)dives.size() == divelog.dives->nr)
if (dives.size() == divelog.dives.size())
return Base::tr("all dives");
int i = 0;
for (dive *d: dives) {

View file

@ -44,13 +44,13 @@ DiveToAdd DiveListBase::removeDive(struct dive *d, std::vector<std::unique_ptr<d
tripsToAdd.push_back(std::move(trip)); // Take ownership of trip
}
int idx = get_divenr(d);
if (idx < 0)
size_t idx = divelog.dives.get_idx(d);
if (idx == std::string::npos)
qWarning("Deletion of unknown dive!");
DiveFilter::instance()->diveRemoved(d);
res.dive.reset(unregister_dive(idx)); // Remove dive from backend
res.dive = divelog.dives.unregister_dive(idx); // Remove dive from backend
return res;
}
@ -88,7 +88,7 @@ void processByTrip(std::vector<std::pair<dive_trip *, dive *>> &dives, Function
// Sort lexicographically by trip then according to the dive_less_than() function.
std::sort(dives.begin(), dives.end(),
[](const std::pair<dive_trip *, dive *> &e1, const std::pair<dive_trip *, dive *> &e2)
{ return e1.first == e2.first ? dive_less_than(e1.second, e2.second) : e1.first < e2.first; });
{ return e1.first == e2.first ? dive_less_than(*e1.second, *e2.second) : e1.first < e2.first; });
// Then, process the dives in batches by trip
size_t i, j; // Begin and end of batch
@ -124,7 +124,8 @@ DivesAndTripsToAdd DiveListBase::removeDives(DivesAndSitesToRemove &divesAndSite
// Make sure that the dive list is sorted. The added dives will be sent in a signal
// and the recipients assume that the dives are sorted the same way as they are
// in the core list.
std::sort(divesAndSitesToDelete.dives.begin(), divesAndSitesToDelete.dives.end(), dive_less_than);
std::sort(divesAndSitesToDelete.dives.begin(), divesAndSitesToDelete.dives.end(),
[](const dive *d1, const dive *d2) { return dive_less_than(*d1, *d2); });
for (dive *d: divesAndSitesToDelete.dives)
divesToAdd.push_back(removeDive(d, tripsToAdd));
@ -177,7 +178,7 @@ DivesAndSitesToRemove DiveListBase::addDives(DivesAndTripsToAdd &toAdd)
// in the core list.
std::sort(toAdd.dives.begin(), toAdd.dives.end(),
[](const DiveToAdd &d, const DiveToAdd &d2)
{ return dive_less_than(d.dive.get(), d2.dive.get()); });
{ return dive_less_than(*d.dive, *d2.dive); });
// Now, add the dives
// Note: the idiomatic STL-way would be std::transform, but let's use a loop since
@ -411,12 +412,12 @@ AddDive::AddDive(dive *d, bool autogroup, bool newNumber)
divePtr->divetrip = nullptr;
divePtr->dive_site = nullptr;
if (!trip && autogroup) {
auto [t, allocated] = get_trip_for_new_dive(divePtr.get());
auto [t, allocated] = get_trip_for_new_dive(divelog, divePtr.get());
trip = t;
allocTrip = std::move(allocated);
}
int idx = dive_table_get_insertion_index(divelog.dives.get(), divePtr.get());
int idx = divelog.dives.get_insertion_index(divePtr.get());
if (newNumber)
divePtr->number = get_dive_nr_at_idx(idx);
@ -455,18 +456,16 @@ void AddDive::undoit()
ImportDives::ImportDives(struct divelog *log, int flags, const QString &source)
{
setText(Command::Base::tr("import %n dive(s) from %1", "", log->dives->nr).arg(source));
setText(Command::Base::tr("import %n dive(s) from %1", "", log->dives.size()).arg(source));
// this only matters if undoit were called before redoit
currentDive = nullptr;
struct dive_table dives_to_add = empty_dive_table;
struct dive_table dives_to_remove = empty_dive_table;
struct trip_table trips_to_add;
dive_site_table sites_to_add;
process_imported_dives(log, flags,
&dives_to_add, &dives_to_remove, trips_to_add,
sites_to_add, devicesToAddAndRemove);
auto [dives_to_add, dives_to_remove, trips_to_add, sites_to_add, devices_to_add] =
process_imported_dives(*log, flags);
// Add devices to devicesToAddAndRemove structure
devicesToAddAndRemove = std::move(devices_to_add);
// Add trips to the divesToAdd.trips structure
divesToAdd.trips.reserve(trips_to_add.size());
@ -477,9 +476,8 @@ ImportDives::ImportDives(struct divelog *log, int flags, const QString &source)
divesToAdd.sites = std::move(sites_to_add);
// Add dives to the divesToAdd.dives structure
divesToAdd.dives.reserve(dives_to_add.nr);
for (int i = 0; i < dives_to_add.nr; ++i) {
std::unique_ptr<dive> divePtr(dives_to_add.dives[i]);
divesToAdd.dives.reserve(dives_to_add.size());
for (auto &divePtr: dives_to_add) {
divePtr->selected = false; // See above in AddDive::AddDive()
dive_trip *trip = divePtr->divetrip;
divePtr->divetrip = nullptr; // See above in AddDive::AddDive()
@ -490,9 +488,7 @@ ImportDives::ImportDives(struct divelog *log, int flags, const QString &source)
}
// Add dive to be deleted to the divesToRemove structure
divesAndSitesToRemove.dives.reserve(dives_to_remove.nr);
for (int i = 0; i < dives_to_remove.nr; ++i)
divesAndSitesToRemove.dives.push_back(dives_to_remove.dives[i]);
divesAndSitesToRemove.dives = std::move(dives_to_remove);
// When encountering filter presets with equal names, check whether they are
// the same. If they are, ignore them.
@ -504,9 +500,6 @@ ImportDives::ImportDives(struct divelog *log, int flags, const QString &source)
continue;
filterPresetsToAdd.emplace_back(preset.name, preset.data);
}
free(dives_to_add.dives);
free(dives_to_remove.dives);
}
bool ImportDives::workToBeDone()
@ -628,7 +621,7 @@ void ShiftTime::redoit()
}
// Changing times may have unsorted the dive and trip tables
sort_dive_table(divelog.dives.get());
divelog.dives.sort();
divelog.trips->sort();
for (dive_trip *trip: trips)
trip->sort_dives();
@ -735,11 +728,9 @@ RemoveAutogenTrips::RemoveAutogenTrips()
{
setText(Command::Base::tr("remove autogenerated trips"));
// TODO: don't touch core-innards directly
int i;
struct dive *dive;
for_each_dive(i, dive) {
if (dive->divetrip && dive->divetrip->autogen)
divesToMove.divesToMove.push_back( {dive, nullptr} );
for (auto &d: divelog.dives) {
if (d->divetrip && d->divetrip->autogen)
divesToMove.divesToMove.push_back( {d.get(), nullptr} );
}
}
@ -767,12 +758,12 @@ AutogroupDives::AutogroupDives()
{
setText(Command::Base::tr("autogroup dives"));
for (auto &entry: get_dives_to_autogroup(divelog.dives.get())) {
for (auto &entry: get_dives_to_autogroup(divelog.dives)) {
// If this is an allocated trip, take ownership
if (entry.created_trip)
divesToMove.tripsToAdd.push_back(std::move(entry.created_trip));
for (int i = entry.from; i < entry.to; ++i)
divesToMove.divesToMove.push_back( { divelog.dives->dives[i], entry.trip } );
for (auto it = divelog.dives.begin() + entry.from; it != divelog.dives.begin() + entry.to; ++it)
divesToMove.divesToMove.push_back( { it->get(), entry.trip } );
}
}
@ -960,9 +951,9 @@ MergeDives::MergeDives(const QVector <dive *> &dives)
// We will only renumber the remaining dives if the joined dives are consecutive.
// Otherwise all bets are off concerning what the user wanted and doing nothing seems
// like the best option.
int idx = get_divenr(dives[0]);
int num = dives.count();
if (idx < 0 || idx + num > divelog.dives->nr) {
size_t idx = divelog.dives.get_idx(dives[0]);
size_t num = dives.count();
if (idx == std::string::npos) {
// It was the callers responsibility to pass only known dives.
// Something is seriously wrong - give up.
qWarning("Merging unknown dives");
@ -970,7 +961,8 @@ MergeDives::MergeDives(const QVector <dive *> &dives)
}
// std::equal compares two ranges. The parameters are (begin_range1, end_range1, begin_range2).
// Here, we can compare C-arrays, because QVector guarantees contiguous storage.
if (std::equal(&dives[0], &dives[0] + num, &divelog.dives->dives[idx]) &&
if (std::equal(&dives[0], &dives[0] + num, divelog.dives.begin() + idx, [](dive *d1,
const std::unique_ptr<dive> &d2) { return d1 == d2.get(); }) &&
dives[0]->number && dives.last()->number && dives[0]->number < dives.last()->number) {
// We have a consecutive set of dives. Rename all following dives according to the
// number of erased dives. This considers that there might be missing numbers.
@ -986,15 +978,14 @@ MergeDives::MergeDives(const QVector <dive *> &dives)
// consecutive, and the difference will be 1, so the
// above example is not supposed to be normal.
int diff = dives.last()->number - dives[0]->number;
divesToRenumber.reserve(divelog.dives->nr - idx - num);
int previousnr = dives[0]->number;
for (int i = idx + num; i < divelog.dives->nr; ++i) {
int newnr = divelog.dives->dives[i]->number - diff;
for (size_t i = idx + num; i < divelog.dives.size(); ++i) {
int newnr = divelog.dives[i]->number - diff;
// Stop renumbering if stuff isn't in order (see also core/divelist.c)
if (newnr <= previousnr)
break;
divesToRenumber.append(QPair<dive *,int>(divelog.dives->dives[i], newnr));
divesToRenumber.append(QPair<dive *,int>(divelog.dives[i].get(), newnr));
previousnr = newnr;
}
}

View file

@ -62,11 +62,9 @@ static std::vector<dive *> getDives(bool currentDiveOnly)
: std::vector<dive *> { };
std::vector<dive *> res;
struct dive *d;
int i;
for_each_dive (i, d) {
for (auto &d: divelog.dives) {
if (d->selected)
res.push_back(d);
res.push_back(d.get());
}
return res;
}
@ -1443,7 +1441,7 @@ void EditDive::exchangeDives()
QVector<dive *> dives = { oldDive };
timestamp_t delta = oldDive->when - newDive->when;
if (delta != 0) {
sort_dive_table(divelog.dives.get());
divelog.dives.sort();
divelog.trips->sort();
if (newDive->divetrip != oldDive->divetrip)
qWarning("Command::EditDive::redo(): This command does not support moving between trips!");

View file

@ -74,6 +74,7 @@ set(SUBSURFACE_CORE_LIB_SRCS
divelogexportlogic.h
divesite.cpp
divesite.h
divesitetable.h
divesitehelpers.cpp
divesitehelpers.h
downloadfromdcthread.cpp
@ -179,6 +180,7 @@ set(SUBSURFACE_CORE_LIB_SRCS
time.cpp
trip.cpp
trip.h
triptable.h
uemis-downloader.cpp
uemis.cpp
uemis.h

View file

@ -601,7 +601,7 @@ static void cochran_parse_samples(struct dive *dive, const unsigned char *log,
static void cochran_parse_dive(const unsigned char *decode, unsigned mod,
const unsigned char *in, unsigned size,
struct dive_table *table)
struct dive_table &table)
{
unsigned char *buf = (unsigned char *)malloc(size);
struct divecomputer *dc;
@ -784,7 +784,7 @@ static void cochran_parse_dive(const unsigned char *decode, unsigned mod,
dc->duration.seconds = duration;
}
record_dive_to_table(dive.release(), table);
table.record_dive(std::move(dive));
free(buf);
}
@ -819,7 +819,7 @@ int try_to_open_cochran(const char *, std::string &mem, struct divelog *log)
break;
cochran_parse_dive(decode, mod, (unsigned char *)mem.data() + dive1,
dive2 - dive1, log->dives.get());
dive2 - dive1, log->dives);
}
return 1; // no further processing needed

View file

@ -698,12 +698,12 @@ int datatrak_import(std::string &mem, std::string &wl_mem, struct divelog *log)
rc = 1;
goto out;
} else {
record_dive_to_table(ptdive.release(), log->dives.get());
log->dives.record_dive(std::move(ptdive));
}
i++;
}
out:
sort_dive_table(log->dives.get());
log->dives.sort();
return rc;
bail:
return 1;

View file

@ -2376,10 +2376,10 @@ static void force_fixup_dive(struct dive *d)
*/
static std::array<std::unique_ptr<dive>, 2> split_dive_at(const struct dive &dive, int a, int b)
{
int nr = get_divenr(&dive);
size_t nr = divelog.dives.get_idx(&dive);
/* if we can't find the dive in the dive list, don't bother */
if (nr < 0)
if (nr == std::string::npos)
return {};
/* Splitting should leave at least 3 samples per dive */
@ -2461,7 +2461,7 @@ static std::array<std::unique_ptr<dive>, 2> split_dive_at(const struct dive &div
* Otherwise the tail is unnumbered.
*/
if (d2->number) {
if (divelog.dives->nr == nr + 1)
if (divelog.dives.size() == nr + 1)
d2->number++;
else
d2->number = 0;
@ -2893,9 +2893,9 @@ depth_t gas_mnd(struct gasmix mix, depth_t end, const struct dive *dive, int rou
struct dive *get_dive(int nr)
{
if (nr >= divelog.dives->nr || nr < 0)
return NULL;
return divelog.dives->dives[nr];
if (nr < 0 || static_cast<size_t>(nr) >= divelog.dives.size())
return nullptr;
return divelog.dives[nr].get();
}
struct dive_site *get_dive_site_for_dive(const struct dive *dive)
@ -2933,42 +2933,6 @@ const struct divecomputer *get_dive_dc(const struct dive *dive, int nr)
return get_dive_dc((struct dive *)dive, nr);
}
struct dive *get_dive_by_uniq_id(int id)
{
int i;
struct dive *dive = NULL;
for_each_dive (i, dive) {
if (dive->id == id)
break;
}
#ifdef DEBUG
if (dive == NULL) {
report_info("Invalid id %x passed to get_dive_by_diveid, try to fix the code", id);
exit(1);
}
#endif
return dive;
}
int get_idx_by_uniq_id(int id)
{
int i;
struct dive *dive = NULL;
for_each_dive (i, dive) {
if (dive->id == id)
break;
}
#ifdef DEBUG
if (dive == NULL) {
report_info("Invalid id %x passed to get_dive_by_diveid, try to fix the code", id);
exit(1);
}
#endif
return i;
}
bool dive_site_has_gps_location(const struct dive_site *ds)
{
return ds && has_location(&ds->location);

View file

@ -139,7 +139,6 @@ extern depth_t gas_mod(struct gasmix mix, pressure_t po2_limit, const struct div
extern depth_t gas_mnd(struct gasmix mix, depth_t end, const struct dive *dive, int roundto);
extern struct dive *get_dive(int nr);
extern struct dive *get_dive_from_table(int nr, const struct dive_table *dt);
extern struct dive_site *get_dive_site_for_dive(const struct dive *dive);
extern std::string get_dive_country(const struct dive *dive);
extern std::string get_dive_location(const struct dive *dive);
@ -153,18 +152,6 @@ extern std::unique_ptr<dive> clone_make_first_dc(const struct dive &d, int dc_nu
extern std::unique_ptr<dive> clone_delete_divecomputer(const struct dive &d, int dc_number);
extern std::array<std::unique_ptr<dive>, 2> split_divecomputer(const struct dive &src, int num);
/*
* Iterate over each dive, with the first parameter being the index
* iterator variable, and the second one being the dive one.
*
* I don't think anybody really wants the index, and we could make
* it local to the for-loop, but that would make us requires C99.
*/
#define for_each_dive(_i, _x) \
for ((_i) = 0; ((_x) = get_dive(_i)) != NULL; (_i)++)
extern struct dive *get_dive_by_uniq_id(int id);
extern int get_idx_by_uniq_id(int id);
extern bool dive_site_has_gps_location(const struct dive_site *ds);
extern int dive_has_gps_location(const struct dive *dive);
extern location_t dive_get_gps_location(const struct dive *d);
@ -173,19 +160,18 @@ extern bool time_during_dive_with_offset(const struct dive *dive, timestamp_t wh
extern int save_dives(const char *filename);
extern int save_dives_logic(const char *filename, bool select_only, bool anonymize);
extern int save_dive(FILE *f, struct dive *dive, bool anonymize);
extern int save_dive(FILE *f, const struct dive &dive, bool anonymize);
extern int export_dives_xslt(const char *filename, bool selected, const int units, const char *export_xslt, bool anonymize);
extern int save_dive_sites_logic(const char *filename, const struct dive_site *sites[], int nr_sites, bool anonymize);
struct membuffer;
extern void save_one_dive_to_mb(struct membuffer *b, struct dive *dive, bool anonymize);
extern void save_one_dive_to_mb(struct membuffer *b, const struct dive &dive, bool anonymize);
extern void subsurface_console_init();
extern void subsurface_console_exit();
extern bool subsurface_user_is_root();
extern void record_dive_to_table(struct dive *dive, struct dive_table *table);
extern void clear_dive(struct dive *dive);
extern void copy_dive(const struct dive *s, struct dive *d);
extern void selective_copy_dive(const struct dive *s, struct dive *d, struct dive_components what, bool clear);
@ -193,7 +179,8 @@ extern struct std::unique_ptr<dive> move_dive(struct dive *s);
extern int legacy_format_o2pressures(const struct dive *dive, const struct divecomputer *dc);
extern bool dive_less_than(const struct dive *a, const struct dive *b);
extern bool dive_less_than(const struct dive &a, const struct dive &b);
extern bool dive_less_than_ptr(const struct dive *a, const struct dive *b);
extern bool dive_or_trip_less_than(struct dive_or_trip a, struct dive_or_trip b);
extern struct dive *fixup_dive(struct dive *dive);
extern pressure_t calculate_surface_pressure(const struct dive *dive);

View file

@ -74,10 +74,8 @@ ShownChange DiveFilter::update(const QVector<dive *> &dives) const
void DiveFilter::reset()
{
int i;
dive *d;
shown_dives = divelog.dives->nr;
for_each_dive(i, d)
shown_dives = static_cast<int>(divelog.dives.size());
for (auto &d: divelog.dives)
d->hidden_by_filter = false;
updateAll();
}
@ -85,26 +83,24 @@ void DiveFilter::reset()
ShownChange DiveFilter::updateAll() const
{
ShownChange res;
int i;
dive *d;
std::vector<dive *> selection = getDiveSelection();
std::vector<dive *> removeFromSelection;
// There are three modes: divesite, fulltext, normal
if (diveSiteMode()) {
for_each_dive(i, d) {
for (auto &d: divelog.dives) {
bool newStatus = range_contains(dive_sites, d->dive_site);
updateDiveStatus(d, newStatus, res, removeFromSelection);
updateDiveStatus(d.get(), newStatus, res, removeFromSelection);
}
} else if (filterData.fullText.doit()) {
FullTextResult ft = fulltext_find_dives(filterData.fullText, filterData.fulltextStringMode);
for_each_dive(i, d) {
bool newStatus = ft.dive_matches(d) && showDive(d);
updateDiveStatus(d, newStatus, res, removeFromSelection);
for (auto &d: divelog.dives) {
bool newStatus = ft.dive_matches(d.get()) && showDive(d.get());
updateDiveStatus(d.get(), newStatus, res, removeFromSelection);
}
} else {
for_each_dive(i, d) {
bool newStatus = showDive(d);
updateDiveStatus(d, newStatus, res, removeFromSelection);
for (auto &d: divelog.dives) {
bool newStatus = showDive(d.get());
updateDiveStatus(d.get(), newStatus, res, removeFromSelection);
}
}
updateSelection(selection, std::vector<dive *>(), removeFromSelection);
@ -204,7 +200,7 @@ bool DiveFilter::diveSiteMode() const
QString DiveFilter::shownText() const
{
int num = divelog.dives->nr;
size_t num = divelog.dives.size();
if (diveSiteMode() || filterData.validFilter())
return gettextFromC::tr("%L1/%L2 shown").arg(shown_dives).arg(num);
else
@ -230,11 +226,9 @@ std::vector<dive *> DiveFilter::visibleDives() const
std::vector<dive *> res;
res.reserve(shown_dives);
int i;
dive *d;
for_each_dive(i, d) {
for (auto &d: divelog.dives) {
if (!d->hidden_by_filter)
res.push_back(d);
res.push_back(d.get());
}
return res;
}

View file

@ -20,9 +20,14 @@
#include "git-access.h"
#include "selection.h"
#include "sample.h"
#include "table.h"
#include "trip.h"
void dive_table::record_dive(std::unique_ptr<dive> d)
{
fixup_dive(d.get());
put(std::move(d));
}
/*
* Get "maximal" dive gas for a dive.
* Rules:
@ -201,7 +206,6 @@ static double calculate_cns_dive(const struct dive *dive)
* so we calculated it "by hand" */
static int calculate_cns(struct dive *dive)
{
int i, divenr;
double cns = 0.0;
timestamp_t last_starttime, last_endtime = 0;
@ -209,16 +213,18 @@ static int calculate_cns(struct dive *dive)
if (dive->cns)
return dive->cns;
divenr = get_divenr(dive);
i = divenr >= 0 ? divenr : divelog.dives->nr;
size_t divenr = divelog.dives.get_idx(dive);
int i = divenr != std::string::npos ? static_cast<int>(divenr)
: static_cast<int>(divelog.dives.size());
int nr_dives = static_cast<int>(divelog.dives.size());
#if DECO_CALC_DEBUG & 2
if (i >= 0 && i < dive_table.nr)
printf("\n\n*** CNS for dive #%d %d\n", i, get_dive(i)->number);
if (static_cast<size_t>(i) < divelog.table->size())
printf("\n\n*** CNS for dive #%d %d\n", i, (*divelog.table)[i]->number);
else
printf("\n\n*** CNS for dive #%d\n", i);
#endif
/* Look at next dive in dive list table and correct i when needed */
while (i < divelog.dives->nr - 1) {
while (i < nr_dives - 1) {
struct dive *pdive = get_dive(i);
if (!pdive || pdive->when > dive->when)
break;
@ -237,7 +243,7 @@ static int calculate_cns(struct dive *dive)
last_starttime = dive->when;
/* Walk backwards to check previous dives - how far do we need to go back? */
while (i--) {
if (i == divenr && i > 0)
if (static_cast<size_t>(i) == divenr && i > 0)
i--;
#if DECO_CALC_DEBUG & 2
printf("Check if dive #%d %d has to be considered as prev dive: ", i, get_dive(i)->number);
@ -263,7 +269,7 @@ static int calculate_cns(struct dive *dive)
#endif
}
/* Walk forward and add dives and surface intervals to CNS */
while (++i < divelog.dives->nr) {
while (++i < nr_dives) {
#if DECO_CALC_DEBUG & 2
printf("Check if dive #%d %d will be really added to CNS calc: ", i, get_dive(i)->number);
#endif
@ -283,7 +289,7 @@ static int calculate_cns(struct dive *dive)
break;
}
/* Don't add the copy of the dive itself */
if (i == divenr) {
if (static_cast<size_t>(i) == divenr) {
#if DECO_CALC_DEBUG & 2
printf("No - copy of dive\n");
#endif
@ -406,20 +412,6 @@ static void add_dive_to_deco(struct deco_state *ds, struct dive *dive, bool in_p
}
}
int get_divenr(const struct dive *dive)
{
int i;
const struct dive *d;
// tempting as it may be, don't die when called with dive=NULL
if (dive) {
for_each_dive(i, d) {
if (d->id == dive->id) // don't compare pointers, we could be passing in a copy of the dive
return i;
}
}
return -1;
}
/* take into account previous dives until there is a 48h gap between dives */
/* return last surface time before this dive or dummy value of 48h */
/* return negative surface time if dives are overlapping */
@ -427,7 +419,6 @@ int get_divenr(const struct dive *dive)
* to create the deco_state */
int init_decompression(struct deco_state *ds, const struct dive *dive, bool in_planner)
{
int i, divenr = -1;
int surface_time = 48 * 60 * 60;
timestamp_t last_endtime = 0, last_starttime = 0;
bool deco_init = false;
@ -436,16 +427,18 @@ int init_decompression(struct deco_state *ds, const struct dive *dive, bool in_p
if (!dive)
return false;
divenr = get_divenr(dive);
i = divenr >= 0 ? divenr : divelog.dives->nr;
int nr_dives = static_cast<int>(divelog.dives.size());
size_t divenr = divelog.dives.get_idx(dive);
int i = divenr != std::string::npos ? static_cast<int>(divenr)
: static_cast<int>(divelog.dives.size());
#if DECO_CALC_DEBUG & 2
if (i >= 0 && i < dive_table.nr)
if (i < dive_table.nr)
printf("\n\n*** Init deco for dive #%d %d\n", i, get_dive(i)->number);
else
printf("\n\n*** Init deco for dive #%d\n", i);
#endif
/* Look at next dive in dive list table and correct i when needed */
while (i < divelog.dives->nr - 1) {
while (i + 1 < nr_dives) {
struct dive *pdive = get_dive(i);
if (!pdive || pdive->when > dive->when)
break;
@ -464,7 +457,7 @@ int init_decompression(struct deco_state *ds, const struct dive *dive, bool in_p
last_starttime = dive->when;
/* Walk backwards to check previous dives - how far do we need to go back? */
while (i--) {
if (i == divenr && i > 0)
if (static_cast<size_t>(i) == divenr && i > 0)
i--;
#if DECO_CALC_DEBUG & 2
printf("Check if dive #%d %d has to be considered as prev dive: ", i, get_dive(i)->number);
@ -490,7 +483,7 @@ int init_decompression(struct deco_state *ds, const struct dive *dive, bool in_p
#endif
}
/* Walk forward an add dives and surface intervals to deco */
while (++i < divelog.dives->nr) {
while (++i < nr_dives) {
#if DECO_CALC_DEBUG & 2
printf("Check if dive #%d %d will be really added to deco calc: ", i, get_dive(i)->number);
#endif
@ -510,7 +503,7 @@ int init_decompression(struct deco_state *ds, const struct dive *dive, bool in_p
break;
}
/* Don't add the copy of the dive itself */
if (i == divenr) {
if (static_cast<size_t>(i) == divenr) {
#if DECO_CALC_DEBUG & 2
printf("No - copy of dive\n");
#endif
@ -635,71 +628,55 @@ static int comp_dc(const struct dive *d1, const struct dive *d2)
* We might also consider sorting by end-time and other criteria,
* but see the caveat above (editing means reordering of the dives).
*/
int comp_dives(const struct dive *a, const struct dive *b)
int comp_dives(const struct dive &a, const struct dive &b)
{
int cmp;
if (a == b)
if (&a == &b)
return 0; /* reflexivity */
if (a->when < b->when)
if (a.when < b.when)
return -1;
if (a->when > b->when)
if (a.when > b.when)
return 1;
if (a->divetrip != b->divetrip) {
if (!b->divetrip)
if (a.divetrip != b.divetrip) {
if (!b.divetrip)
return -1;
if (!a->divetrip)
if (!a.divetrip)
return 1;
if (trip_date(*a->divetrip) < trip_date(*b->divetrip))
if (trip_date(*a.divetrip) < trip_date(*b.divetrip))
return -1;
if (trip_date(*a->divetrip) > trip_date(*b->divetrip))
if (trip_date(*a.divetrip) > trip_date(*b.divetrip))
return 1;
}
if (a->number < b->number)
if (a.number < b.number)
return -1;
if (a->number > b->number)
if (a.number > b.number)
return 1;
if ((cmp = comp_dc(a, b)) != 0)
if ((cmp = comp_dc(&a, &b)) != 0)
return cmp;
if (a->id < b->id)
if (a.id < b.id)
return -1;
if (a->id > b->id)
if (a.id > b.id)
return 1;
return a < b ? -1 : 1; /* give up. */
return &a < &b ? -1 : 1; /* give up. */
}
/* Dive table functions */
static void free_dive(dive *d)
int comp_dives_ptr(const struct dive *a, const struct dive *b)
{
delete d;
}
static MAKE_GROW_TABLE(dive_table, struct dive *, dives)
MAKE_GET_INSERTION_INDEX(dive_table, struct dive *, dives, dive_less_than)
MAKE_ADD_TO(dive_table, struct dive *, dives)
static MAKE_REMOVE_FROM(dive_table, dives)
static MAKE_GET_IDX(dive_table, struct dive *, dives)
MAKE_SORT(dive_table, struct dive *, dives, comp_dives)
MAKE_REMOVE(dive_table, struct dive *, dive)
MAKE_CLEAR_TABLE(dive_table, dives, dive)
MAKE_MOVE_TABLE(dive_table, dives)
void insert_dive(struct dive_table *table, struct dive *d)
{
int idx = dive_table_get_insertion_index(table, d);
add_to_dive_table(table, idx, d);
return comp_dives(*a, *b);
}
/*
* Walk the dives from the oldest dive in the given table, and see if we
* can autogroup them. But only do this when the user selected autogrouping.
*/
static void autogroup_dives(struct dive_table *table, struct trip_table &trip_table)
static void autogroup_dives(struct dive_table &table, struct trip_table &trip_table)
{
if (!divelog.autogroup)
return;
for (auto &entry: get_dives_to_autogroup(table)) {
for (int i = entry.from; i < entry.to; ++i)
add_dive_to_trip(table->dives[i], entry.trip);
for (auto it = table.begin() + entry.from; it != table.begin() + entry.to; ++it)
add_dive_to_trip(it->get(), entry.trip);
/* If this was newly allocated, add trip to list */
if (entry.created_trip)
trip_table.put(std::move(entry.created_trip));
@ -710,35 +687,20 @@ static void autogroup_dives(struct dive_table *table, struct trip_table &trip_ta
#endif
}
/* Remove a dive from a dive table. This assumes that the
* dive was already removed from any trip and deselected.
* It simply shrinks the table and frees the trip */
void delete_dive_from_table(struct dive_table *table, int idx)
{
delete table->dives[idx];
remove_from_dive_table(table, idx);
}
struct dive *get_dive_from_table(int nr, const struct dive_table *dt)
{
if (nr >= dt->nr || nr < 0)
return NULL;
return dt->dives[nr];
}
/* This removes a dive from the global dive table but doesn't free the
* resources associated with the dive. The caller must removed the dive
* from the trip-list. Returns a pointer to the unregistered dive.
* The unregistered dive has the selection- and hidden-flags cleared. */
struct dive *unregister_dive(int idx)
std::unique_ptr<dive> dive_table::unregister_dive(int idx)
{
struct dive *dive = get_dive(idx);
if (!dive)
return NULL; /* this should never happen */
if (idx < 0 || static_cast<size_t>(idx) >= size())
return {}; /* this should never happen */
auto dive = pull_at(idx);
/* When removing a dive from the global dive table,
* we also have to unregister its fulltext cache. */
fulltext_unregister(dive);
remove_from_dive_table(divelog.dives.get(), idx);
fulltext_unregister(dive.get());
if (dive->selected)
amount_selected--;
dive->selected = false;
@ -755,21 +717,20 @@ struct dive *register_dive(std::unique_ptr<dive> d)
// dives have been added, their status will be updated.
d->hidden_by_filter = true;
int idx = dive_table_get_insertion_index(divelog.dives.get(), d.get());
fulltext_register(d.get()); // Register the dive's fulltext cache
invalidate_dive_cache(d.get()); // Ensure that dive is written in git_save()
add_to_dive_table(divelog.dives.get(), idx, d.get());
auto [res, idx] = divelog.dives.put(std::move(d));
return d.release();
return res;
}
void process_loaded_dives()
{
sort_dive_table(divelog.dives.get());
divelog.dives.sort();
divelog.trips->sort();
/* Autogroup dives if desired by user. */
autogroup_dives(divelog.dives.get(), *divelog.trips);
autogroup_dives(divelog.dives, *divelog.trips);
fulltext_populate();
@ -785,13 +746,11 @@ void process_loaded_dives()
* that the dives are neither selected, not part of a trip, as
* is the case of freshly imported dives.
*/
static void merge_imported_dives(struct dive_table *table)
static void merge_imported_dives(struct dive_table &table)
{
int i;
for (i = 1; i < table->nr; i++) {
struct dive *prev = table->dives[i - 1];
struct dive *dive = table->dives[i];
struct dive_site *ds;
for (size_t i = 1; i < table.size(); i++) {
auto &prev = table[i - 1];
auto &dive = table[i];
/* only try to merge overlapping dives - or if one of the dives has
* zero duration (that might be a gps marker from the webservice) */
@ -804,20 +763,19 @@ static void merge_imported_dives(struct dive_table *table)
continue;
/* Add dive to dive site; try_to_merge() does not do that! */
ds = merged->dive_site;
struct dive_site *ds = merged->dive_site;
if (ds) {
merged->dive_site = NULL;
ds->add_dive(merged.get());
}
unregister_dive_from_dive_site(prev);
unregister_dive_from_dive_site(dive);
unregister_dive_from_trip(prev);
unregister_dive_from_trip(dive);
unregister_dive_from_dive_site(prev.get());
unregister_dive_from_dive_site(dive.get());
unregister_dive_from_trip(prev.get());
unregister_dive_from_trip(dive.get());
/* Overwrite the first of the two dives and remove the second */
delete prev;
table->dives[i - 1] = merged.release();
delete_dive_from_table(table, i);
table[i - 1] = std::move(merged);
table.erase(table.begin() + i);
/* Redo the new 'i'th dive */
i--;
@ -831,45 +789,46 @@ static void merge_imported_dives(struct dive_table *table)
* table. On failure everything stays unchanged.
* If "prefer_imported" is true, use data of the new dive.
*/
static bool try_to_merge_into(struct dive &dive_to_add, struct dive &old_dive, bool prefer_imported,
static bool try_to_merge_into(struct dive &dive_to_add, struct dive *old_dive, bool prefer_imported,
/* output parameters: */
struct dive_table *dives_to_add, struct dive_table *dives_to_remove)
struct dive_table &dives_to_add, struct std::vector<dive *> &dives_to_remove)
{
auto merged = try_to_merge(old_dive, dive_to_add, prefer_imported);
auto merged = try_to_merge(*old_dive, dive_to_add, prefer_imported);
if (!merged)
return false;
merged->divetrip = old_dive.divetrip;
insert_dive(dives_to_remove, &old_dive);
insert_dive(dives_to_add, merged.release());
merged->divetrip = old_dive->divetrip;
range_insert_sorted(dives_to_remove, old_dive, comp_dives_ptr);
dives_to_add.put(std::move(merged));
return true;
}
/* Check if a dive is ranked after the last dive of the global dive list */
static bool dive_is_after_last(struct dive *d)
static bool dive_is_after_last(const struct dive &d)
{
if (divelog.dives->nr == 0)
if (divelog.dives.empty())
return true;
return dive_less_than(divelog.dives->dives[divelog.dives->nr - 1], d);
return dive_less_than(*divelog.dives.back(), d);
}
/* Merge dives from "dives_from" into "dives_to". Overlapping dives will be merged,
* non-overlapping dives will be moved. The results will be added to the "dives_to_add"
* table. Dives that were merged are added to the "dives_to_remove" table.
* Any newly added (not merged) dive will be assigned to the trip of the "trip"
* paremeter. If "delete_from" is non-null dives will be removed from this table.
/* Merge dives from "dives_from", owned by "delete" into the owned by "dives_to".
* Overlapping dives will be merged, non-overlapping dives will be moved. The results
* will be added to the "dives_to_add" table. Dives that were merged are added to
* the "dives_to_remove" table. Any newly added (not merged) dive will be assigned
* to the trip of the "trip" paremeter. If "delete_from" is non-null dives will be
* removed from this table.
* This function supposes that all input tables are sorted.
* Returns true if any dive was added (not merged) that is not past the
* last dive of the global dive list (i.e. the sequence will change).
* The integer pointed to by "num_merged" will be increased for every
* The integer referenced by "num_merged" will be increased for every
* merged dive that is added to "dives_to_add" */
static bool merge_dive_tables(const std::vector<dive *> &dives_from, struct dive_table *delete_from,
static bool merge_dive_tables(const std::vector<dive *> &dives_from, struct dive_table &delete_from,
const std::vector<dive *> &dives_to,
bool prefer_imported, struct dive_trip *trip,
/* output parameters: */
struct dive_table *dives_to_add, struct dive_table *dives_to_remove,
int *num_merged)
struct dive_table &dives_to_add, struct std::vector<dive *> &dives_to_remove,
int &num_merged)
{
bool sequence_changed = false;
@ -884,11 +843,18 @@ static bool merge_dive_tables(const std::vector<dive *> &dives_from, struct dive
*/
size_t j = 0; /* Index in dives_to */
size_t last_merged_into = std::string::npos;
for (auto dive_to_add: dives_from) {
remove_dive(dive_to_add, delete_from);
for (dive *add: dives_from) {
/* This gets an owning pointer to the dive to add and removes it from
* the delete_from table. If the dive is not explicitly stored, it will
* be automatically deleting when ending the loop iteration */
auto [dive_to_add, idx] = delete_from.pull(add);
if (!dive_to_add) {
report_info("merging unknown dives!");
continue;
}
/* Find insertion point. */
while (j < dives_to.size() && dive_less_than(dives_to[j], dive_to_add))
while (j < dives_to.size() && dive_less_than(*dives_to[j], *dive_to_add))
j++;
/* Try to merge into previous dive.
@ -899,11 +865,10 @@ static bool merge_dive_tables(const std::vector<dive *> &dives_from, struct dive
* transitive. But let's just go *completely* sure for the odd corner-case. */
if (j > 0 && (last_merged_into == std::string::npos || j > last_merged_into + 1) &&
dives_to[j - 1]->endtime() > dive_to_add->when) {
if (try_to_merge_into(*dive_to_add, *dives_to[j - 1], prefer_imported,
if (try_to_merge_into(*dive_to_add, dives_to[j - 1], prefer_imported,
dives_to_add, dives_to_remove)) {
delete dive_to_add;
last_merged_into = j - 1;
(*num_merged)++;
num_merged++;
continue;
}
}
@ -912,19 +877,16 @@ static bool merge_dive_tables(const std::vector<dive *> &dives_from, struct dive
* Try to merge into next dive. */
if (j < dives_to.size() && (last_merged_into == std::string::npos || j > last_merged_into) &&
dive_to_add->endtime() > dives_to[j]->when) {
if (try_to_merge_into(*dive_to_add, *dives_to[j], prefer_imported,
if (try_to_merge_into(*dive_to_add, dives_to[j], prefer_imported,
dives_to_add, dives_to_remove)) {
delete dive_to_add;
last_merged_into = j;
(*num_merged)++;
num_merged++;
continue;
}
}
/* We couldnt merge dives, simply add to list of dives to-be-added. */
insert_dive(dives_to_add, dive_to_add);
sequence_changed |= !dive_is_after_last(dive_to_add);
dive_to_add->divetrip = trip;
sequence_changed |= !dive_is_after_last(*dive_to_add);
dives_to_add.put(std::move(dive_to_add));
}
return sequence_changed;
@ -933,46 +895,34 @@ static bool merge_dive_tables(const std::vector<dive *> &dives_from, struct dive
/* Merge the dives of the trip "from" and the dive_table "dives_from" into the trip "to"
* and dive_table "dives_to". If "prefer_imported" is true, dive data of "from" takes
* precedence */
void add_imported_dives(struct divelog *import_log, int flags)
void add_imported_dives(struct divelog &import_log, int flags)
{
int i, idx;
struct dive_table dives_to_add = empty_dive_table;
struct dive_table dives_to_remove = empty_dive_table;
struct trip_table trips_to_add;
dive_site_table dive_sites_to_add;
device_table devices_to_add;
/* Process imported dives and generate lists of dives
* to-be-added and to-be-removed */
process_imported_dives(import_log, flags, &dives_to_add, &dives_to_remove, trips_to_add,
dive_sites_to_add, devices_to_add);
auto [dives_to_add, dives_to_remove, trips_to_add, dive_sites_to_add, devices_to_add] =
process_imported_dives(import_log, flags);
/* Start by deselecting all dives, so that we don't end up with an invalid selection */
select_single_dive(NULL);
/* Add new dives to trip and site to get reference count correct. */
for (i = 0; i < dives_to_add.nr; i++) {
struct dive *d = dives_to_add.dives[i];
for (auto &d: dives_to_add) {
struct dive_trip *trip = d->divetrip;
struct dive_site *site = d->dive_site;
d->divetrip = NULL;
d->dive_site = NULL;
add_dive_to_trip(d, trip);
add_dive_to_trip(d.get(), trip);
if (site)
site->add_dive(d);
site->add_dive(d.get());
}
/* Remove old dives */
for (i = 0; i < dives_to_remove.nr; i++) {
idx = get_divenr(dives_to_remove.dives[i]);
divelog.delete_single_dive(idx);
}
dives_to_remove.nr = 0;
divelog.delete_multiple_dives(dives_to_remove);
/* Add new dives */
for (i = 0; i < dives_to_add.nr; i++)
insert_dive(divelog.dives.get(), dives_to_add.dives[i]);
dives_to_add.nr = 0;
for (auto &d: dives_to_add)
divelog.dives.put(std::move(d));
dives_to_add.clear();
/* Add new trips */
for (auto &trip: trips_to_add)
@ -989,10 +939,7 @@ void add_imported_dives(struct divelog *import_log, int flags)
/* We might have deleted the old selected dive.
* Choose the newest dive as selected (if any) */
current_dive = divelog.dives->nr > 0 ? divelog.dives->dives[divelog.dives->nr - 1] : NULL;
free(dives_to_add.dives);
free(dives_to_remove.dives);
current_dive = !divelog.dives.empty() ? divelog.dives.back().get() : nullptr;
/* Inform frontend of reset data. This should reset all the models. */
emit_reset_signal();
@ -1008,14 +955,14 @@ void add_imported_dives(struct divelog *import_log, int flags)
* Returns true if trip was merged. In this case, the trip will be
* freed.
*/
static bool try_to_merge_trip(dive_trip &trip_import, struct dive_table *import_table, bool prefer_imported,
static bool try_to_merge_trip(dive_trip &trip_import, struct dive_table &import_table, bool prefer_imported,
/* output parameters: */
struct dive_table *dives_to_add, struct dive_table *dives_to_remove,
bool *sequence_changed, int *start_renumbering_at)
struct dive_table &dives_to_add, std::vector<dive *> &dives_to_remove,
bool &sequence_changed, int &start_renumbering_at)
{
for (auto &trip_old: *divelog.trips) {
if (trips_overlap(trip_import, *trip_old)) {
*sequence_changed |= merge_dive_tables(trip_import.dives, import_table, trip_old->dives,
sequence_changed |= merge_dive_tables(trip_import.dives, import_table, trip_old->dives,
prefer_imported, trip_old.get(),
dives_to_add, dives_to_remove,
start_renumbering_at);
@ -1033,27 +980,21 @@ static bool try_to_merge_trip(dive_trip &trip_import, struct dive_table *import_
static std::vector<dive *> dive_table_to_non_owning(const dive_table &dives)
{
std::vector<dive *> res;
res.reserve(dives.nr);
for (int i = 0; i < dives.nr; ++i)
res.push_back(dives.dives[i]);
res.reserve(dives.size());
for (auto &d: dives)
res.push_back(d.get());
return res;
}
/* Process imported dives: take a table of dives to be imported and
* generate five lists:
* 1) Dives to be added
* 2) Dives to be removed
* 3) Trips to be added
* 4) Dive sites to be added
* 5) Devices to be added
* The dives to be added are owning (i.e. the caller is responsible
* for freeing them).
* The dives, trips and sites in "import_table", "import_trip_table"
* and "import_sites_table" are consumed. On return, the tables have
* size 0. "import_trip_table" may be NULL if all dives are not associated
* with a trip.
* The output tables should be empty - if not, their content
* will be cleared!
* 1) Dives to be added (newly created, owned)
* 2) Dives to be removed (old, non-owned, references global divelog)
* 3) Trips to be added (newly created, owned)
* 4) Dive sites to be added (newly created, owned)
* 5) Devices to be added (newly created, owned)
* The dives, trips and sites in import_log are consumed.
* On return, the tables have * size 0.
*
* Note: The new dives will have their divetrip- and divesites-fields
* set, but will *not* be part of the trip and site. The caller has to
@ -1072,90 +1013,70 @@ static std::vector<dive *> dive_table_to_non_owning(const dive_table &dives)
* - If IMPORT_ADD_TO_NEW_TRIP is true, dives that are not assigned
* to a trip will be added to a newly generated trip.
*/
void process_imported_dives(struct divelog *import_log, int flags,
/* output parameters: */
struct dive_table *dives_to_add, struct dive_table *dives_to_remove,
struct trip_table &trips_to_add, dive_site_table &sites_to_add,
device_table &devices_to_add)
process_imported_dives_result process_imported_dives(struct divelog &import_log, int flags)
{
int i, j, nr, start_renumbering_at = 0;
int start_renumbering_at = 0;
bool sequence_changed = false;
bool new_dive_has_number = false;
bool last_old_dive_is_numbered;
/* Make sure that output parameters don't contain garbage */
clear_dive_table(dives_to_add);
clear_dive_table(dives_to_remove);
trips_to_add.clear();
sites_to_add.clear();
devices_to_add.clear();
process_imported_dives_result res;
/* If no dives were imported, don't bother doing anything */
if (import_log.dives.empty())
return res;
/* Check if any of the new dives has a number. This will be
* important later to decide if we want to renumber the added
* dives */
for (int i = 0; i < import_log->dives->nr; i++) {
if (import_log->dives->dives[i]->number > 0) {
new_dive_has_number = true;
break;
}
}
/* If no dives were imported, don't bother doing anything */
if (!import_log->dives->nr)
return;
bool new_dive_has_number = std::any_of(import_log.dives.begin(), import_log.dives.end(),
[](auto &d) { return d->number > 0; });
/* Add only the devices that we don't know about yet. */
for (auto &dev: import_log->devices) {
for (auto &dev: import_log.devices) {
if (!device_exists(divelog.devices, dev))
add_to_device_table(devices_to_add, dev);
add_to_device_table(res.devices_to_add, dev);
}
/* Sort the table of dives to be imported and combine mergable dives */
sort_dive_table(import_log->dives.get());
merge_imported_dives(import_log->dives.get());
import_log.dives.sort();
merge_imported_dives(import_log.dives);
/* Autogroup tripless dives if desired by user. But don't autogroup
* if tripless dives should be added to a new trip. */
if (!(flags & IMPORT_ADD_TO_NEW_TRIP))
autogroup_dives(import_log->dives.get(), *import_log->trips);
autogroup_dives(import_log.dives, *import_log.trips);
/* If dive sites already exist, use the existing versions. */
for (auto &new_ds: *import_log->sites) {
struct dive_site *old_ds = divelog.sites->get_same(*new_ds);
for (auto &new_ds: *import_log.sites) {
/* Check if it dive site is actually used by new dives. */
for (j = 0; j < import_log->dives->nr; j++) {
if (import_log->dives->dives[j]->dive_site == new_ds.get())
break;
}
if (j == import_log->dives->nr) {
/* Dive site not even used. */
if (std::none_of(import_log.dives.begin(), import_log.dives.end(), [ds=new_ds.get()]
(auto &d) { return d->dive_site == ds; }))
continue;
}
struct dive_site *old_ds = divelog.sites->get_same(*new_ds);
if (!old_ds) {
/* Dive site doesn't exist. Add it to list of dive sites to be added. */
new_ds->dives.clear(); /* Caller is responsible for adding dives to site */
sites_to_add.put(std::move(new_ds));
res.sites_to_add.put(std::move(new_ds));
} else {
/* Dive site already exists - use the old one. */
for (j = 0; j < import_log->dives->nr; j++) {
if (import_log->dives->dives[j]->dive_site == new_ds.get())
import_log->dives->dives[j]->dive_site = old_ds;
for (auto &d: import_log.dives) {
if (d->dive_site == new_ds.get())
d->dive_site = old_ds;
}
}
}
import_log->sites->clear();
import_log.sites->clear();
/* Merge overlapping trips. Since both trip tables are sorted, we
* could be smarter here, but realistically not a whole lot of trips
* will be imported so do a simple n*m loop until someone complains.
*/
for (auto &trip_import: *import_log->trips) {
for (auto &trip_import: *import_log.trips) {
if ((flags & IMPORT_MERGE_ALL_TRIPS) || trip_import->autogen) {
if (try_to_merge_trip(*trip_import, import_log->dives.get(), flags & IMPORT_PREFER_IMPORTED, dives_to_add, dives_to_remove,
&sequence_changed, &start_renumbering_at))
if (try_to_merge_trip(*trip_import, import_log.dives, flags & IMPORT_PREFER_IMPORTED,
res.dives_to_add, res.dives_to_remove,
sequence_changed, start_renumbering_at))
continue;
}
@ -1163,43 +1084,43 @@ void process_imported_dives(struct divelog *import_log, int flags,
* First, add dives to list of dives to add */
for (struct dive *d: trip_import->dives) {
/* Add dive to list of dives to-be-added. */
insert_dive(dives_to_add, d);
sequence_changed |= !dive_is_after_last(d);
remove_dive(d, import_log->dives.get());
auto [owned, idx] = import_log.dives.pull(d);
if (!owned)
continue;
sequence_changed |= !dive_is_after_last(*owned);
res.dives_to_add.put(std::move(owned));
}
trip_import->dives.clear(); /* Caller is responsible for adding dives to trip */
/* Finally, add trip to list of trips to add */
trips_to_add.put(std::move(trip_import));
res.trips_to_add.put(std::move(trip_import));
}
import_log->trips->clear(); /* All trips were consumed */
import_log.trips->clear(); /* All trips were consumed */
if ((flags & IMPORT_ADD_TO_NEW_TRIP) && import_log->dives->nr > 0) {
if ((flags & IMPORT_ADD_TO_NEW_TRIP) && !import_log.dives.empty()) {
/* Create a new trip for unassigned dives, if desired. */
auto [new_trip, idx] = trips_to_add.put(
create_trip_from_dive(import_log->dives->dives[0])
auto [new_trip, idx] = res.trips_to_add.put(
create_trip_from_dive(import_log.dives.front().get())
);
/* Add all remaining dives to this trip */
for (i = 0; i < import_log->dives->nr; i++) {
struct dive *d = import_log->dives->dives[i];
for (auto &d: import_log.dives) {
sequence_changed |= !dive_is_after_last(*d);
d->divetrip = new_trip;
insert_dive(dives_to_add, d);
sequence_changed |= !dive_is_after_last(d);
res.dives_to_add.put(std::move(d));
}
import_log->dives->nr = 0; /* All dives were consumed */
} else if (import_log->dives->nr > 0) {
/* The remaining dives in import_log->dives are those that don't belong to
import_log.dives.clear(); /* All dives were consumed */
} else if (!import_log.dives.empty()) {
/* The remaining dives in import_log.dives are those that don't belong to
* a trip and the caller does not want them to be associated to a
* new trip. Merge them into the global table. */
sequence_changed |= merge_dive_tables(dive_table_to_non_owning(*import_log->dives),
import_log->dives.get(),
dive_table_to_non_owning(*divelog.dives),
sequence_changed |= merge_dive_tables(dive_table_to_non_owning(import_log.dives),
import_log.dives,
dive_table_to_non_owning(divelog.dives),
flags & IMPORT_PREFER_IMPORTED, NULL,
dives_to_add, dives_to_remove, &start_renumbering_at);
res.dives_to_add, res.dives_to_remove, start_renumbering_at);
}
/* If new dives were only added at the end, renumber the added dives.
@ -1207,26 +1128,25 @@ void process_imported_dives(struct divelog *import_log, int flags,
* - The last dive in the old dive table had a number itself (if there is a last dive).
* - None of the new dives has a number.
*/
last_old_dive_is_numbered = divelog.dives->nr == 0 || divelog.dives->dives[divelog.dives->nr - 1]->number > 0;
last_old_dive_is_numbered = divelog.dives.empty() || divelog.dives.back()->number > 0;
/* We counted the number of merged dives that were added to dives_to_add.
* Skip those. Since sequence_changed is false all added dives are *after*
* all merged dives. */
if (!sequence_changed && last_old_dive_is_numbered && !new_dive_has_number) {
nr = divelog.dives->nr > 0 ? divelog.dives->dives[divelog.dives->nr - 1]->number : 0;
for (i = start_renumbering_at; i < dives_to_add->nr; i++)
dives_to_add->dives[i]->number = ++nr;
int nr = !divelog.dives.empty() ? divelog.dives.back()->number : 0;
for (auto it = res.dives_to_add.begin() + start_renumbering_at; it < res.dives_to_add.end(); ++it)
(*it)->number = ++nr;
}
return res;
}
static struct dive *get_last_valid_dive()
{
int i;
for (i = divelog.dives->nr - 1; i >= 0; i--) {
if (!divelog.dives->dives[i]->invalid)
return divelog.dives->dives[i];
}
return NULL;
auto it = std::find_if(divelog.dives.rbegin(), divelog.dives.rend(),
[](auto &d) { return !d->invalid; });
return it != divelog.dives.rend() ? it->get() : nullptr;
}
/* return the number a dive gets when inserted at the given index.
@ -1238,7 +1158,7 @@ static struct dive *get_last_valid_dive()
*/
int get_dive_nr_at_idx(int idx)
{
if (idx < divelog.dives->nr)
if (static_cast<size_t>(idx) < divelog.dives.size())
return 0;
struct dive *last_dive = get_last_valid_dive();
if (!last_dive)
@ -1246,6 +1166,19 @@ int get_dive_nr_at_idx(int idx)
return last_dive->number ? last_dive->number + 1 : 0;
}
/* lookup of trip in main trip_table based on its id */
dive *dive_table::get_by_uniq_id(int id) const
{
auto it = std::find_if(begin(), end(), [id](auto &d) { return d->id == id; });
#ifdef DEBUG
if (it == end()) {
report_info("Invalid id %x passed to get_dive_by_diveid, try to fix the code", id);
exit(1);
}
#endif
return it != end() ? it->get() : nullptr;
}
static int min_datafile_version;
int get_min_datafile_version()
@ -1278,11 +1211,16 @@ void clear_dive_file_data()
emit_reset_signal();
}
bool dive_less_than(const struct dive *a, const struct dive *b)
bool dive_less_than(const struct dive &a, const struct dive &b)
{
return comp_dives(a, b) < 0;
}
bool dive_less_than_ptr(const struct dive *a, const struct dive *b)
{
return comp_dives(*a, *b) < 0;
}
/* When comparing a dive to a trip, use the first dive of the trip. */
static int comp_dive_to_trip(struct dive *a, struct dive_trip *b)
{
@ -1290,7 +1228,7 @@ static int comp_dive_to_trip(struct dive *a, struct dive_trip *b)
* with no (or worse a negative number of) dives. */
if (!b || b->dives.empty())
return -1;
return comp_dives(a, b->dives[0]);
return comp_dives(*a, *b->dives[0]);
}
static int comp_dive_or_trip(struct dive_or_trip a, struct dive_or_trip b)
@ -1308,7 +1246,7 @@ static int comp_dive_or_trip(struct dive_or_trip a, struct dive_or_trip b)
if (!b.dive && !b.trip)
return 1;
if (a.dive && b.dive)
return comp_dives(a.dive, b.dive);
return comp_dives(*a.dive, *b.dive);
if (a.trip && b.trip)
return comp_trips(*a.trip, *b.trip);
if (a.dive)
@ -1334,18 +1272,15 @@ bool dive_or_trip_less_than(struct dive_or_trip a, struct dive_or_trip b)
*/
timestamp_t get_surface_interval(timestamp_t when)
{
int i;
timestamp_t prev_end;
/* find previous dive. might want to use a binary search. */
for (i = divelog.dives->nr - 1; i >= 0; --i) {
if (divelog.dives->dives[i]->when < when)
break;
}
if (i < 0)
auto it = std::find_if(divelog.dives.rbegin(), divelog.dives.rend(),
[when] (auto &d) { return d->when < when; });
if (it == divelog.dives.rend())
return -1;
prev_end = divelog.dives->dives[i]->endtime();
prev_end = (*it)->endtime();
if (prev_end > when)
return 0;
return when - prev_end;
@ -1355,43 +1290,31 @@ timestamp_t get_surface_interval(timestamp_t when)
* then newer dives. */
struct dive *find_next_visible_dive(timestamp_t when)
{
int i, j;
if (!divelog.dives->nr)
return NULL;
if (divelog.dives.empty())
return nullptr;
/* we might want to use binary search here */
for (i = 0; i < divelog.dives->nr; i++) {
if (when <= get_dive(i)->when)
break;
auto it = std::find_if(divelog.dives.begin(), divelog.dives.end(),
[when] (auto &d) { return d->when <= when; });
for (auto it2 = it; it2 != divelog.dives.begin(); --it2) {
if (!(*std::prev(it2))->hidden_by_filter)
return it2->get();
}
for (j = i - 1; j > 0; j--) {
if (!get_dive(j)->hidden_by_filter)
return get_dive(j);
for (auto it2 = it; it2 != divelog.dives.end(); ++it2) {
if (!(*it2)->hidden_by_filter)
return it2->get();
}
for (j = i; j < divelog.dives->nr; j++) {
if (!get_dive(j)->hidden_by_filter)
return get_dive(j);
}
return NULL;
return nullptr;
}
bool has_dive(unsigned int deviceid, unsigned int diveid)
{
int i;
struct dive *dive;
for_each_dive (i, dive) {
for (auto &dc: dive->dcs) {
if (dc.deviceid != deviceid)
continue;
if (dc.diveid != diveid)
continue;
return 1;
}
}
return 0;
return std::any_of(divelog.dives.begin(), divelog.dives.end(), [deviceid,diveid] (auto &d) {
return std::any_of(d->dcs.begin(), d->dcs.end(), [deviceid,diveid] (auto &dc) {
return dc.deviceid == deviceid && dc.diveid == diveid;
});
});
}

View file

@ -2,27 +2,29 @@
#ifndef DIVELIST_H
#define DIVELIST_H
#include "triptable.h"
#include "divesitetable.h"
#include "units.h"
#include <memory>
#include <vector>
struct dive;
struct divelog;
struct trip_table;
class dive_site_table;
struct device;
struct deco_state;
struct dive_table {
int nr, allocated;
struct dive **dives;
int comp_dives(const struct dive &a, const struct dive &b);
int comp_dives_ptr(const struct dive *a, const struct dive *b);
struct dive_table : public sorted_owning_table<dive, &comp_dives> {
dive *get_by_uniq_id(int id) const;
void record_dive(std::unique_ptr<dive> d); // call fixup_dive() before adding dive to table.
std::unique_ptr<dive> unregister_dive(int idx);
};
static const struct dive_table empty_dive_table = { 0, 0, (struct dive **)0 };
/* this is used for both git and xml format */
#define DATAFORMAT_VERSION 3
extern void sort_dive_table(struct dive_table *table);
extern void update_cylinder_related_info(struct dive *);
extern int init_decompression(struct deco_state *ds, const struct dive *dive, bool in_planner);
@ -33,30 +35,26 @@ extern void process_loaded_dives();
#define IMPORT_IS_DOWNLOADED (1 << 1)
#define IMPORT_MERGE_ALL_TRIPS (1 << 2)
#define IMPORT_ADD_TO_NEW_TRIP (1 << 3)
extern void add_imported_dives(struct divelog *log, int flags);
extern void process_imported_dives(struct divelog *import_log, int flags,
struct dive_table *dives_to_add, struct dive_table *dives_to_remove,
struct trip_table &trips_to_add, dive_site_table &sites_to_add,
std::vector<device> &devices_to_add);
extern void add_imported_dives(struct divelog &log, int flags);
struct process_imported_dives_result {
dive_table dives_to_add;
std::vector<dive *> dives_to_remove;
trip_table trips_to_add;
dive_site_table sites_to_add;
std::vector<device> devices_to_add;
};
extern process_imported_dives_result process_imported_dives(struct divelog &import_log, int flags);
extern int dive_table_get_insertion_index(struct dive_table *table, struct dive *dive);
extern void add_to_dive_table(struct dive_table *table, int idx, struct dive *dive);
extern void insert_dive(struct dive_table *table, struct dive *d);
extern void get_dive_gas(const struct dive *dive, int *o2_p, int *he_p, int *o2low_p);
extern int get_divenr(const struct dive *dive);
extern int remove_dive(const struct dive *dive, struct dive_table *table);
extern int get_dive_nr_at_idx(int idx);
extern timestamp_t get_surface_interval(timestamp_t when);
extern void delete_dive_from_table(struct dive_table *table, int idx);
extern struct dive *find_next_visible_dive(timestamp_t when);
extern int comp_dives(const struct dive *a, const struct dive *b);
int get_min_datafile_version();
void report_datafile_version(int version);
void clear_dive_file_data();
void clear_dive_table(struct dive_table *table);
struct dive *unregister_dive(int idx);
struct dive *register_dive(std::unique_ptr<dive> d);
extern bool has_dive(unsigned int deviceid, unsigned int diveid);

View file

@ -3,6 +3,7 @@
#include "divelist.h"
#include "divesite.h"
#include "device.h"
#include "dive.h"
#include "errorhelper.h"
#include "filterpreset.h"
#include "trip.h"
@ -10,21 +11,14 @@
struct divelog divelog;
divelog::divelog() :
dives(std::make_unique<dive_table>()),
trips(std::make_unique<trip_table>()),
sites(std::make_unique<dive_site_table>()),
filter_presets(std::make_unique<filter_preset_table>()),
autogroup(false)
{
*dives = empty_dive_table;
}
divelog::~divelog()
{
if (dives)
clear_dive_table(dives.get());
}
divelog::~divelog() = default;
divelog::divelog(divelog &&) = default;
struct divelog &divelog::operator=(divelog &&) = default;
@ -32,11 +26,11 @@ struct divelog &divelog::operator=(divelog &&) = default;
* dive log and the trip, but doesn't deal with updating dive trips, etc */
void divelog::delete_single_dive(int idx)
{
if (idx < 0 || idx > dives->nr) {
report_info("Warning: deleting unexisting dive with index %d", idx);
if (idx < 0 || static_cast<size_t>(idx) >= dives.size()) {
report_info("Warning: deleting non-existing dive with index %d", idx);
return;
}
struct dive *dive = dives->dives[idx];
struct dive *dive = dives[idx].get();
struct dive_trip *trip = unregister_dive_from_trip(dive);
// Deleting a dive may change the order of trips!
@ -46,15 +40,58 @@ void divelog::delete_single_dive(int idx)
if (trip && trip->dives.empty())
trips->pull(trip);
unregister_dive_from_dive_site(dive);
delete_dive_from_table(dives.get(), idx);
dives.erase(dives.begin() + idx);
}
void divelog::delete_multiple_dives(const std::vector<dive *> &dives_to_delete)
{
bool trips_changed = false;
for (dive *d: dives_to_delete) {
// Delete dive from trip and delete trip if empty
struct dive_trip *trip = unregister_dive_from_trip(d);
if (trip && trip->dives.empty()) {
trips_changed = true;
trips->pull(trip);
}
unregister_dive_from_dive_site(d);
dives.pull(d);
}
// Deleting a dive may change the order of trips!
if (trips_changed)
trips->sort();
}
void divelog::clear()
{
while (dives->nr > 0)
delete_dive_from_table(dives.get(), dives->nr - 1);
dives.clear();
sites->clear();
trips->clear();
devices.clear();
filter_presets->clear();
}
/* check if we have a trip right before / after this dive */
bool divelog::is_trip_before_after(const struct dive *dive, bool before) const
{
auto it = std::find_if(dives.begin(), dives.end(),
[dive](auto &d) { return d.get() == dive; });
if (it == dives.end())
return false;
if (before) {
do {
if (it == dives.begin())
return false;
--it;
} while ((*it)->invalid);
return (*it)->divetrip != nullptr;
} else {
++it;
while (it != dives.end() && (*it)->invalid)
++it;
return it != dives.end() && (*it)->divetrip != nullptr;
}
}

View file

@ -3,17 +3,18 @@
#ifndef DIVELOG_H
#define DIVELOG_H
#include "divelist.h"
#include <memory>
#include <vector>
struct dive_table;
struct trip_table;
class dive_site_table;
struct device;
struct filter_preset_table;
struct divelog {
std::unique_ptr<dive_table> dives;
dive_table dives;
std::unique_ptr<trip_table> trips;
std::unique_ptr<dive_site_table> sites;
std::vector<device> devices;
@ -26,7 +27,9 @@ struct divelog {
divelog &operator=(divelog &&); // move assignment (argument is consumed).
void delete_single_dive(int idx);
void delete_multiple_dives(const std::vector<dive *> &dives);
void clear();
bool is_trip_before_after(const struct dive *dive, bool before) const;
};
extern struct divelog divelog;

View file

@ -11,6 +11,13 @@
#include <math.h>
int divesite_comp_uuid(const dive_site &ds1, const dive_site &ds2)
{
if (ds1.uuid == ds2.uuid)
return 0;
return ds1.uuid < ds2.uuid ? -1 : 1;
}
template <typename PRED>
dive_site *get_by_predicate(const dive_site_table &ds_table, PRED pred)
{

View file

@ -3,13 +3,10 @@
#define DIVESITE_H
#include "divelist.h"
#include "owning_table.h"
#include "taxonomy.h"
#include "units.h"
#include <stdlib.h>
#include <QObject>
struct dive_site
{
uint32_t uuid = 0;
@ -33,32 +30,11 @@ struct dive_site
void add_dive(struct dive *d);
};
inline int divesite_comp_uuid(const dive_site &ds1, const dive_site &ds2)
{
if (ds1.uuid == ds2.uuid)
return 0;
return ds1.uuid < ds2.uuid ? -1 : 1;
}
class dive_site_table : public sorted_owning_table<dive_site, &divesite_comp_uuid> {
public:
put_result register_site(std::unique_ptr<dive_site> site); // Creates or changes UUID if duplicate
dive_site *get_by_uuid(uint32_t uuid) const;
dive_site *alloc_or_get(uint32_t uuid);
dive_site *create(const std::string &name);
dive_site *create(const std::string &name, const location_t);
dive_site *find_or_create(const std::string &name);
dive_site *get_by_name(const std::string &name) const;
dive_site *get_by_gps(const location_t *) const;
dive_site *get_by_gps_and_name(const std::string &name, const location_t) const;
dive_site *get_by_gps_proximity(location_t, int distance) const;
dive_site *get_same(const struct dive_site &) const;
void purge_empty();
};
struct dive_site *unregister_dive_from_dive_site(struct dive *d);
int divesite_comp_uuid(const dive_site &ds1, const dive_site &ds2);
/* Make pointer-to-dive_site a "Qt metatype" so that we can pass it through QVariants */
#include <QObject>
Q_DECLARE_METATYPE(dive_site *);
#endif // DIVESITE_H

27
core/divesitetable.h Normal file
View file

@ -0,0 +1,27 @@
// SPDX-License-Identifier: GPL-2.0
#ifndef DIVESITETABLE_H
#define DIVESITETABLE_H
#include "owning_table.h"
#include "units.h"
struct dive_site;
int divesite_comp_uuid(const dive_site &ds1, const dive_site &ds2);
class dive_site_table : public sorted_owning_table<dive_site, &divesite_comp_uuid> {
public:
put_result register_site(std::unique_ptr<dive_site> site); // Creates or changes UUID if duplicate
dive_site *get_by_uuid(uint32_t uuid) const;
dive_site *alloc_or_get(uint32_t uuid);
dive_site *create(const std::string &name);
dive_site *create(const std::string &name, const location_t);
dive_site *find_or_create(const std::string &name);
dive_site *get_by_name(const std::string &name) const;
dive_site *get_by_gps(const location_t *) const;
dive_site *get_by_gps_and_name(const std::string &name, const location_t) const;
dive_site *get_by_gps_proximity(location_t, int distance) const;
dive_site *get_same(const struct dive_site &) const;
void purge_empty();
};
#endif // DIVESITETABLE_H

View file

@ -112,9 +112,9 @@ void DownloadThread::run()
internalData->vendor.c_str(), internalData->product.c_str());
report_info("Finishing download thread: %s", error.c_str());
} else {
if (!log.dives->nr)
if (log.dives.empty())
error = tr("No new dives downloaded from dive computer").toStdString();
report_info("Finishing download thread: %d dives downloaded", log.dives->nr);
report_info("Finishing download thread: %d dives downloaded", static_cast<int>(log.dives.size()));
}
qPrefDiveComputer::set_vendor(internalData->vendor.c_str());
qPrefDiveComputer::set_product(internalData->product.c_str());

View file

@ -284,8 +284,7 @@ void reset_tank_info_table(std::vector<tank_info> &table)
add_default_tank_infos(table);
/* Add cylinders from dive list */
for (int i = 0; i < divelog.dives->nr; ++i) {
const struct dive *dive = divelog.dives->dives[i];
for (auto &dive: divelog.dives) {
for (auto &cyl: dive->cylinders)
add_cylinder_description(cyl.type);
}

View file

@ -143,11 +143,9 @@ void FullText::populate()
// we want this to be two calls as the second text is overwritten below by the lines starting with "\r"
uiNotification(QObject::tr("Create full text index"));
uiNotification(QObject::tr("start processing"));
int i;
dive *d;
for_each_dive(i, d)
registerDive(d);
uiNotification(QObject::tr("%1 dives processed").arg(divelog.dives->nr));
for (auto &d: divelog.dives)
registerDive(d.get());
uiNotification(QObject::tr("%1 dives processed").arg(divelog.dives.size()));
}
void FullText::registerDive(struct dive *d)
@ -170,9 +168,7 @@ void FullText::unregisterDive(struct dive *d)
void FullText::unregisterAll()
{
int i;
dive *d;
for_each_dive(i, d)
for (auto &d: divelog.dives)
d->full_text.reset();
words.clear();
}

View file

@ -443,7 +443,7 @@ int try_to_open_csv(std::string &mem, enum csv_format type, struct divelog *log)
break;
p = end + 1;
}
record_dive_to_table(dive.release(), log->dives.get());
log->dives.record_dive(std::move(dive));
return 1;
}
@ -749,7 +749,7 @@ int parse_txt_file(const char *filename, const char *csv, struct divelog *log)
if (!lineptr || !*lineptr)
break;
}
record_dive_to_table(dive.release(), log->dives.get());
log->dives.record_dive(std::move(dive));
return 1;
} else {
return 0;

View file

@ -537,7 +537,7 @@ static int might_be_same_dc(const struct divecomputer &a, const struct divecompu
return a.deviceid == b.deviceid;
}
static bool match_one_dive(const struct divecomputer &a, struct dive *dive)
static bool match_one_dive(const struct divecomputer &a, const struct dive &dive)
{
/*
* Walk the existing dive computer data,
@ -545,13 +545,13 @@ static bool match_one_dive(const struct divecomputer &a, struct dive *dive)
* the same dive computer but a different
* dive ID).
*/
for (auto &b: dive->dcs) {
for (auto &b: dive.dcs) {
if (match_one_dc(a, b) > 0)
return true;
}
/* Ok, no exact dive computer match. Does the date match? */
for (auto &b: dive->dcs) {
for (auto &b: dive.dcs) {
if (a.when == b.when && might_be_same_dc(a, b))
return true;
}
@ -562,17 +562,10 @@ static bool match_one_dive(const struct divecomputer &a, struct dive *dive)
/*
* Check if this dive already existed before the import
*/
static int find_dive(const struct divecomputer &match)
static bool find_dive(const struct divecomputer &match)
{
int i;
for (i = divelog.dives->nr - 1; i >= 0; i--) {
struct dive *old = divelog.dives->dives[i];
if (match_one_dive(match, old))
return 1;
}
return 0;
return std::any_of(divelog.dives.rbegin(), divelog.dives.rend(),
[&match] (auto &old) { return match_one_dive(match, *old);} );
}
/*
@ -871,7 +864,7 @@ static int dive_cb(const unsigned char *data, unsigned int size,
dive->dcs[0].samples[1].temperature.mkelvin > dive->dcs[0].samples[0].temperature.mkelvin)
dive->dcs[0].samples[0].temperature.mkelvin = dive->dcs[0].samples[1].temperature.mkelvin;
record_dive_to_table(dive.release(), devdata->log->dives.get());
devdata->log->dives.record_dive(std::move(dive));
return true;
error_exit:
@ -1509,7 +1502,7 @@ std::string do_libdivecomputer_import(device_data_t *data)
dc_device_close(data->device);
data->device = NULL;
if (!data->log->dives->nr)
if (data->log->dives.empty())
dev_info(data, translate("gettextFromC", "No new dives downloaded from dive computer"));
}
dc_iostream_close(data->iostream);

View file

@ -131,7 +131,7 @@ static int handle_event_ver3(int code, const unsigned char *ps, unsigned int ps_
return skip;
}
static void parse_dives(int log_version, const unsigned char *buf, unsigned int buf_size, struct dive_table *table, dive_site_table &sites)
static void parse_dives(int log_version, const unsigned char *buf, unsigned int buf_size, struct dive_table &table, dive_site_table &sites)
{
unsigned int ptr = 0;
unsigned char model;
@ -407,8 +407,7 @@ static void parse_dives(int log_version, const unsigned char *buf, unsigned int
}
// End dive
record_dive_to_table(dive.release(), table);
dive = NULL;
table.record_dive(std::move(dive));
// Advance ptr for next dive
ptr += ps_ptr + 4;
@ -438,7 +437,7 @@ int try_to_open_liquivision(const char *, std::string &mem, struct divelog *log)
}
ptr += 4;
parse_dives(log_version, buf + ptr, buf_size - ptr, log->dives.get(), *log->sites);
parse_dives(log_version, buf + ptr, buf_size - ptr, log->dives, *log->sites);
return 1;
}

View file

@ -1390,7 +1390,7 @@ static void finish_active_trip(struct git_parser_state *state)
static void finish_active_dive(struct git_parser_state *state)
{
if (state->active_dive)
record_dive_to_table(state->active_dive.release(), state->log->dives.get());
state->log->dives.record_dive(std::move(state->active_dive));
}
static void create_new_dive(timestamp_t when, struct git_parser_state *state)

View file

@ -169,6 +169,5 @@ void ostctools_import(const char *file, struct divelog *log)
else if (it == ostcdive->dcs[0].extra_data.end())
add_extra_data(&ostcdive->dcs[0], "Serial", ostcdive->dcs[0].serial);
record_dive_to_table(ostcdive.release(), log->dives.get());
sort_dive_table(log->dives.get());
log->dives.record_dive(std::move(ostcdive));
}

View file

@ -124,6 +124,7 @@ public:
this->insert(it, std::move(item));
return { ptr, idx };
}
// Optimized version of get_idx(), which uses binary search
// If not found, fall back to linear search and emit a warning.
// Note: this is probaly slower than a linesr search. But for now,
@ -140,6 +141,15 @@ public:
}
return it - this->begin();
}
// Get place where insertion would take place
size_t get_insertion_index(const T *item) const {
auto it = std::lower_bound(this->begin(), this->end(), item,
[] (const auto &i1, const auto &i2)
{ return CMP(*i1, *i2) < 0; });
return it - this->begin();
}
// Note: this is silly - finding the pointer by a linear search
// is probably significantly faster than doing a binary search.
// But it helps finding consistency problems for now. Remove in
@ -152,6 +162,7 @@ public:
}
return { this->pull_at(idx), idx };
}
void sort() {
std::sort(this->begin(), this->end(), [](const auto &a, const auto &b) { return CMP(*a, *b) < 0; });
}

View file

@ -31,14 +31,6 @@ struct divecomputer *get_dc(struct parser_state *state)
return state->cur_dc ?: &state->cur_dive->dcs[0];
}
/*
* Add a dive into the dive_table array
*/
void record_dive_to_table(struct dive *dive, struct dive_table *table)
{
add_to_dive_table(table, table->nr, fixup_dive(dive));
}
void start_match(const char *type, const char *name, char *buffer)
{
if (verbose > 2)
@ -270,7 +262,12 @@ void dive_end(struct parser_state *state)
if (is_dive(state)) {
if (state->cur_trip)
add_dive_to_trip(state->cur_dive.get(), state->cur_trip.get());
record_dive_to_table(state->cur_dive.release(), state->log->dives.get());
// Note: we add dives in an unsorted way. The caller of the parsing
// function must sort dives.
fixup_dive(state->cur_dive.get());
state->log->dives.push_back(std::move(state->cur_dive));
// This would add dives in a sorted way:
// state->log->dives.record_dive(std::move(state->cur_dive));
}
state->cur_dive.reset();
state->cur_dc = NULL;

View file

@ -1,6 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
#include "picture.h"
#include "dive.h"
#include "divelist.h"
#include "divelog.h"
#if !defined(SUBSURFACE_MOBILE)
#include "metadata.h"
#endif
@ -30,11 +32,11 @@ int get_picture_idx(const picture_table &t, const std::string &filename)
#if !defined(SUBSURFACE_MOBILE)
/* Return distance of timestamp to time of dive. Result is always positive, 0 means during dive. */
static timestamp_t time_from_dive(const struct dive *d, timestamp_t timestamp)
static timestamp_t time_from_dive(const struct dive &d, timestamp_t timestamp)
{
timestamp_t end_time = d->endtime();
if (timestamp < d->when)
return d->when - timestamp;
timestamp_t end_time = d.endtime();
if (timestamp < d.when)
return d.when - timestamp;
else if (timestamp > end_time)
return timestamp - end_time;
else
@ -44,16 +46,15 @@ static timestamp_t time_from_dive(const struct dive *d, timestamp_t timestamp)
/* Return dive closest selected dive to given timestamp or NULL if no dives are selected. */
static struct dive *nearest_selected_dive(timestamp_t timestamp)
{
struct dive *d, *res = NULL;
int i;
timestamp_t offset, min = 0;
struct dive *res = NULL;
timestamp_t min = 0;
for_each_dive(i, d) {
for (auto &d: divelog.dives) {
if (!d->selected)
continue;
offset = time_from_dive(d, timestamp);
timestamp_t offset = time_from_dive(*d, timestamp);
if (!res || offset < min) {
res = d;
res = d.get();
min = offset;
}
@ -71,7 +72,7 @@ static struct dive *nearest_selected_dive(timestamp_t timestamp)
// only add pictures that have timestamps between 30 minutes before the dive and
// 30 minutes after the dive ends
static constexpr timestamp_t d30min = 30 * 60;
static bool dive_check_picture_time(const struct dive *d, timestamp_t timestamp)
static bool dive_check_picture_time(const struct dive &d, timestamp_t timestamp)
{
return time_from_dive(d, timestamp) < d30min;
}
@ -93,7 +94,7 @@ std::pair<std::optional<picture>, dive *> create_picture(const std::string &file
return { {}, nullptr };
if (get_picture_idx(dive->pictures, filename) >= 0)
return { {}, nullptr };
if (!match_all && !dive_check_picture_time(dive, timestamp))
if (!match_all && !dive_check_picture_time(*dive, timestamp))
return { {}, nullptr };
struct picture picture;
@ -105,12 +106,8 @@ std::pair<std::optional<picture>, dive *> create_picture(const std::string &file
bool picture_check_valid_time(timestamp_t timestamp, timestamp_t shift_time)
{
int i;
struct dive *dive;
for_each_dive (i, dive)
if (dive->selected && dive_check_picture_time(dive, timestamp + shift_time))
return true;
return false;
return std::any_of(divelog.dives.begin(), divelog.dives.end(),
[t = timestamp + shift_time] (auto &d)
{ return d->selected && dive_check_picture_time(*d, t); });
}
#endif

View file

@ -301,7 +301,7 @@ static void create_dive_from_plan(struct diveplan *diveplan, struct dive *dive,
dc->last_manual_time.seconds = last_manual_point;
#if DEBUG_PLAN & 32
save_dive(stdout, dive);
save_dive(stdout, *dive);
#endif
return;
}

View file

@ -988,14 +988,14 @@ static QString get_dive_only_date_string(timestamp_t when)
QString get_first_dive_date_string()
{
const dive_table &dives = *divelog.dives;
return dives.nr > 0 ? get_dive_only_date_string(dives.dives[0]->when) : gettextFromC::tr("no dives");
const dive_table &dives = divelog.dives;
return !dives.empty() ? get_dive_only_date_string(dives[0]->when) : gettextFromC::tr("no dives");
}
QString get_last_dive_date_string()
{
const dive_table &dives = *divelog.dives;
return dives.nr > 0 ? get_dive_only_date_string(dives.dives[dives.nr - 1]->when) : gettextFromC::tr("no dives");
const dive_table &dives = divelog.dives;
return !dives.empty() ? get_dive_only_date_string(dives.back()->when) : gettextFromC::tr("no dives");
}
std::string get_current_date()

View file

@ -46,7 +46,7 @@ static void cond_put_format(int cond, struct membuffer *b, const char *fmt, ...)
}
}
#define SAVE(str, x) cond_put_format(dive->x, b, str " %d\n", dive->x)
#define SAVE(str, x) cond_put_format(dive.x, b, str " %d\n", dive.x)
static void quote(struct membuffer *b, const char *text)
{
@ -96,12 +96,12 @@ static void show_utf8(struct membuffer *b, const char *prefix, const char *value
}
}
static void save_overview(struct membuffer *b, struct dive *dive)
static void save_overview(struct membuffer *b, const struct dive &dive)
{
show_utf8(b, "divemaster ", dive->diveguide.c_str(), "\n");
show_utf8(b, "buddy ", dive->buddy.c_str(), "\n");
show_utf8(b, "suit ", dive->suit.c_str(), "\n");
show_utf8(b, "notes ", dive->notes.c_str(), "\n");
show_utf8(b, "divemaster ", dive.diveguide.c_str(), "\n");
show_utf8(b, "buddy ", dive.buddy.c_str(), "\n");
show_utf8(b, "suit ", dive.suit.c_str(), "\n");
show_utf8(b, "notes ", dive.notes.c_str(), "\n");
}
static void save_tags(struct membuffer *b, const tag_list &tags)
@ -138,9 +138,9 @@ static void put_gasmix(struct membuffer *b, struct gasmix mix)
}
}
static void save_cylinder_info(struct membuffer *b, struct dive *dive)
static void save_cylinder_info(struct membuffer *b, const struct dive &dive)
{
for (auto &cyl: dive->cylinders) {
for (auto &cyl: dive.cylinders) {
int volume = cyl.type.size.mliter;
int use = cyl.cylinder_use;
@ -161,9 +161,9 @@ static void save_cylinder_info(struct membuffer *b, struct dive *dive)
}
}
static void save_weightsystem_info(struct membuffer *b, const struct dive *dive)
static void save_weightsystem_info(struct membuffer *b, const struct dive &dive)
{
for (auto &ws: dive->weightsystems) {
for (auto &ws: dive.weightsystems) {
int grams = ws.weight.grams;
put_string(b, "weightsystem");
@ -173,12 +173,12 @@ static void save_weightsystem_info(struct membuffer *b, const struct dive *dive)
}
}
static void save_dive_temperature(struct membuffer *b, struct dive *dive)
static void save_dive_temperature(struct membuffer *b, const struct dive &dive)
{
if (dive->airtemp.mkelvin != dive->dc_airtemp().mkelvin)
put_temperature(b, dive->airtemp, "airtemp ", "°C\n");
if (dive->watertemp.mkelvin != dive->dc_watertemp().mkelvin)
put_temperature(b, dive->watertemp, "watertemp ", "°C\n");
if (dive.airtemp.mkelvin != dive.dc_airtemp().mkelvin)
put_temperature(b, dive.airtemp, "airtemp ", "°C\n");
if (dive.watertemp.mkelvin != dive.dc_watertemp().mkelvin)
put_temperature(b, dive.watertemp, "watertemp ", "°C\n");
}
static void save_depths(struct membuffer *b, const struct divecomputer &dc)
@ -356,13 +356,13 @@ static void save_sample(struct membuffer *b, const struct sample &sample, struct
put_format(b, "\n");
}
static void save_samples(struct membuffer *b, struct dive *dive, const struct divecomputer &dc)
static void save_samples(struct membuffer *b, const struct dive &dive, const struct divecomputer &dc)
{
int o2sensor;
struct sample dummy;
/* Is this a CCR dive with the old-style "o2pressure" sensor? */
o2sensor = legacy_format_o2pressures(dive, &dc);
o2sensor = legacy_format_o2pressures(&dive, &dc);
if (o2sensor >= 0) {
dummy.sensor[0] = !o2sensor;
dummy.sensor[1] = o2sensor;
@ -372,7 +372,7 @@ static void save_samples(struct membuffer *b, struct dive *dive, const struct di
save_sample(b, s, dummy, o2sensor);
}
static void save_one_event(struct membuffer *b, struct dive *dive, const struct event &ev)
static void save_one_event(struct membuffer *b, const struct dive &dive, const struct event &ev)
{
put_format(b, "event %d:%02d", FRACTION_TUPLE(ev.time.seconds, 60));
show_index(b, ev.type, "type=", "");
@ -384,7 +384,7 @@ static void save_one_event(struct membuffer *b, struct dive *dive, const struct
show_index(b, ev.value, "value=", "");
show_utf8(b, " name=", ev.name.c_str(), "");
if (ev.is_gaschange()) {
struct gasmix mix = get_gasmix_from_event(dive, ev);
struct gasmix mix = get_gasmix_from_event(&dive, ev);
if (ev.gas.index >= 0)
show_integer(b, ev.gas.index, "cylinder=", "");
put_gasmix(b, mix);
@ -392,13 +392,13 @@ static void save_one_event(struct membuffer *b, struct dive *dive, const struct
put_string(b, "\n");
}
static void save_events(struct membuffer *b, struct dive *dive, const struct divecomputer &dc)
static void save_events(struct membuffer *b, const struct dive &dive, const struct divecomputer &dc)
{
for (auto &ev: dc.events)
save_one_event(b, dive, ev);
}
static void save_dc(struct membuffer *b, struct dive *dive, const struct divecomputer &dc)
static void save_dc(struct membuffer *b, const struct dive &dive, const struct divecomputer &dc)
{
show_utf8(b, "model ", dc.model.c_str(), "\n");
if (dc.last_manual_time.seconds)
@ -407,9 +407,9 @@ static void save_dc(struct membuffer *b, struct dive *dive, const struct divecom
put_format(b, "deviceid %08x\n", dc.deviceid);
if (dc.diveid)
put_format(b, "diveid %08x\n", dc.diveid);
if (dc.when && dc.when != dive->when)
if (dc.when && dc.when != dive.when)
show_date(b, dc.when);
if (dc.duration.seconds && dc.duration.seconds != dive->dcs[0].duration.seconds)
if (dc.duration.seconds && dc.duration.seconds != dive.dcs[0].duration.seconds)
put_duration(b, dc.duration, "duration ", "min\n");
if (dc.divemode != OC) {
put_format(b, "dctype %s\n", divemode_text[dc.divemode]);
@ -431,28 +431,28 @@ static void save_dc(struct membuffer *b, struct dive *dive, const struct divecom
* Note that we don't save the date and time or dive
* number: they are encoded in the filename.
*/
static void create_dive_buffer(struct dive *dive, struct membuffer *b)
static void create_dive_buffer(const struct dive &dive, struct membuffer *b)
{
pressure_t surface_pressure = un_fixup_surface_pressure(dive);
if (dive->dcs[0].duration.seconds > 0)
put_format(b, "duration %u:%02u min\n", FRACTION_TUPLE(dive->dcs[0].duration.seconds, 60));
pressure_t surface_pressure = un_fixup_surface_pressure(&dive);
if (dive.dcs[0].duration.seconds > 0)
put_format(b, "duration %u:%02u min\n", FRACTION_TUPLE(dive.dcs[0].duration.seconds, 60));
SAVE("rating", rating);
SAVE("visibility", visibility);
SAVE("wavesize", wavesize);
SAVE("current", current);
SAVE("surge", surge);
SAVE("chill", chill);
if (dive->user_salinity)
put_format(b, "watersalinity %d g/l\n", (int)(dive->user_salinity/10));
if (dive.user_salinity)
put_format(b, "watersalinity %d g/l\n", (int)(dive.user_salinity/10));
if (surface_pressure.mbar)
SAVE("airpressure", surface_pressure.mbar);
cond_put_format(dive->notrip, b, "notrip\n");
cond_put_format(dive->invalid, b, "invalid\n");
save_tags(b, dive->tags);
if (dive->dive_site)
put_format(b, "divesiteid %08x\n", dive->dive_site->uuid);
if (verbose && dive->dive_site)
report_info("removed reference to non-existant dive site with uuid %08x\n", dive->dive_site->uuid);
cond_put_format(dive.notrip, b, "notrip\n");
cond_put_format(dive.invalid, b, "invalid\n");
save_tags(b, dive.tags);
if (dive.dive_site)
put_format(b, "divesiteid %08x\n", dive.dive_site->uuid);
if (verbose && dive.dive_site)
report_info("removed reference to non-existant dive site with uuid %08x\n", dive.dive_site->uuid);
save_overview(b, dive);
save_cylinder_info(b, dive);
save_weightsystem_info(b, dive);
@ -565,12 +565,12 @@ static struct dir *mktree(git_repository *repo, struct dir *dir, const char *fmt
* We do *not* want to use localized weekdays and cause peoples save
* formats to depend on their locale.
*/
static void create_dive_name(struct dive *dive, struct membuffer *name, struct tm *dirtm)
static void create_dive_name(struct dive &dive, struct membuffer *name, struct tm *dirtm)
{
struct tm tm;
static const char weekday[7][4] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
utc_mkdate(dive->when, &tm);
utc_mkdate(dive.when, &tm);
if (tm.tm_year != dirtm->tm_year)
put_format(name, "%04u-", tm.tm_year);
if (tm.tm_mon != dirtm->tm_mon)
@ -600,7 +600,7 @@ static int blob_insert(git_repository *repo, struct dir *tree, struct membuffer
return ret;
}
static int save_one_divecomputer(git_repository *repo, struct dir *tree, struct dive *dive, const struct divecomputer &dc, int idx)
static int save_one_divecomputer(git_repository *repo, struct dir *tree, const struct dive &dive, const struct divecomputer &dc, int idx)
{
int ret;
membuffer buf;
@ -635,17 +635,17 @@ static int save_one_picture(git_repository *repo, struct dir *dir, const struct
sign, h, FRACTION_TUPLE(offset, 60));
}
static int save_pictures(git_repository *repo, struct dir *dir, struct dive *dive)
static int save_pictures(git_repository *repo, struct dir *dir, const struct dive &dive)
{
if (!dive->pictures.empty()) {
if (!dive.pictures.empty()) {
dir = mktree(repo, dir, "Pictures");
for (auto &picture: dive->pictures)
for (auto &picture: dive.pictures)
save_one_picture(repo, dir, picture);
}
return 0;
}
static int save_one_dive(git_repository *repo, struct dir *tree, struct dive *dive, struct tm *tm, bool cached_ok)
static int save_one_dive(git_repository *repo, struct dir *tree, struct dive &dive, struct tm *tm, bool cached_ok)
{
membuffer buf, name;
struct dir *subdir;
@ -658,9 +658,9 @@ static int save_one_dive(git_repository *repo, struct dir *tree, struct dive *di
* If the dive git ID is valid, we just create the whole directory
* with that ID
*/
if (cached_ok && dive_cache_is_valid(dive)) {
if (cached_ok && dive_cache_is_valid(&dive)) {
git_oid oid;
git_oid_fromraw(&oid, dive->git_id);
git_oid_fromraw(&oid, dive.git_id);
ret = tree_insert(tree->files, mb_cstring(&name), 1,
&oid, GIT_FILEMODE_TREE);
if (ret)
@ -672,7 +672,7 @@ static int save_one_dive(git_repository *repo, struct dir *tree, struct dive *di
subdir->unique = true;
create_dive_buffer(dive, &buf);
nr = dive->number;
nr = dive.number;
ret = blob_insert(repo, subdir, &buf,
"Dive%c%d", nr ? '-' : 0, nr);
if (ret)
@ -683,8 +683,8 @@ static int save_one_dive(git_repository *repo, struct dir *tree, struct dive *di
* computer, use index 0 for that (which disables the index
* generation when naming it).
*/
nr = dive->dcs.size() > 1 ? 1 : 0;
for (auto &dc: dive->dcs)
nr = dive.dcs.size() > 1 ? 1 : 0;
for (auto &dc: dive.dcs)
save_one_divecomputer(repo, subdir, dive, dc, nr++);
/* Save the picture data, if any */
@ -782,8 +782,6 @@ static void verify_shared_date(timestamp_t when, struct tm *tm)
static int save_one_trip(git_repository *repo, struct dir *tree, dive_trip *trip, struct tm *tm, bool cached_ok)
{
int i;
struct dive *dive;
struct dir *subdir;
membuffer name;
timestamp_t first, last;
@ -799,7 +797,7 @@ static int save_one_trip(git_repository *repo, struct dir *tree, dive_trip *trip
/* Make sure we write out the dates to the dives consistently */
first = MAX_TIMESTAMP;
last = MIN_TIMESTAMP;
for_each_dive(i, dive) {
for (auto &dive: divelog.dives) {
if (dive->divetrip != trip)
continue;
if (dive->when < first)
@ -811,9 +809,9 @@ static int save_one_trip(git_repository *repo, struct dir *tree, dive_trip *trip
verify_shared_date(last, tm);
/* Save each dive in the directory */
for_each_dive(i, dive) {
for (auto &dive: divelog.dives) {
if (dive->divetrip == trip)
save_one_dive(repo, subdir, dive, tm, cached_ok);
save_one_dive(repo, subdir, *dive, tm, cached_ok);
}
return 0;
@ -981,9 +979,6 @@ static void save_filter_presets(git_repository *repo, struct dir *tree)
static int create_git_tree(git_repository *repo, struct dir *root, bool select_only, bool cached_ok)
{
int i;
struct dive *dive;
git_storage_update_progress(translate("gettextFromC", "Start saving data"));
save_settings(repo, root);
@ -995,7 +990,7 @@ static int create_git_tree(git_repository *repo, struct dir *root, bool select_o
/* save the dives */
git_storage_update_progress(translate("gettextFromC", "Start saving dives"));
for_each_dive(i, dive) {
for (auto &dive: divelog.dives) {
struct tm tm;
struct dir *tree;
@ -1024,7 +1019,7 @@ static int create_git_tree(git_repository *repo, struct dir *root, bool select_o
continue;
}
save_one_dive(repo, tree, dive, &tm, cached_ok);
save_one_dive(repo, tree, *dive, &tm, cached_ok);
}
git_storage_update_progress(translate("gettextFromC", "Done creating local cache"));
return 0;
@ -1095,7 +1090,7 @@ int get_authorship(git_repository *repo, git_signature **authorp)
static void create_commit_message(struct membuffer *msg, bool create_empty)
{
int nr = divelog.dives->nr;
int nr = static_cast<int>(divelog.dives.size());
struct dive *dive = get_dive(nr-1);
std::string changes_made = get_changes_made();

View file

@ -43,13 +43,13 @@ static void copy_image_and_overwrite(const std::string &cfileName, const std::st
report_info("copy of %s to %s failed", cfileName.c_str(), newName.c_str());
}
static void save_photos(struct membuffer *b, const char *photos_dir, const struct dive *dive)
static void save_photos(struct membuffer *b, const char *photos_dir, const struct dive &dive)
{
if (dive->pictures.empty())
if (dive.pictures.empty())
return;
const char *separator = "\"photos\":[";
for (auto &picture: dive->pictures) {
for (auto &picture: dive.pictures) {
put_string(b, separator);
separator = ", ";
std::string fname = get_file_name(local_file_path(picture));
@ -61,11 +61,11 @@ static void save_photos(struct membuffer *b, const char *photos_dir, const struc
put_string(b, "],");
}
static void write_divecomputers(struct membuffer *b, const struct dive *dive)
static void write_divecomputers(struct membuffer *b, const struct dive &dive)
{
put_string(b, "\"divecomputers\":[");
const char *separator = "";
for (auto &dc: dive->dcs) {
for (auto &dc: dive.dcs) {
put_string(b, separator);
separator = ", ";
put_format(b, "{");
@ -83,17 +83,17 @@ static void write_divecomputers(struct membuffer *b, const struct dive *dive)
put_string(b, "],");
}
static void write_dive_status(struct membuffer *b, const struct dive *dive)
static void write_dive_status(struct membuffer *b, const struct dive &dive)
{
put_format(b, "\"sac\":\"%d\",", dive->sac);
put_format(b, "\"otu\":\"%d\",", dive->otu);
put_format(b, "\"cns\":\"%d\",", dive->cns);
put_format(b, "\"sac\":\"%d\",", dive.sac);
put_format(b, "\"otu\":\"%d\",", dive.otu);
put_format(b, "\"cns\":\"%d\",", dive.cns);
}
static void put_HTML_bookmarks(struct membuffer *b, const struct dive *dive)
static void put_HTML_bookmarks(struct membuffer *b, const struct dive &dive)
{
const char *separator = "\"events\":[";
for (const auto &ev: dive->dcs[0].events) {
for (const auto &ev: dive.dcs[0].events) {
put_string(b, separator);
separator = ", ";
put_string(b, "{\"name\":\"");
@ -106,13 +106,13 @@ static void put_HTML_bookmarks(struct membuffer *b, const struct dive *dive)
put_string(b, "],");
}
static void put_weightsystem_HTML(struct membuffer *b, const struct dive *dive)
static void put_weightsystem_HTML(struct membuffer *b, const struct dive &dive)
{
put_string(b, "\"Weights\":[");
const char *separator = "";
for (auto &ws: dive->weightsystems) {
for (auto &ws: dive.weightsystems) {
int grams = ws.weight.grams;
put_string(b, separator);
@ -125,14 +125,14 @@ static void put_weightsystem_HTML(struct membuffer *b, const struct dive *dive)
put_string(b, "],");
}
static void put_cylinder_HTML(struct membuffer *b, const struct dive *dive)
static void put_cylinder_HTML(struct membuffer *b, const struct dive &dive)
{
const char *separator = "\"Cylinders\":[";
if (dive->cylinders.empty())
if (dive.cylinders.empty())
put_string(b, separator);
for (auto &cyl: dive->cylinders) {
for (auto &cyl: dive.cylinders) {
put_format(b, "%s{", separator);
separator = ", ";
write_attribute(b, "Type", cyl.type.description.c_str(), ", ");
@ -172,25 +172,25 @@ static void put_cylinder_HTML(struct membuffer *b, const struct dive *dive)
}
static void put_HTML_samples(struct membuffer *b, const struct dive *dive)
static void put_HTML_samples(struct membuffer *b, const struct dive &dive)
{
put_format(b, "\"maxdepth\":%d,", dive->dcs[0].maxdepth.mm);
put_format(b, "\"duration\":%d,", dive->dcs[0].duration.seconds);
put_format(b, "\"maxdepth\":%d,", dive.dcs[0].maxdepth.mm);
put_format(b, "\"duration\":%d,", dive.dcs[0].duration.seconds);
if (dive->dcs[0].samples.empty())
if (dive.dcs[0].samples.empty())
return;
const char *separator = "\"samples\":[";
for (auto &s: dive->dcs[0].samples) {
for (auto &s: dive.dcs[0].samples) {
put_format(b, "%s[%d,%d,%d,%d]", separator, s.time.seconds, s.depth.mm, s.pressure[0].mbar, s.temperature.mkelvin);
separator = ", ";
}
put_string(b, "],");
}
static void put_HTML_coordinates(struct membuffer *b, const struct dive *dive)
static void put_HTML_coordinates(struct membuffer *b, const struct dive &dive)
{
struct dive_site *ds = get_dive_site_for_dive(dive);
struct dive_site *ds = get_dive_site_for_dive(&dive);
if (!ds)
return;
degrees_t latitude = ds->location.lat;
@ -206,10 +206,10 @@ static void put_HTML_coordinates(struct membuffer *b, const struct dive *dive)
put_string(b, "},");
}
void put_HTML_date(struct membuffer *b, const struct dive *dive, const char *pre, const char *post)
void put_HTML_date(struct membuffer *b, const struct dive &dive, const char *pre, const char *post)
{
struct tm tm;
utc_mkdate(dive->when, &tm);
utc_mkdate(dive.when, &tm);
put_format(b, "%s%04u-%02u-%02u%s", pre, tm.tm_year, tm.tm_mon + 1, tm.tm_mday, post);
}
@ -219,11 +219,11 @@ void put_HTML_quoted(struct membuffer *b, const char *text)
put_quoted(b, text, is_attribute, is_html);
}
void put_HTML_notes(struct membuffer *b, const struct dive *dive, const char *pre, const char *post)
void put_HTML_notes(struct membuffer *b, const struct dive &dive, const char *pre, const char *post)
{
put_string(b, pre);
if (!dive->notes.empty())
put_HTML_quoted(b, dive->notes.c_str());
if (!dive.notes.empty())
put_HTML_quoted(b, dive.notes.c_str());
else
put_string(b, "--");
put_string(b, post);
@ -263,24 +263,24 @@ void put_HTML_weight_units(struct membuffer *b, unsigned int grams, const char *
put_format(b, "%s%.1f %s%s", pre, value, unit, post);
}
void put_HTML_time(struct membuffer *b, const struct dive *dive, const char *pre, const char *post)
void put_HTML_time(struct membuffer *b, const struct dive &dive, const char *pre, const char *post)
{
struct tm tm;
utc_mkdate(dive->when, &tm);
utc_mkdate(dive.when, &tm);
put_format(b, "%s%02u:%02u:%02u%s", pre, tm.tm_hour, tm.tm_min, tm.tm_sec, post);
}
void put_HTML_depth(struct membuffer *b, const struct dive *dive, const char *pre, const char *post)
void put_HTML_depth(struct membuffer *b, const struct dive &dive, const char *pre, const char *post)
{
const char *unit;
double value;
const struct units *units_p = get_units();
if (!dive->maxdepth.mm) {
if (!dive.maxdepth.mm) {
put_format(b, "%s--%s", pre, post);
return;
}
value = get_depth_units(dive->maxdepth.mm, NULL, &unit);
value = get_depth_units(dive.maxdepth.mm, NULL, &unit);
switch (units_p->length) {
case units::METERS:
@ -293,41 +293,41 @@ void put_HTML_depth(struct membuffer *b, const struct dive *dive, const char *pr
}
}
void put_HTML_airtemp(struct membuffer *b, const struct dive *dive, const char *pre, const char *post)
void put_HTML_airtemp(struct membuffer *b, const struct dive &dive, const char *pre, const char *post)
{
const char *unit;
double value;
if (!dive->airtemp.mkelvin) {
if (!dive.airtemp.mkelvin) {
put_format(b, "%s--%s", pre, post);
return;
}
value = get_temp_units(dive->airtemp.mkelvin, &unit);
value = get_temp_units(dive.airtemp.mkelvin, &unit);
put_format(b, "%s%.1f %s%s", pre, value, unit, post);
}
void put_HTML_watertemp(struct membuffer *b, const struct dive *dive, const char *pre, const char *post)
void put_HTML_watertemp(struct membuffer *b, const struct dive &dive, const char *pre, const char *post)
{
const char *unit;
double value;
if (!dive->watertemp.mkelvin) {
if (!dive.watertemp.mkelvin) {
put_format(b, "%s--%s", pre, post);
return;
}
value = get_temp_units(dive->watertemp.mkelvin, &unit);
value = get_temp_units(dive.watertemp.mkelvin, &unit);
put_format(b, "%s%.1f %s%s", pre, value, unit, post);
}
static void put_HTML_tags(struct membuffer *b, const struct dive *dive, const char *pre, const char *post)
static void put_HTML_tags(struct membuffer *b, const struct dive &dive, const char *pre, const char *post)
{
put_string(b, pre);
if (dive->tags.empty())
if (dive.tags.empty())
put_string(b, "[\"--\"");
const char *separator = "[";
for (const divetag *tag: dive->tags) {
for (const divetag *tag: dive.tags) {
put_format(b, "%s\"", separator);
separator = ", ";
put_HTML_quoted(b, tag->name.c_str());
@ -338,30 +338,30 @@ static void put_HTML_tags(struct membuffer *b, const struct dive *dive, const ch
}
/* if exporting list_only mode, we neglect exporting the samples, bookmarks and cylinders */
static void write_one_dive(struct membuffer *b, const struct dive *dive, const char *photos_dir, int *dive_no, bool list_only)
static void write_one_dive(struct membuffer *b, const struct dive &dive, const char *photos_dir, int *dive_no, bool list_only)
{
put_string(b, "{");
put_format(b, "\"number\":%d,", *dive_no);
put_format(b, "\"subsurface_number\":%d,", dive->number);
put_format(b, "\"subsurface_number\":%d,", dive.number);
put_HTML_date(b, dive, "\"date\":\"", "\",");
put_HTML_time(b, dive, "\"time\":\"", "\",");
write_attribute(b, "location", get_dive_location(dive).c_str(), ", ");
write_attribute(b, "location", get_dive_location(&dive).c_str(), ", ");
put_HTML_coordinates(b, dive);
put_format(b, "\"rating\":%d,", dive->rating);
put_format(b, "\"visibility\":%d,", dive->visibility);
put_format(b, "\"current\":%d,", dive->current);
put_format(b, "\"wavesize\":%d,", dive->wavesize);
put_format(b, "\"surge\":%d,", dive->surge);
put_format(b, "\"chill\":%d,", dive->chill);
put_format(b, "\"rating\":%d,", dive.rating);
put_format(b, "\"visibility\":%d,", dive.visibility);
put_format(b, "\"current\":%d,", dive.current);
put_format(b, "\"wavesize\":%d,", dive.wavesize);
put_format(b, "\"surge\":%d,", dive.surge);
put_format(b, "\"chill\":%d,", dive.chill);
put_format(b, "\"dive_duration\":\"%u:%02u min\",",
FRACTION_TUPLE(dive->duration.seconds, 60));
FRACTION_TUPLE(dive.duration.seconds, 60));
put_string(b, "\"temperature\":{");
put_HTML_airtemp(b, dive, "\"air\":\"", "\",");
put_HTML_watertemp(b, dive, "\"water\":\"", "\"");
put_string(b, " },");
write_attribute(b, "buddy", dive->buddy.c_str(), ", ");
write_attribute(b, "diveguide", dive->diveguide.c_str(), ", ");
write_attribute(b, "suit", dive->suit.c_str(), ", ");
write_attribute(b, "buddy", dive.buddy.c_str(), ", ");
write_attribute(b, "diveguide", dive.diveguide.c_str(), ", ");
write_attribute(b, "suit", dive.suit.c_str(), ", ");
put_HTML_tags(b, dive, "\"tags\":", ",");
if (!list_only) {
put_cylinder_HTML(b, dive);
@ -380,12 +380,10 @@ static void write_one_dive(struct membuffer *b, const struct dive *dive, const c
static void write_no_trip(struct membuffer *b, int *dive_no, bool selected_only, const char *photos_dir, const bool list_only, char *sep)
{
int i;
const struct dive *dive;
const char *separator = "";
bool found_sel_dive = 0;
for_each_dive (i, dive) {
for (auto &dive: divelog.dives) {
// write dive if it doesn't belong to any trip and the dive is selected
// or we are in exporting all dives mode.
if (!dive->divetrip && (dive->selected || !selected_only)) {
@ -398,7 +396,7 @@ static void write_no_trip(struct membuffer *b, int *dive_no, bool selected_only,
}
put_string(b, separator);
separator = ", ";
write_one_dive(b, dive, photos_dir, dive_no, list_only);
write_one_dive(b, *dive, photos_dir, dive_no, list_only);
}
}
if (found_sel_dive)
@ -424,7 +422,7 @@ static void write_trip(struct membuffer *b, dive_trip *trip, int *dive_no, bool
}
put_string(b, separator);
separator = ", ";
write_one_dive(b, dive, photos_dir, dive_no, list_only);
write_one_dive(b, *dive, photos_dir, dive_no, list_only);
}
// close the trip object if contain dives.
@ -434,15 +432,14 @@ static void write_trip(struct membuffer *b, dive_trip *trip, int *dive_no, bool
static void write_trips(struct membuffer *b, const char *photos_dir, bool selected_only, const bool list_only)
{
int i, dive_no = 0;
const struct dive *dive;
int dive_no = 0;
char sep_ = ' ';
char *sep = &sep_;
for (auto &trip: *divelog.trips)
trip->saved = 0;
for_each_dive (i, dive) {
for (auto &dive: divelog.dives) {
dive_trip *trip = dive->divetrip;
/*Continue if the dive have no trips or we have seen this trip before*/

View file

@ -6,12 +6,12 @@
struct dive;
void put_HTML_date(struct membuffer *b, const struct dive *dive, const char *pre, const char *post);
void put_HTML_depth(struct membuffer *b, const struct dive *dive, const char *pre, const char *post);
void put_HTML_airtemp(struct membuffer *b, const struct dive *dive, const char *pre, const char *post);
void put_HTML_watertemp(struct membuffer *b, const struct dive *dive, const char *pre, const char *post);
void put_HTML_time(struct membuffer *b, const struct dive *dive, const char *pre, const char *post);
void put_HTML_notes(struct membuffer *b, const struct dive *dive, const char *pre, const char *post);
void put_HTML_date(struct membuffer *b, const struct dive &dive, const char *pre, const char *post);
void put_HTML_depth(struct membuffer *b, const struct dive &dive, const char *pre, const char *post);
void put_HTML_airtemp(struct membuffer *b, const struct dive &dive, const char *pre, const char *post);
void put_HTML_watertemp(struct membuffer *b, const struct dive &dive, const char *pre, const char *post);
void put_HTML_time(struct membuffer *b, const struct dive &dive, const char *pre, const char *post);
void put_HTML_notes(struct membuffer *b, const struct dive &dive, const char *pre, const char *post);
void put_HTML_quoted(struct membuffer *b, const char *text);
void put_HTML_pressure_units(struct membuffer *b, pressure_t pressure, const char *pre, const char *post);
void put_HTML_weight_units(struct membuffer *b, unsigned int grams, const char *pre, const char *post);

View file

@ -1,5 +1,7 @@
#include "core/save-profiledata.h"
#include "core/dive.h"
#include "core/divelist.h"
#include "core/divelog.h"
#include "core/profile.h"
#include "core/errorhelper.h"
#include "core/file.h"
@ -203,14 +205,12 @@ static void put_st_event(struct membuffer *b, const plot_data &entry, const plot
static void save_profiles_buffer(struct membuffer *b, bool select_only)
{
int i;
struct dive *dive;
struct deco_state *planner_deco_state = NULL;
for_each_dive(i, dive) {
for(auto &dive: divelog.dives) {
if (select_only && !dive->selected)
continue;
plot_info pi = create_plot_info_new(dive, &dive->dcs[0], planner_deco_state);
plot_info pi = create_plot_info_new(dive.get(), &dive->dcs[0], planner_deco_state);
put_headers(b, pi.nr_cylinders);
for (int i = 0; i < pi.nr; i++)

View file

@ -100,67 +100,67 @@ static void show_utf8_blanked(struct membuffer *b, const char *text, const char
show_utf8(b, copy.c_str(), pre, post, is_attribute);
}
static void save_depths(struct membuffer *b, struct divecomputer *dc)
static void save_depths(struct membuffer *b, const struct divecomputer &dc)
{
/* What's the point of this dive entry again? */
if (!dc->maxdepth.mm && !dc->meandepth.mm)
if (!dc.maxdepth.mm && !dc.meandepth.mm)
return;
put_string(b, " <depth");
put_depth(b, dc->maxdepth, " max='", " m'");
put_depth(b, dc->meandepth, " mean='", " m'");
put_depth(b, dc.maxdepth, " max='", " m'");
put_depth(b, dc.meandepth, " mean='", " m'");
put_string(b, " />\n");
}
static void save_dive_temperature(struct membuffer *b, struct dive *dive)
static void save_dive_temperature(struct membuffer *b, const struct dive &dive)
{
if (!dive->airtemp.mkelvin && !dive->watertemp.mkelvin)
if (!dive.airtemp.mkelvin && !dive.watertemp.mkelvin)
return;
if (dive->airtemp.mkelvin == dive->dc_airtemp().mkelvin && dive->watertemp.mkelvin == dive->dc_watertemp().mkelvin)
if (dive.airtemp.mkelvin == dive.dc_airtemp().mkelvin && dive.watertemp.mkelvin == dive.dc_watertemp().mkelvin)
return;
put_string(b, " <divetemperature");
if (dive->airtemp.mkelvin != dive->dc_airtemp().mkelvin)
put_temperature(b, dive->airtemp, " air='", " C'");
if (dive->watertemp.mkelvin != dive->dc_watertemp().mkelvin)
put_temperature(b, dive->watertemp, " water='", " C'");
if (dive.airtemp.mkelvin != dive.dc_airtemp().mkelvin)
put_temperature(b, dive.airtemp, " air='", " C'");
if (dive.watertemp.mkelvin != dive.dc_watertemp().mkelvin)
put_temperature(b, dive.watertemp, " water='", " C'");
put_string(b, "/>\n");
}
static void save_temperatures(struct membuffer *b, struct divecomputer *dc)
static void save_temperatures(struct membuffer *b, const struct divecomputer &dc)
{
if (!dc->airtemp.mkelvin && !dc->watertemp.mkelvin)
if (!dc.airtemp.mkelvin && !dc.watertemp.mkelvin)
return;
put_string(b, " <temperature");
put_temperature(b, dc->airtemp, " air='", " C'");
put_temperature(b, dc->watertemp, " water='", " C'");
put_temperature(b, dc.airtemp, " air='", " C'");
put_temperature(b, dc.watertemp, " water='", " C'");
put_string(b, " />\n");
}
static void save_airpressure(struct membuffer *b, struct divecomputer *dc)
static void save_airpressure(struct membuffer *b, const struct divecomputer &dc)
{
if (!dc->surface_pressure.mbar)
if (!dc.surface_pressure.mbar)
return;
put_string(b, " <surface");
put_pressure(b, dc->surface_pressure, " pressure='", " bar'");
put_pressure(b, dc.surface_pressure, " pressure='", " bar'");
put_string(b, " />\n");
}
static void save_salinity(struct membuffer *b, struct divecomputer *dc)
static void save_salinity(struct membuffer *b, const struct divecomputer &dc)
{
if (!dc->salinity)
if (!dc.salinity)
return;
put_string(b, " <water");
put_salinity(b, dc->salinity, " salinity='", " g/l'");
put_salinity(b, dc.salinity, " salinity='", " g/l'");
put_string(b, " />\n");
}
static void save_overview(struct membuffer *b, struct dive *dive, bool anonymize)
static void save_overview(struct membuffer *b, const struct dive &dive, bool anonymize)
{
show_utf8_blanked(b, dive->diveguide.c_str(), " <divemaster>", "</divemaster>\n", 0, anonymize);
show_utf8_blanked(b, dive->buddy.c_str(), " <buddy>", "</buddy>\n", 0, anonymize);
show_utf8_blanked(b, dive->notes.c_str(), " <notes>", "</notes>\n", 0, anonymize);
show_utf8_blanked(b, dive->suit.c_str(), " <suit>", "</suit>\n", 0, anonymize);
show_utf8_blanked(b, dive.diveguide.c_str(), " <divemaster>", "</divemaster>\n", 0, anonymize);
show_utf8_blanked(b, dive.buddy.c_str(), " <buddy>", "</buddy>\n", 0, anonymize);
show_utf8_blanked(b, dive.notes.c_str(), " <notes>", "</notes>\n", 0, anonymize);
show_utf8_blanked(b, dive.suit.c_str(), " <suit>", "</suit>\n", 0, anonymize);
}
static void put_gasmix(struct membuffer *b, struct gasmix mix)
@ -175,9 +175,9 @@ static void put_gasmix(struct membuffer *b, struct gasmix mix)
}
}
static void save_cylinder_info(struct membuffer *b, struct dive *dive)
static void save_cylinder_info(struct membuffer *b, const struct dive &dive)
{
for (auto &cyl: dive->cylinders) {
for (auto &cyl: dive.cylinders) {
int volume = cyl.type.size.mliter;
int use = cyl.cylinder_use;
@ -197,9 +197,9 @@ static void save_cylinder_info(struct membuffer *b, struct dive *dive)
}
}
static void save_weightsystem_info(struct membuffer *b, const struct dive *dive)
static void save_weightsystem_info(struct membuffer *b, const struct dive &dive)
{
for (auto &ws: dive->weightsystems) {
for (auto &ws: dive.weightsystems) {
int grams = ws.weight.grams;
put_format(b, " <weightsystem");
@ -341,7 +341,7 @@ static void save_sample(struct membuffer *b, const struct sample &sample, struct
put_format(b, " />\n");
}
static void save_one_event(struct membuffer *b, struct dive *dive, const struct event &ev)
static void save_one_event(struct membuffer *b, const struct dive &dive, const struct event &ev)
{
put_format(b, " <event time='%d:%02d min'", FRACTION_TUPLE(ev.time.seconds, 60));
show_index(b, ev.type, "type='", "'");
@ -352,7 +352,7 @@ static void save_one_event(struct membuffer *b, struct dive *dive, const struct
show_index(b, ev.value, "value='", "'");
show_utf8(b, ev.name.c_str(), " name='", "'", 1);
if (ev.is_gaschange()) {
struct gasmix mix = get_gasmix_from_event(dive, ev);
struct gasmix mix = get_gasmix_from_event(&dive, ev);
if (ev.gas.index >= 0)
show_integer(b, ev.gas.index, "cylinder='", "'");
put_gasmix(b, mix);
@ -361,9 +361,9 @@ static void save_one_event(struct membuffer *b, struct dive *dive, const struct
}
static void save_events(struct membuffer *b, struct dive *dive, const struct divecomputer *dc)
static void save_events(struct membuffer *b, const struct dive &dive, const struct divecomputer &dc)
{
for (auto &ev: dc->events)
for (auto &ev: dc.events)
save_one_event(b, dive, ev);
}
@ -381,9 +381,9 @@ static void save_tags(struct membuffer *b, const tag_list &tags)
}
}
static void save_extra_data(struct membuffer *b, const struct divecomputer *dc)
static void save_extra_data(struct membuffer *b, const struct divecomputer &dc)
{
for (const auto &ed: dc->extra_data) {
for (const auto &ed: dc.extra_data) {
if (!ed.key.empty() && !ed.value.empty()) {
put_string(b, " <extradata");
show_utf8(b, ed.key.c_str(), " key='", "'", 1);
@ -406,49 +406,48 @@ static void show_date(struct membuffer *b, timestamp_t when)
tm.tm_hour, tm.tm_min, tm.tm_sec);
}
static void save_samples(struct membuffer *b, struct dive *dive, struct divecomputer *dc)
static void save_samples(struct membuffer *b, const struct dive &dive, const struct divecomputer &dc)
{
int o2sensor;
struct sample dummy;
/* Set up default pressure sensor indices */
o2sensor = legacy_format_o2pressures(dive, dc);
int o2sensor = legacy_format_o2pressures(&dive, &dc);
if (o2sensor >= 0) {
dummy.sensor[0] = !o2sensor;
dummy.sensor[1] = o2sensor;
}
for (const auto &s: dc->samples)
for (const auto &s: dc.samples)
save_sample(b, s, dummy, o2sensor);
}
static void save_dc(struct membuffer *b, struct dive *dive, struct divecomputer *dc)
static void save_dc(struct membuffer *b, const struct dive &dive, const struct divecomputer &dc)
{
put_format(b, " <divecomputer");
show_utf8(b, dc->model.c_str(), " model='", "'", 1);
if (dc->last_manual_time.seconds)
put_duration(b, dc->last_manual_time, " last-manual-time='", " min'");
if (dc->deviceid)
put_format(b, " deviceid='%08x'", dc->deviceid);
if (dc->diveid)
put_format(b, " diveid='%08x'", dc->diveid);
if (dc->when && dc->when != dive->when)
show_date(b, dc->when);
if (dc->duration.seconds && dc->duration.seconds != dive->dcs[0].duration.seconds)
put_duration(b, dc->duration, " duration='", " min'");
if (dc->divemode != OC) {
int i = (int)dc->divemode;
show_utf8(b, dc.model.c_str(), " model='", "'", 1);
if (dc.last_manual_time.seconds)
put_duration(b, dc.last_manual_time, " last-manual-time='", " min'");
if (dc.deviceid)
put_format(b, " deviceid='%08x'", dc.deviceid);
if (dc.diveid)
put_format(b, " diveid='%08x'", dc.diveid);
if (dc.when && dc.when != dive.when)
show_date(b, dc.when);
if (dc.duration.seconds && dc.duration.seconds != dive.dcs[0].duration.seconds)
put_duration(b, dc.duration, " duration='", " min'");
if (dc.divemode != OC) {
int i = (int)dc.divemode;
if (i >= 0 && i < NUM_DIVEMODE)
show_utf8(b, divemode_text[i], " dctype='", "'", 1);
if (dc->no_o2sensors)
put_format(b," no_o2sensors='%d'", dc->no_o2sensors);
if (dc.no_o2sensors)
put_format(b," no_o2sensors='%d'", dc.no_o2sensors);
}
put_format(b, ">\n");
save_depths(b, dc);
save_temperatures(b, dc);
save_airpressure(b, dc);
save_salinity(b, dc);
put_duration(b, dc->surfacetime, " <surfacetime>", " min</surfacetime>\n");
put_duration(b, dc.surfacetime, " <surfacetime>", " min</surfacetime>\n");
save_extra_data(b, dc);
save_events(b, dive, dc);
save_samples(b, dive, dc);
@ -475,50 +474,50 @@ static void save_picture(struct membuffer *b, const struct picture &pic)
put_string(b, "/>\n");
}
void save_one_dive_to_mb(struct membuffer *b, struct dive *dive, bool anonymize)
void save_one_dive_to_mb(struct membuffer *b, const struct dive &dive, bool anonymize)
{
pressure_t surface_pressure = un_fixup_surface_pressure(dive);
pressure_t surface_pressure = un_fixup_surface_pressure(&dive);
put_string(b, "<dive");
if (dive->number)
put_format(b, " number='%d'", dive->number);
if (dive->notrip)
if (dive.number)
put_format(b, " number='%d'", dive.number);
if (dive.notrip)
put_format(b, " tripflag='NOTRIP'");
if (dive->rating)
put_format(b, " rating='%d'", dive->rating);
if (dive->visibility)
put_format(b, " visibility='%d'", dive->visibility);
if (dive->wavesize)
put_format(b, " wavesize='%d'", dive->wavesize);
if (dive->current)
put_format(b, " current='%d'", dive->current);
if (dive->surge)
put_format(b, " surge='%d'", dive->surge);
if (dive->chill)
put_format(b, " chill='%d'", dive->chill);
if (dive->invalid)
if (dive.rating)
put_format(b, " rating='%d'", dive.rating);
if (dive.visibility)
put_format(b, " visibility='%d'", dive.visibility);
if (dive.wavesize)
put_format(b, " wavesize='%d'", dive.wavesize);
if (dive.current)
put_format(b, " current='%d'", dive.current);
if (dive.surge)
put_format(b, " surge='%d'", dive.surge);
if (dive.chill)
put_format(b, " chill='%d'", dive.chill);
if (dive.invalid)
put_format(b, " invalid='1'");
// These three are calculated, and not read when loading.
// But saving them into the XML is useful for data export.
if (dive->sac > 100)
put_format(b, " sac='%d.%03d l/min'", FRACTION_TUPLE(dive->sac, 1000));
if (dive->otu)
put_format(b, " otu='%d'", dive->otu);
if (dive->maxcns)
put_format(b, " cns='%d%%'", dive->maxcns);
if (dive.sac > 100)
put_format(b, " sac='%d.%03d l/min'", FRACTION_TUPLE(dive.sac, 1000));
if (dive.otu)
put_format(b, " otu='%d'", dive.otu);
if (dive.maxcns)
put_format(b, " cns='%d%%'", dive.maxcns);
save_tags(b, dive->tags);
if (dive->dive_site)
put_format(b, " divesiteid='%8x'", dive->dive_site->uuid);
if (dive->user_salinity)
put_salinity(b, dive->user_salinity, " watersalinity='", " g/l'");
show_date(b, dive->when);
save_tags(b, dive.tags);
if (dive.dive_site)
put_format(b, " divesiteid='%8x'", dive.dive_site->uuid);
if (dive.user_salinity)
put_salinity(b, dive.user_salinity, " watersalinity='", " g/l'");
show_date(b, dive.when);
if (surface_pressure.mbar)
put_pressure(b, surface_pressure, " airpressure='", " bar'");
if (dive->dcs[0].duration.seconds > 0)
if (dive.dcs[0].duration.seconds > 0)
put_format(b, " duration='%u:%02u min'>\n",
FRACTION_TUPLE(dive->dcs[0].duration.seconds, 60));
FRACTION_TUPLE(dive.dcs[0].duration.seconds, 60));
else
put_format(b, ">\n");
save_overview(b, dive, anonymize);
@ -526,14 +525,14 @@ void save_one_dive_to_mb(struct membuffer *b, struct dive *dive, bool anonymize)
save_weightsystem_info(b, dive);
save_dive_temperature(b, dive);
/* Save the dive computer data */
for (auto &dc: dive->dcs)
save_dc(b, dive, &dc);
for (auto &picture: dive->pictures)
for (auto &dc: dive.dcs)
save_dc(b, dive, dc);
for (auto &picture: dive.pictures)
save_picture(b, picture);
put_format(b, "</dive>\n");
}
int save_dive(FILE *f, struct dive *dive, bool anonymize)
int save_dive(FILE *f, const struct dive &dive, bool anonymize)
{
membuffer buf;
@ -545,9 +544,6 @@ int save_dive(FILE *f, struct dive *dive, bool anonymize)
static void save_trip(struct membuffer *b, dive_trip &trip, bool anonymize)
{
int i;
struct dive *dive;
put_format(b, "<trip");
show_date(b, trip_date(trip));
show_utf8(b, trip.location.c_str(), " location=\'", "\'", 1);
@ -560,9 +556,9 @@ static void save_trip(struct membuffer *b, dive_trip &trip, bool anonymize)
* list in the trip, we just traverse the global dive array and
* check the divetrip pointer..
*/
for_each_dive(i, dive) {
for (auto &dive: divelog.dives) {
if (dive->divetrip == &trip)
save_one_dive_to_mb(b, dive, anonymize);
save_one_dive_to_mb(b, *dive, anonymize);
}
put_format(b, "</trip>\n");
@ -640,9 +636,6 @@ static void save_filter_presets(struct membuffer *b)
static void save_dives_buffer(struct membuffer *b, bool select_only, bool anonymize)
{
int i;
struct dive *dive;
put_format(b, "<divelog program='subsurface' version='%d'>\n<settings>\n", DATAFORMAT_VERSION);
/* save the dive computer nicknames, if any */
@ -692,19 +685,17 @@ static void save_dives_buffer(struct membuffer *b, bool select_only, bool anonym
save_filter_presets(b);
/* save the dives */
for_each_dive(i, dive) {
for (auto &dive: divelog.dives) {
if (select_only) {
if (!dive->selected)
continue;
save_one_dive_to_mb(b, dive, anonymize);
save_one_dive_to_mb(b, *dive, anonymize);
} else {
dive_trip *trip = dive->divetrip;
/* Bare dive without a trip? */
if (!trip) {
save_one_dive_to_mb(b, dive, anonymize);
save_one_dive_to_mb(b, *dive, anonymize);
continue;
}

View file

@ -16,32 +16,20 @@ static int amount_trips_selected;
struct dive *first_selected_dive()
{
int idx;
struct dive *d;
for_each_dive (idx, d) {
if (d->selected)
return d;
}
return NULL;
auto it = std::find_if(divelog.dives.begin(), divelog.dives.end(),
[](auto &d) { return d->selected; });
return it != divelog.dives.end() ? it->get() : nullptr;
}
struct dive *last_selected_dive()
{
int idx;
struct dive *d, *ret = NULL;
for_each_dive (idx, d) {
if (d->selected)
ret = d;
}
return ret;
auto it = std::find_if(divelog.dives.rbegin(), divelog.dives.rend(),
[](auto &d) { return d->selected; });
return it != divelog.dives.rend() ? it->get() : nullptr;
}
bool consecutive_selected()
{
struct dive *d;
int i;
bool consecutive = true;
bool firstfound = false;
bool lastfound = false;
@ -49,7 +37,7 @@ bool consecutive_selected()
if (amount_selected == 0 || amount_selected == 1)
return true;
for_each_dive(i, d) {
for (auto &d: divelog.dives) {
if (d->selected) {
if (!firstfound)
firstfound = true;
@ -65,11 +53,8 @@ bool consecutive_selected()
#if DEBUG_SELECTION_TRACKING
void dump_selection()
{
int i;
struct dive *dive;
printf("currently selected are %u dives:", amount_selected);
for_each_dive(i, dive) {
for (auto &dive: divelog.dives) {
if (dive->selected)
printf(" %d", i);
}
@ -137,10 +122,8 @@ QVector<dive *> setSelectionCore(const std::vector<dive *> &selection, dive *cur
divesToSelect.reserve(selection.size());
// TODO: We might want to keep track of selected dives in a more efficient way!
int i;
dive *d;
amount_selected = 0; // We recalculate amount_selected
for_each_dive(i, d) {
for (auto &d: divelog.dives) {
// We only modify dives that are currently visible.
if (d->hidden_by_filter) {
d->selected = false; // Note, not necessary, just to be sure
@ -150,11 +133,11 @@ QVector<dive *> setSelectionCore(const std::vector<dive *> &selection, dive *cur
// Search the dive in the list of selected dives.
// TODO: By sorting the list in the same way as the backend, this could be made more efficient.
bool newState = std::find(selection.begin(), selection.end(), d) != selection.end();
bool newState = std::find(selection.begin(), selection.end(), d.get()) != selection.end();
if (newState) {
++amount_selected;
divesToSelect.push_back(d);
divesToSelect.push_back(d.get());
}
d->selected = newState;
}
@ -217,10 +200,8 @@ void setTripSelection(dive_trip *trip, dive *currentDive)
return;
current_dive = currentDive;
for (int i = 0; i < divelog.dives->nr; ++i) {
dive &d = *divelog.dives->dives[i];
d.selected = d.divetrip == trip;
}
for (auto &d: divelog.dives)
d->selected = d->divetrip == trip;
for (auto &t: *divelog.trips)
t->selected = t.get() == trip;
@ -245,11 +226,9 @@ std::vector<dive *> getDiveSelection()
std::vector<dive *> res;
res.reserve(amount_selected);
int i;
dive *d;
for_each_dive(i, d) {
for (auto &d: divelog.dives) {
if (d->selected)
res.push_back(d);
res.push_back(d.get());
}
return res;
}
@ -257,7 +236,7 @@ std::vector<dive *> getDiveSelection()
bool diveInSelection(const std::vector<dive *> &selection, const dive *d)
{
// Do a binary search using the ordering of the dive list.
auto it = std::lower_bound(selection.begin(), selection.end(), d, dive_less_than);
auto it = std::lower_bound(selection.begin(), selection.end(), d, dive_less_than_ptr);
return it != selection.end() && *it == d;
}
@ -265,7 +244,7 @@ void updateSelection(std::vector<dive *> &selection, const std::vector<dive *> &
{
// We could sort the array and merge the vectors as we do in the undo code. But is it necessary?
for (dive *d: add) {
auto it = std::lower_bound(selection.begin(), selection.end(), d, dive_less_than);
auto it = std::lower_bound(selection.begin(), selection.end(), d, dive_less_than_ptr);
if (it != selection.end() && *it == d)
continue; // Ooops. Already there?
selection.insert(it, d);
@ -273,7 +252,7 @@ void updateSelection(std::vector<dive *> &selection, const std::vector<dive *> &
// Likewise, we could sort the array and be smarter here. Again, is it necessary?
for (dive *d: remove) {
auto it = std::lower_bound(selection.begin(), selection.end(), d, dive_less_than);
auto it = std::lower_bound(selection.begin(), selection.end(), d, dive_less_than_ptr);
if (it == selection.end() || *it != d)
continue; // Ooops. Not there?
selection.erase(it);
@ -283,10 +262,9 @@ void updateSelection(std::vector<dive *> &selection, const std::vector<dive *> &
// Select the first dive that is visible
void select_newest_visible_dive()
{
for (int i = divelog.dives->nr - 1; i >= 0; --i) {
dive *d = divelog.dives->dives[i];
if (!d->hidden_by_filter)
return select_single_dive(d);
for (auto it = divelog.dives.rbegin(); it != divelog.dives.rend(); ++it) {
if (!(*it)->hidden_by_filter)
return select_single_dive(it->get());
}
// No visible dive -> deselect all

View file

@ -19,15 +19,15 @@
#include <string.h>
#include <ctype.h>
static void process_temperatures(struct dive *dp, stats_t &stats)
static void process_temperatures(const struct dive &dp, stats_t &stats)
{
temperature_t min_temp, mean_temp, max_temp = {.mkelvin = 0};
max_temp.mkelvin = dp->maxtemp.mkelvin;
max_temp.mkelvin = dp.maxtemp.mkelvin;
if (max_temp.mkelvin && (!stats.max_temp.mkelvin || max_temp.mkelvin > stats.max_temp.mkelvin))
stats.max_temp.mkelvin = max_temp.mkelvin;
min_temp.mkelvin = dp->mintemp.mkelvin;
min_temp.mkelvin = dp.mintemp.mkelvin;
if (min_temp.mkelvin && (!stats.min_temp.mkelvin || min_temp.mkelvin < stats.min_temp.mkelvin))
stats.min_temp.mkelvin = min_temp.mkelvin;
@ -42,10 +42,10 @@ static void process_temperatures(struct dive *dp, stats_t &stats)
}
}
static void process_dive(struct dive *dive, stats_t &stats)
static void process_dive(const struct dive &dive, stats_t &stats)
{
int old_tadt, sac_time = 0;
int32_t duration = dive->duration.seconds;
int32_t duration = dive.duration.seconds;
old_tadt = stats.total_average_depth_time.seconds;
stats.total_time.seconds += duration;
@ -53,32 +53,32 @@ static void process_dive(struct dive *dive, stats_t &stats)
stats.longest_time.seconds = duration;
if (stats.shortest_time.seconds == 0 || duration < stats.shortest_time.seconds)
stats.shortest_time.seconds = duration;
if (dive->maxdepth.mm > stats.max_depth.mm)
stats.max_depth.mm = dive->maxdepth.mm;
if (stats.min_depth.mm == 0 || dive->maxdepth.mm < stats.min_depth.mm)
stats.min_depth.mm = dive->maxdepth.mm;
stats.combined_max_depth.mm += dive->maxdepth.mm;
if (dive.maxdepth.mm > stats.max_depth.mm)
stats.max_depth.mm = dive.maxdepth.mm;
if (stats.min_depth.mm == 0 || dive.maxdepth.mm < stats.min_depth.mm)
stats.min_depth.mm = dive.maxdepth.mm;
stats.combined_max_depth.mm += dive.maxdepth.mm;
process_temperatures(dive, stats);
/* Maybe we should drop zero-duration dives */
if (!duration)
return;
if (dive->meandepth.mm) {
if (dive.meandepth.mm) {
stats.total_average_depth_time.seconds += duration;
stats.avg_depth.mm = lrint((1.0 * old_tadt * stats.avg_depth.mm +
duration * dive->meandepth.mm) /
duration * dive.meandepth.mm) /
stats.total_average_depth_time.seconds);
}
if (dive->sac > 100) { /* less than .1 l/min is bogus, even with a pSCR */
if (dive.sac > 100) { /* less than .1 l/min is bogus, even with a pSCR */
sac_time = stats.total_sac_time.seconds + duration;
stats.avg_sac.mliter = lrint((1.0 * stats.total_sac_time.seconds * stats.avg_sac.mliter +
duration * dive->sac) /
duration * dive.sac) /
sac_time);
if (dive->sac > stats.max_sac.mliter)
stats.max_sac.mliter = dive->sac;
if (stats.min_sac.mliter == 0 || dive->sac < stats.min_sac.mliter)
stats.min_sac.mliter = dive->sac;
if (dive.sac > stats.max_sac.mliter)
stats.max_sac.mliter = dive.sac;
if (stats.min_sac.mliter == 0 || dive.sac < stats.min_sac.mliter)
stats.min_sac.mliter = dive.sac;
stats.total_sac_time.seconds = sac_time;
}
}
@ -91,8 +91,6 @@ static void process_dive(struct dive *dive, stats_t &stats)
*/
stats_summary calculate_stats_summary(bool selected_only)
{
int idx;
struct dive *dp;
struct tm tm;
int current_year = -1;
int current_month = 0;
@ -128,7 +126,7 @@ stats_summary calculate_stats_summary(bool selected_only)
/* this relies on the fact that the dives in the dive_table
* are in chronological order */
for_each_dive (idx, dp) {
for (auto &dp: divelog.dives) {
if (selected_only && !dp->selected)
continue;
if (dp->invalid)
@ -143,34 +141,34 @@ stats_summary calculate_stats_summary(bool selected_only)
out.stats_yearly.emplace_back();
out.stats_yearly.back().is_year = true;
}
process_dive(dp, out.stats_yearly.back());
process_dive(*dp, out.stats_yearly.back());
out.stats_yearly.back().selection_size++;
out.stats_yearly.back().period = current_year;
/* stats_by_type[0] is all the dives combined */
out.stats_by_type[0].selection_size++;
process_dive(dp, out.stats_by_type[0]);
process_dive(*dp, out.stats_by_type[0]);
process_dive(dp, out.stats_by_type[dp->dcs[0].divemode + 1]);
process_dive(*dp, out.stats_by_type[dp->dcs[0].divemode + 1]);
out.stats_by_type[dp->dcs[0].divemode + 1].selection_size++;
/* stats_by_depth[0] is all the dives combined */
out.stats_by_depth[0].selection_size++;
process_dive(dp, out.stats_by_depth[0]);
process_dive(*dp, out.stats_by_depth[0]);
int d_idx = dp->maxdepth.mm / (STATS_DEPTH_BUCKET * 1000);
d_idx = std::clamp(d_idx, 0, STATS_MAX_DEPTH / STATS_DEPTH_BUCKET);
process_dive(dp, out.stats_by_depth[d_idx + 1]);
process_dive(*dp, out.stats_by_depth[d_idx + 1]);
out.stats_by_depth[d_idx + 1].selection_size++;
/* stats_by_temp[0] is all the dives combined */
out.stats_by_temp[0].selection_size++;
process_dive(dp, out.stats_by_temp[0]);
process_dive(*dp, out.stats_by_temp[0]);
int t_idx = ((int)mkelvin_to_C(dp->mintemp.mkelvin)) / STATS_TEMP_BUCKET;
t_idx = std::clamp(t_idx, 0, STATS_MAX_TEMP / STATS_TEMP_BUCKET);
process_dive(dp, out.stats_by_temp[t_idx + 1]);
process_dive(*dp, out.stats_by_temp[t_idx + 1]);
out.stats_by_temp[t_idx + 1].selection_size++;
if (dp->divetrip != NULL) {
@ -182,11 +180,11 @@ stats_summary calculate_stats_summary(bool selected_only)
/* stats_by_trip[0] is all the dives combined */
/* TODO: yet, this doesn't seem to consider dives outside of trips !? */
out.stats_by_trip[0].selection_size++;
process_dive(dp, out.stats_by_trip[0]);
process_dive(*dp, out.stats_by_trip[0]);
out.stats_by_trip[0].is_trip = true;
out.stats_by_trip[0].location = translate("gettextFromC", "All (by trip stats)");
process_dive(dp, out.stats_by_trip.back());
process_dive(*dp, out.stats_by_trip.back());
out.stats_by_trip.back().selection_size++;
out.stats_by_trip.back().is_trip = true;
out.stats_by_trip.back().location = dp->divetrip->location;
@ -202,7 +200,7 @@ stats_summary calculate_stats_summary(bool selected_only)
if (prev_month != current_month || prev_year != current_year)
out.stats_monthly.emplace_back();
}
process_dive(dp, out.stats_monthly.back());
process_dive(*dp, out.stats_monthly.back());
out.stats_monthly.back().selection_size++;
out.stats_monthly.back().period = current_month;
prev_month = current_month;
@ -230,25 +228,18 @@ stats_summary calculate_stats_summary(bool selected_only)
return out;
}
stats_summary::stats_summary()
{
}
stats_summary::~stats_summary()
{
}
stats_summary::stats_summary() = default;
stats_summary::~stats_summary() = default;
/* make sure we skip the selected summary entries */
stats_t calculate_stats_selected()
{
stats_t stats_selection;
struct dive *dive;
unsigned int i, nr;
unsigned int nr = 0;
nr = 0;
for_each_dive(i, dive) {
for (auto &dive: divelog.dives) {
if (dive->selected && !dive->invalid) {
process_dive(dive, stats_selection);
process_dive(*dive, stats_selection);
nr++;
}
}
@ -336,16 +327,14 @@ static std::pair<volume_t, volume_t> get_gas_parts(struct gasmix mix, volume_t v
std::pair<volume_t, volume_t> selected_dives_gas_parts()
{
int i;
struct dive *d;
volume_t o2_tot, he_tot;
for_each_dive (i, d) {
for (auto &d: divelog.dives) {
if (!d->selected || d->invalid)
continue;
int j = 0;
for (auto &gas: get_gas_used(d)) {
for (auto &gas: get_gas_used(d.get())) {
if (gas.mliter) {
auto [o2, he] = get_gas_parts(get_cylinder(d, j)->gasmix, gas, O2_IN_AIR);
auto [o2, he] = get_gas_parts(get_cylinder(d.get(), j)->gasmix, gas, O2_IN_AIR);
o2_tot.mliter += o2.mliter;
he_tot.mliter += he.mliter;
}

View file

@ -1,5 +1,7 @@
#include "string-format.h"
#include "dive.h"
#include "divelist.h"
#include "divelog.h"
#include "divesite.h"
#include "event.h"
#include "format.h"
@ -135,9 +137,7 @@ static void addStringToSortedList(QStringList &l, const std::string &s)
QStringList formatFullCylinderList()
{
QStringList cylinders;
struct dive *d;
int i = 0;
for_each_dive (i, d) {
for (auto &d: divelog.dives) {
for (const cylinder_t &cyl: d->cylinders)
addStringToSortedList(cylinders, cyl.type.description);
}

View file

@ -50,22 +50,6 @@ static timestamp_t trip_enddate(const struct dive_trip &trip)
return trip.dives.back()->endtime();
}
/* check if we have a trip right before / after this dive */
bool is_trip_before_after(const struct dive *dive, bool before)
{
int idx = get_idx_by_uniq_id(dive->id);
if (before) {
const struct dive *d = get_dive(idx - 1);
if (d && d->divetrip)
return true;
} else {
const struct dive *d = get_dive(idx + 1);
if (d && d->divetrip)
return true;
}
return false;
}
/* Add dive to a trip. Caller is responsible for removing dive
* from trip beforehand. */
void add_dive_to_trip(struct dive *dive, dive_trip *trip)
@ -73,8 +57,8 @@ void add_dive_to_trip(struct dive *dive, dive_trip *trip)
if (dive->divetrip == trip)
return;
if (dive->divetrip)
report_info("Warning: adding dive to trip that has trip set\n");
range_insert_sorted(trip->dives, dive, comp_dives);
report_info("Warning: adding dive to trip, which already has a trip set");
range_insert_sorted(trip->dives, dive, comp_dives_ptr);
dive->divetrip = trip;
}
@ -112,13 +96,10 @@ std::unique_ptr<dive_trip> create_trip_from_dive(const struct dive *dive)
* exist, allocate a new trip. A unique_ptr is returned if a new trip
* was allocated. The caller has to store it.
*/
std::pair<dive_trip *, std::unique_ptr<dive_trip>> get_trip_for_new_dive(const struct dive *new_dive)
std::pair<dive_trip *, std::unique_ptr<dive_trip>> get_trip_for_new_dive(const struct divelog &log, const struct dive *new_dive)
{
dive *d;
int i;
/* Find dive that is within TRIP_THRESHOLD of current dive */
for_each_dive(i, d) {
for (auto &d: log.dives) {
/* Check if we're past the range of possible dives */
if (d->when >= new_dive->when + TRIP_THRESHOLD)
break;
@ -164,7 +145,7 @@ bool trips_overlap(const struct dive_trip &t1, const struct dive_trip &t2)
* manually injects the new trips. If there are no dives to be autogrouped,
* return NULL.
*/
std::vector<dives_to_autogroup_result> get_dives_to_autogroup(struct dive_table *table)
std::vector<dives_to_autogroup_result> get_dives_to_autogroup(const struct dive_table &table)
{
std::vector<dives_to_autogroup_result> res;
struct dive *lastdive = NULL;
@ -172,12 +153,11 @@ std::vector<dives_to_autogroup_result> get_dives_to_autogroup(struct dive_table
/* Find first dive that should be merged and remember any previous
* dive that could be merged into.
*/
for (int i = 0; i < table->nr; ++i) {
struct dive *dive = table->dives[i];
dive_trip *trip;
for (size_t i = 0; i < table.size(); ++i) {
auto &dive = table[i];
if (dive->divetrip) {
lastdive = dive;
lastdive = dive.get();
continue;
}
@ -190,9 +170,10 @@ std::vector<dives_to_autogroup_result> get_dives_to_autogroup(struct dive_table
/* We found a dive, let's see if we have to allocate a new trip */
std::unique_ptr<dive_trip> allocated;
dive_trip *trip;
if (!lastdive || dive->when >= lastdive->when + TRIP_THRESHOLD) {
/* allocate new trip */
allocated = create_trip_from_dive(dive);
allocated = create_trip_from_dive(dive.get());
allocated->autogen = true;
trip = allocated.get();
} else {
@ -201,16 +182,16 @@ std::vector<dives_to_autogroup_result> get_dives_to_autogroup(struct dive_table
}
// Now, find all dives that will be added to this trip
lastdive = dive;
int to;
for (to = i + 1; to < table->nr; to++) {
dive = table->dives[to];
lastdive = dive.get();
size_t to;
for (to = i + 1; to < table.size(); to++) {
auto &dive = table[to];
if (dive->divetrip || dive->notrip ||
dive->when >= lastdive->when + TRIP_THRESHOLD)
break;
if (trip->location.empty())
trip->location = get_dive_location(dive);
lastdive = dive;
trip->location = get_dive_location(dive.get());
lastdive = dive.get();
}
res.push_back({ i, to, trip, std::move(allocated) });
i = to - 1;
@ -250,7 +231,7 @@ int comp_trips(const struct dive_trip &a, const struct dive_trip &b)
return -1;
if (b.dives.empty())
return 1;
return comp_dives(a.dives[0], b.dives[0]);
return comp_dives(*a.dives[0], *b.dives[0]);
}
static bool is_same_day(timestamp_t trip_when, timestamp_t dive_when)
@ -285,5 +266,5 @@ int trip_shown_dives(const struct dive_trip *trip)
void dive_trip::sort_dives()
{
std::sort(dives.begin(), dives.end(), [] (dive *d1, dive *d2) { return comp_dives(d1, d2) < 0; });
std::sort(dives.begin(), dives.end(), [] (dive *d1, dive *d2) { return comp_dives(*d1, *d2) < 0; });
}

View file

@ -3,9 +3,8 @@
#define TRIP_H
#include "divelist.h"
#include "owning_table.h"
#include <string>
struct divelog;
struct dive_trip
{
@ -26,10 +25,6 @@ struct dive_trip
int comp_trips(const dive_trip &t1, const dive_trip &t2);
struct trip_table : public sorted_owning_table<dive_trip, &comp_trips> {
dive_trip *get_by_uniq_id(int tripId) const;
};
extern void add_dive_to_trip(struct dive *, dive_trip *);
extern struct dive_trip *unregister_dive_from_trip(struct dive *dive);
@ -40,18 +35,17 @@ extern dive_trip *create_and_hookup_trip_from_dive(const struct dive *dive, stru
// Result item of get_dives_to_autogroup()
struct dives_to_autogroup_result {
int from, to; // Group dives in the range [from, to)
size_t from, to; // Group dives in the range [from, to)
dive_trip *trip; // Pointer to trip
std::unique_ptr<dive_trip> created_trip;
// Is set if the trip was newly created - caller has to store it.
};
extern std::vector<dives_to_autogroup_result> get_dives_to_autogroup(struct dive_table *table);
extern std::pair<dive_trip *, std::unique_ptr<dive_trip>> get_trip_for_new_dive(const struct dive *new_dive);
extern std::vector<dives_to_autogroup_result> get_dives_to_autogroup(const struct dive_table &table);
extern std::pair<dive_trip *, std::unique_ptr<dive_trip>> get_trip_for_new_dive(const struct divelog &log, const struct dive *new_dive);
extern bool trips_overlap(const struct dive_trip &t1, const struct dive_trip &t2);
extern std::unique_ptr<dive_trip> combine_trips(struct dive_trip *trip_a, struct dive_trip *trip_b);
extern bool is_trip_before_after(const struct dive *dive, bool before);
extern bool trip_is_single_day(const struct dive_trip &trip);
extern int trip_shown_dives(const struct dive_trip *trip);
@ -59,10 +53,9 @@ extern int trip_shown_dives(const struct dive_trip *trip);
extern void dump_trip_list();
#endif
/* Make pointers to dive_trip and trip_table "Qt metatypes" so that they can be
/* Make pointers to dive_trip "Qt metatypes" so that they can be
* passed through QVariants and through QML. See comment in dive.h. */
#include <QObject>
Q_DECLARE_METATYPE(struct dive_trip *);
Q_DECLARE_METATYPE(trip_table *);
#endif

21
core/triptable.h Normal file
View file

@ -0,0 +1,21 @@
// SPDX-License-Identifier: GPL-2.0
#ifndef TRIPTABLE_H
#define TRIPTABLE_H
#include "owning_table.h"
struct dive_trip;
int comp_trips(const dive_trip &t1, const dive_trip &t2);
struct trip_table : public sorted_owning_table<dive_trip, &comp_trips> {
dive_trip *get_by_uniq_id(int tripId) const;
};
/* Make pointers to trip_table "Qt metatypes" so that they can be
* passed through QVariants and through QML. See comment in dive.h. */
#include <QObject>
Q_DECLARE_METATYPE(trip_table *);
#endif

View file

@ -190,9 +190,9 @@ static std::unique_ptr<dive> uemis_start_dive(uint32_t deviceid)
static struct dive *get_dive_by_uemis_diveid(device_data_t *devdata, uint32_t object_id)
{
for (int i = 0; i < devdata->log->dives->nr; i++) {
if (object_id == devdata->log->dives->dives[i]->dcs[0].diveid)
return devdata->log->dives->dives[i];
for (auto &d: devdata->log->dives) {
if (object_id == d->dcs[0].diveid)
return d.get();
}
return NULL;
}
@ -767,27 +767,13 @@ static void parse_tag(struct dive *dive, std::string_view tag, std::string_view
static bool uemis_delete_dive(device_data_t *devdata, uint32_t diveid)
{
struct dive *dive = NULL;
auto it = std::find_if(devdata->log->dives.begin(), devdata->log->dives.end(),
[diveid] (auto &d) { return d->dcs[0].diveid == diveid; });
if (it == devdata->log->dives.end())
return false;
if (devdata->log->dives->dives[devdata->log->dives->nr - 1]->dcs[0].diveid == diveid) {
/* we hit the last one in the array */
dive = devdata->log->dives->dives[devdata->log->dives->nr - 1];
} else {
for (int i = 0; i < devdata->log->dives->nr - 1; i++) {
if (devdata->log->dives->dives[i]->dcs[0].diveid == diveid) {
dive = devdata->log->dives->dives[i];
for (int x = i; x < devdata->log->dives->nr - 1; x++)
devdata->log->dives->dives[i] = devdata->log->dives->dives[x + 1];
}
}
}
if (dive) {
devdata->log->dives->dives[--devdata->log->dives->nr] = NULL;
delete dive;
return true;
}
return false;
devdata->log->dives.erase(it);
return true;
}
/* This function is called for both dive log and dive information that we get
@ -914,7 +900,7 @@ static bool process_raw_buffer(device_data_t *devdata, uint32_t deviceid, std::s
bp = bp.substr(1);
if (bp[0] != '{' && bp.find("{{") != std::string::npos) {
done = false;
record_dive_to_table(owned_dive.release(), devdata->log->dives.get());
devdata->log->dives.record_dive(std::move(owned_dive));
owned_dive = uemis_start_dive(deviceid);
}
}
@ -947,7 +933,7 @@ static bool process_raw_buffer(device_data_t *devdata, uint32_t deviceid, std::s
}
if (is_log) {
if (owned_dive->dcs[0].diveid)
record_dive_to_table(owned_dive.release(), devdata->log->dives.get());
devdata->log->dives.record_dive(std::move(owned_dive));
else /* partial dive */
return false;
}
@ -959,7 +945,6 @@ static std::pair<uint32_t, uint32_t> uemis_get_divenr(uint32_t deviceid, struct
{
uint32_t maxdiveid = 0;
uint32_t mindiveid = 0xFFFFFFFF;
int i;
/*
* If we are are retrying after a disconnect/reconnect, we
@ -971,11 +956,10 @@ static std::pair<uint32_t, uint32_t> uemis_get_divenr(uint32_t deviceid, struct
*
* Otherwise, use the global dive table.
*/
if (!force && !table->nr)
table = divelog.dives.get();
if (!force && table->empty())
table = &divelog.dives;
for (i = 0; i < table->nr; i++) {
struct dive *d = table->dives[i];
for (auto &d: *table) {
if (!d)
continue;
for (auto &dc: d->dcs) {
@ -1037,19 +1021,19 @@ static bool do_dump_buffer_to_file(std::string_view buf, const char *prefix)
* return : ok if there is enough memory for a full round
* full if the memory is exhausted
*/
static uemis_mem_status get_memory(struct dive_table *td, uemis_checkpoint checkpoint)
static uemis_mem_status get_memory(struct dive_table &td, uemis_checkpoint checkpoint)
{
if (td->nr <= 0)
if (td.empty())
return uemis_mem_status::ok;
switch (checkpoint) {
case uemis_checkpoint::log:
if (filenr / td->nr > max_mem_used)
max_mem_used = filenr / td->nr;
if (filenr / static_cast<int>(td.size()) > max_mem_used)
max_mem_used = filenr / static_cast<int>(td.size());
/* check if a full block of dive logs + dive details and dive spot fit into the UEMIS buffer */
#if UEMIS_DEBUG & 4
report_info("max_mem_used %d (from td->nr %d) * block_size %d > max_files %d - filenr %d?\n", max_mem_used, td->nr, uemis_log_block_size, uemis_max_files, filenr);
report_info("max_mem_used %d (from td.size() %d) * block_size %d > max_files %d - filenr %d?\n", max_mem_used, static_cast<int>(td.size()), uemis_log_block_size, uemis_max_files, filenr);
#endif
if (max_mem_used * uemis_log_block_size > uemis_max_files - filenr)
return uemis_mem_status::full;
@ -1069,10 +1053,10 @@ static uemis_mem_status get_memory(struct dive_table *td, uemis_checkpoint check
/* we misuse the hidden_by_filter flag to mark a dive as deleted.
* this will be picked up by some cleaning statement later. */
static void do_delete_dives(struct dive_table *td, int idx)
static void do_delete_dives(struct dive_table &td, size_t idx)
{
for (int x = idx; x < td->nr; x++)
td->dives[x]->hidden_by_filter = true;
for (auto it = td.begin() + idx; it != td.end(); ++it)
(*it)->hidden_by_filter = true;
}
static bool load_uemis_divespot(const std::string &mountpath, int divespot_id)
@ -1128,9 +1112,9 @@ static void get_uemis_divespot(device_data_t *devdata, const std::string &mountp
}
}
static bool get_matching_dive(int idx, int &newmax, uemis_mem_status &mem_status, device_data_t *data, const std::string &mountpath, const char deviceidnr)
static bool get_matching_dive(size_t idx, int &newmax, uemis_mem_status &mem_status, device_data_t *data, const std::string &mountpath, const char deviceidnr)
{
struct dive *dive = data->log->dives->dives[idx];
auto &dive = data->log->dives[idx];
char log_file_no_to_find[20];
bool found = false;
bool found_below = false;
@ -1151,7 +1135,7 @@ static bool get_matching_dive(int idx, int &newmax, uemis_mem_status &mem_status
#if UEMIS_DEBUG & 16
do_dump_buffer_to_file(mbuf, "Dive");
#endif
mem_status = get_memory(data->log->dives.get(), uemis_checkpoint::single_dive);
mem_status = get_memory(data->log->dives, uemis_checkpoint::single_dive);
if (mem_status == uemis_mem_status::ok) {
/* if the memory isn's completely full we can try to read more dive log vs. dive details
* and the dive spots should fit into the UEMIS memory
@ -1174,7 +1158,7 @@ static bool get_matching_dive(int idx, int &newmax, uemis_mem_status &mem_status
#endif
int divespot_id = uemis_obj.get_divespot_id_by_diveid(dive->dcs[0].diveid);
if (divespot_id >= 0)
get_uemis_divespot(data, mountpath, divespot_id, dive);
get_uemis_divespot(data, mountpath, divespot_id, dive.get());
} else {
/* in this case we found a deleted file, so let's increment */
@ -1215,7 +1199,7 @@ static bool get_matching_dive(int idx, int &newmax, uemis_mem_status &mem_status
} else {
/* At this point the memory of the UEMIS is full, let's cleanup all dive log files were
* we could not match the details to. */
do_delete_dives(data->log->dives.get(), idx);
do_delete_dives(data->log->dives, idx);
return false;
}
}
@ -1236,7 +1220,6 @@ std::string do_uemis_import(device_data_t *data)
std::string deviceid;
std::string result;
bool once = true;
int match_dive_and_log = 0;
int dive_offset = 0;
uemis_mem_status mem_status = uemis_mem_status::ok;
@ -1274,7 +1257,7 @@ std::string do_uemis_import(device_data_t *data)
param_buff[1] = "notempty";
{
auto [mindiveid, maxdiveid] = uemis_get_divenr(deviceidnr, data->log->dives.get(), force_download);
auto [mindiveid, maxdiveid] = uemis_get_divenr(deviceidnr, &data->log->dives, force_download);
newmax = maxdiveid;
if (verbose)
report_info("Uemis downloader: start looking at dive nr %d", newmax);
@ -1292,13 +1275,13 @@ std::string do_uemis_import(device_data_t *data)
report_info("d_u_i inner loop start %d end %d newmax %d\n", start, end, newmax);
#endif
/* start at the last filled download table index */
match_dive_and_log = data->log->dives->nr;
size_t match_dive_and_log = data->log->dives.size();
newmax = start;
std::string newmax_str = std::to_string(newmax);
param_buff[2] = newmax_str.c_str();
param_buff[3].clear();
std::string mbuf = uemis_get_answer(mountpath, "getDivelogs", 3, 0, result);
mem_status = get_memory(data->log->dives.get(), uemis_checkpoint::details);
mem_status = get_memory(data->log->dives, uemis_checkpoint::details);
/* first, remove any leading garbage... this needs to start with a '{' */
std::string_view realmbuf = mbuf;
size_t pos = realmbuf.find('{');
@ -1341,7 +1324,7 @@ std::string do_uemis_import(device_data_t *data)
* What the following part does is to optimize the mapping by using
* dive_to_read = the dive details entry that need to be read using the object_id
* logFileNoToFind = map the logfilenr of the dive details with the object_id = diveid from the get dive logs */
for (int i = match_dive_and_log; i < data->log->dives->nr; i++) {
for (size_t i = match_dive_and_log; i < data->log->dives.size(); i++) {
if (!get_matching_dive(i, newmax, mem_status, data, mountpath, deviceidnr))
break;
if (import_thread_cancelled)
@ -1351,7 +1334,7 @@ std::string do_uemis_import(device_data_t *data)
start = end;
/* Do some memory checking here */
mem_status = get_memory(data->log->dives.get(), uemis_checkpoint::log);
mem_status = get_memory(data->log->dives, uemis_checkpoint::log);
if (mem_status != uemis_mem_status::ok) {
#if UEMIS_DEBUG & 4
report_info("d_u_i out of memory, bailing\n");
@ -1365,7 +1348,7 @@ std::string do_uemis_import(device_data_t *data)
// Resetting to original state
filenr = 0;
max_mem_used = -1;
mem_status = get_memory(data->log->dives.get(), uemis_checkpoint::details);
mem_status = get_memory(data->log->dives, uemis_checkpoint::details);
if (uemis_get_answer(mountpath, "getDeviceId", 0, 1, result).empty())
goto bail;
if (deviceid != param_buff[0]) {
@ -1408,7 +1391,7 @@ std::string do_uemis_import(device_data_t *data)
* be deleted from the download_table.
*/
if (mem_status == uemis_mem_status::full)
do_delete_dives(data->log->dives.get(), match_dive_and_log);
do_delete_dives(data->log->dives, match_dive_and_log);
#if UEMIS_DEBUG & 4
report_info("d_u_i out of memory, bailing instead of processing\n");
#endif
@ -1425,9 +1408,9 @@ std::string do_uemis_import(device_data_t *data)
/* Regardless on where we are with the memory situation, it's time now
* to see if we have to clean some dead bodies from our download table */
for (int next_table_index = 0; next_table_index < data->log->dives->nr; ) {
if (data->log->dives->dives[next_table_index]->hidden_by_filter)
uemis_delete_dive(data, data->log->dives->dives[next_table_index]->dcs[0].diveid);
for (size_t next_table_index = 0; next_table_index < data->log->dives.size(); ) {
if (data->log->dives[next_table_index]->hidden_by_filter)
uemis_delete_dive(data, data->log->dives[next_table_index]->dcs[0].diveid);
else
next_table_index++;
}
@ -1446,7 +1429,7 @@ bail:
else
result = param_buff[2];
}
if (!data->log->dives->nr)
if (data->log->dives.empty())
result = translate("gettextFromC", ERR_NO_FILES);
return result;
}

View file

@ -7,8 +7,11 @@
#include "core/errorhelper.h"
#include "core/qthelper.h"
#include "core/dive.h"
#include "core/membuffer.h"
#include "core/divelist.h"
#include "core/divelog.h"
#include "core/divesite.h"
#include "core/membuffer.h"
#include "core/range.h"
#include "core/cloudstorage.h"
#include "core/xmlparams.h"
#ifndef SUBSURFACE_MOBILE
@ -87,9 +90,7 @@ bool uploadDiveLogsDE::prepareDives(const QString &tempfile, bool selected)
}
/* walk the dive list in chronological order */
int i;
struct dive *dive;
for_each_dive (i, dive) {
for (auto [i, dive]: enumerated_range(divelog.dives)) {
char filename[PATH_MAX];
int streamsize;
char *membuf;
@ -131,7 +132,7 @@ bool uploadDiveLogsDE::prepareDives(const QString &tempfile, bool selected)
put_format(&mb, "</site>\n</divesites>\n");
}
save_one_dive_to_mb(&mb, dive, false);
save_one_dive_to_mb(&mb, *dive, false);
if (ds) {
put_format(&mb, "</divelog>\n");

View file

@ -10,10 +10,12 @@
#include <stdio.h>
#include "dive.h"
#include "membuffer.h"
#include "divelist.h"
#include "divelog.h"
#include "divesite.h"
#include "errorhelper.h"
#include "file.h"
#include "membuffer.h"
#include "save-html.h"
#include "format.h"
#include "worldmap-save.h"
@ -28,43 +30,39 @@ static const char *getGoogleApi()
static void writeMarkers(struct membuffer *b, bool selected_only)
{
int i, dive_no = 0;
struct dive *dive;
std::string pre, post;
int dive_no = 0;
for_each_dive (i, dive) {
if (selected_only) {
if (!dive->selected)
for (auto &dive: divelog.dives) {
if (selected_only && !dive->selected)
continue;
}
struct dive_site *ds = get_dive_site_for_dive(dive);
struct dive_site *ds = get_dive_site_for_dive(dive.get());
if (!dive_site_has_gps_location(ds))
continue;
put_degrees(b, ds->location.lat, "temp = new google.maps.Marker({position: new google.maps.LatLng(", "");
put_degrees(b, ds->location.lon, ",", ")});\n");
put_string(b, "markers.push(temp);\ntempinfowindow = new google.maps.InfoWindow({content: '<div id=\"content\">'+'<div id=\"siteNotice\">'+'</div>'+'<div id=\"bodyContent\">");
pre = format_string_std("<p>%s ", translate("gettextFromC", "Date:"));
put_HTML_date(b, dive, pre.c_str(), "</p>");
std::string pre = format_string_std("<p>%s ", translate("gettextFromC", "Date:"));
put_HTML_date(b, *dive, pre.c_str(), "</p>");
pre = format_string_std("<p>%s ", translate("gettextFromC", "Time:"));
put_HTML_time(b, dive, pre.c_str(), "</p>");
put_HTML_time(b, *dive, pre.c_str(), "</p>");
pre = format_string_std("<p>%s ", translate("gettextFromC", "Duration:"));
post = format_string_std(" %s</p>", translate("gettextFromC", "min"));
std::string post = format_string_std(" %s</p>", translate("gettextFromC", "min"));
put_duration(b, dive->duration, pre.c_str(), post.c_str());
put_string(b, "<p> ");
put_HTML_quoted(b, translate("gettextFromC", "Max. depth:"));
put_HTML_depth(b, dive, " ", "</p>");
put_HTML_depth(b, *dive, " ", "</p>");
put_string(b, "<p> ");
put_HTML_quoted(b, translate("gettextFromC", "Air temp.:"));
put_HTML_airtemp(b, dive, " ", "</p>");
put_HTML_airtemp(b, *dive, " ", "</p>");
put_string(b, "<p> ");
put_HTML_quoted(b, translate("gettextFromC", "Water temp.:"));
put_HTML_watertemp(b, dive, " ", "</p>");
put_HTML_watertemp(b, *dive, " ", "</p>");
pre = format_string_std("<p>%s <b>", translate("gettextFromC", "Location:"));
put_string(b, pre.c_str());
put_HTML_quoted(b, get_dive_location(dive).c_str());
put_HTML_quoted(b, get_dive_location(dive.get()).c_str());
put_string(b, "</b></p>");
pre = format_string_std("<p> %s ", translate("gettextFromC", "Notes:"));
put_HTML_notes(b, dive, pre.c_str(), " </p>");
put_HTML_notes(b, *dive, pre.c_str(), " </p>");
put_string(b, "</p>'+'</div>'+'</div>'});\ninfowindows.push(tempinfowindow);\n");
put_format(b, "google.maps.event.addListener(markers[%d], 'mouseover', function() {\ninfowindows[%d].open(map,markers[%d]);}", dive_no, dive_no, dive_no);
put_format(b, ");google.maps.event.addListener(markers[%d], 'mouseout', function() {\ninfowindows[%d].close();});\n", dive_no, dive_no);

View file

@ -755,9 +755,9 @@ void DiveListView::contextMenuEvent(QContextMenuEvent *event)
bottom = first_selected_dive();
}
}
if (is_trip_before_after(top, (currentOrder == Qt::AscendingOrder)))
if (divelog.is_trip_before_after(top, (currentOrder == Qt::AscendingOrder)))
popup.addAction(tr("Add dive(s) to trip immediately above","",amount_selected), this, &DiveListView::addToTripAbove);
if (is_trip_before_after(bottom, (currentOrder == Qt::DescendingOrder)))
if (divelog.is_trip_before_after(bottom, (currentOrder == Qt::DescendingOrder)))
popup.addAction(tr("Add dive(s) to trip immediately below","",amount_selected), this, &DiveListView::addToTripBelow);
}
}

View file

@ -465,7 +465,7 @@ void DownloadFromDCWidget::on_downloadCancelRetryButton_clicked()
qPrefDiveComputer::set_device(data->devName());
// before we start, remember where the dive_table ended
previousLast = divelog.dives->nr;
previousLast = static_cast<int>(divelog.dives.size());
diveImportedModel->startDownload();
// FIXME: We should get the _actual_ device info instead of whatever

View file

@ -1,5 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include "findmovedimagesdialog.h"
#include "core/divelog.h"
#include "core/divelist.h"
#include "core/picture.h"
#include "core/qthelper.h"
#include "desktop-widgets/divelistview.h" // TODO: used for lastUsedImageDir()
@ -184,12 +186,12 @@ void FindMovedImagesDialog::on_scanButton_clicked()
// We have to collect the names of the image filenames in the main thread
bool onlySelected = ui.onlySelectedDives->isChecked();
QVector<QString> imagePaths;
int i;
struct dive *dive;
for_each_dive (i, dive)
if (!onlySelected || dive->selected)
for (auto &dive: divelog.dives) {
if (!onlySelected || dive->selected) {
for (auto &picture: dive->pictures)
imagePaths.append(QString::fromStdString(picture.filename));
}
}
stopScanning = 0;
QFuture<QVector<Match>> future = QtConcurrent::run(
// Note that we capture everything but "this" by copy to avoid dangling references.

View file

@ -430,7 +430,7 @@ void MainWindow::on_actionCloudstorageopen_triggered()
// Return whether saving to cloud is OK. If it isn't, show an error return false.
static bool saveToCloudOK()
{
if (!divelog.dives->nr) {
if (divelog.dives.empty()) {
report_error("%s", qPrintable(gettextFromC::tr("Don't save an empty log to the cloud")));
return false;
}

View file

@ -1,7 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
#include "printer.h"
#include "templatelayout.h"
#include "core/dive.h" // for get_dive_by_uniq_id()
#include "core/divelist.h"
#include "core/divelog.h"
#include "core/selection.h"
#include "core/statistics.h"
#include "core/qthelper.h"
@ -129,7 +130,7 @@ void Printer::render(int pages)
// dive id field should be dive_{{dive_no}} se we remove the first 5 characters
QString diveIdString = collection.at(elemNo).attribute("id");
int diveId = diveIdString.remove(0, 5).toInt(0, 10);
putProfileImage(collection.at(elemNo).geometry(), viewPort, &painter, get_dive_by_uniq_id(diveId), profile.get());
putProfileImage(collection.at(elemNo).geometry(), viewPort, &painter, divelog.dives.get_by_uniq_id(diveId), profile.get());
elemNo++;
}
@ -160,10 +161,8 @@ std::vector<dive *> Printer::getDives() const
return getDiveSelection();
} else {
std::vector<dive *> res;
int i;
struct dive *dive;
for_each_dive (i, dive)
res.push_back(dive);
for (auto &d: divelog.dives)
res.push_back(d.get());
return res;
}
}

View file

@ -31,12 +31,10 @@ void RenumberDialog::buttonClicked(QAbstractButton *button)
if (ui.buttonBox->buttonRole(button) == QDialogButtonBox::AcceptRole) {
// we remember a list from dive uuid to a new number
QVector<QPair<dive *, int>> renumberedDives;
int i;
int newNr = ui.spinBox->value();
struct dive *d;
for_each_dive (i, d) {
for (auto &d: divelog.dives) {
if (!selectedOnly || d->selected)
renumberedDives.append({ d, newNr++ });
renumberedDives.append({ d.get(), newNr++ });
}
Command::renumberDives(renumberedDives);
}

View file

@ -5,9 +5,12 @@
#include <QVector>
#include "qmlmapwidgethelper.h"
#include "core/divefilter.h"
#include "core/divelist.h"
#include "core/divelog.h"
#include "core/divesite.h"
#include "core/qthelper.h"
#include "core/divefilter.h"
#include "core/range.h"
#include "qt-models/maplocationmodel.h"
#include "qt-models/divelocationmodel.h"
#ifndef SUBSURFACE_MOBILE
@ -122,8 +125,6 @@ void MapWidgetHelper::reloadMapLocations()
void MapWidgetHelper::selectedLocationChanged(struct dive_site *ds_in)
{
int idx;
struct dive *dive;
QList<int> selectedDiveIds;
if (!ds_in)
@ -133,8 +134,8 @@ void MapWidgetHelper::selectedLocationChanged(struct dive_site *ds_in)
return;
QGeoCoordinate locationCoord = location->coordinate;
for_each_dive (idx, dive) {
struct dive_site *ds = get_dive_site_for_dive(dive);
for (auto [idx, dive]: enumerated_range(divelog.dives)) {
struct dive_site *ds = get_dive_site_for_dive(dive.get());
if (!dive_site_has_gps_location(ds))
continue;
#ifndef SUBSURFACE_MOBILE
@ -160,11 +161,9 @@ void MapWidgetHelper::selectedLocationChanged(struct dive_site *ds_in)
void MapWidgetHelper::selectVisibleLocations()
{
int idx;
struct dive *dive;
QList<int> selectedDiveIds;
for_each_dive (idx, dive) {
struct dive_site *ds = get_dive_site_for_dive(dive);
for (auto [idx, dive]: enumerated_range(divelog.dives)) {
struct dive_site *ds = get_dive_site_for_dive(dive.get());
if (!dive_site_has_gps_location(ds))
continue;
const qreal latitude = ds->location.lat.udeg * 0.000001;

View file

@ -413,9 +413,9 @@ void QMLManager::openLocalThenRemote(QString url)
qPrefTechnicalDetails::set_show_ccr_sensors(git_prefs.show_ccr_sensors);
qPrefPartialPressureGas::set_po2(git_prefs.pp_graphs.po2);
// the following steps can take a long time, so provide updates
setNotificationText(tr("Processing %1 dives").arg(divelog.dives->nr));
setNotificationText(tr("Processing %1 dives").arg(divelog.dives.size()));
process_loaded_dives();
setNotificationText(tr("%1 dives loaded from local dive data file").arg(divelog.dives->nr));
setNotificationText(tr("%1 dives loaded from local dive data file").arg(divelog.dives.size()));
}
if (qPrefCloudStorage::cloud_verification_status() == qPrefCloudStorage::CS_NEED_TO_VERIFY) {
appendTextToLog(QStringLiteral("have cloud credentials, but still needs PIN"));
@ -478,7 +478,7 @@ void QMLManager::mergeLocalRepo()
{
struct divelog log;
parse_file(qPrintable(nocloud_localstorage()), &log);
add_imported_dives(&log, IMPORT_MERGE_ALL_TRIPS);
add_imported_dives(log, IMPORT_MERGE_ALL_TRIPS);
mark_divelist_changed(true);
}
@ -588,7 +588,7 @@ void QMLManager::finishSetup()
// successfully opened the local file, now add thigs to the dive list
consumeFinishedLoad();
updateHaveLocalChanges(true);
appendTextToLog(QString("working in no-cloud mode, finished loading %1 dives from %2").arg(divelog.dives->nr).arg(existing_filename.c_str()));
appendTextToLog(QString("working in no-cloud mode, finished loading %1 dives from %2").arg(divelog.dives.size()).arg(existing_filename.c_str()));
}
} else {
qPrefCloudStorage::set_cloud_verification_status(qPrefCloudStorage::CS_UNKNOWN);
@ -672,7 +672,7 @@ void QMLManager::saveCloudCredentials(const QString &newEmail, const QString &ne
qPrefCloudStorage::set_cloud_storage_email(email);
qPrefCloudStorage::set_cloud_storage_password(newPassword);
if (m_oldStatus == qPrefCloudStorage::CS_NOCLOUD && cloudCredentialsChanged && divelog.dives->nr) {
if (m_oldStatus == qPrefCloudStorage::CS_NOCLOUD && cloudCredentialsChanged && divelog.dives.size()) {
// we came from NOCLOUD and are connecting to a cloud account;
// since we already have dives in the table, let's remember that so we can keep them
noCloudToCloud = true;
@ -830,7 +830,7 @@ void QMLManager::loadDivesWithValidCredentials()
if (noCloudToCloud) {
git_storage_update_progress(qPrintable(tr("Loading dives from local storage ('no cloud' mode)")));
mergeLocalRepo();
appendTextToLog(QStringLiteral("%1 dives loaded after importing nocloud local storage").arg(divelog.dives->nr));
appendTextToLog(QStringLiteral("%1 dives loaded after importing nocloud local storage").arg(divelog.dives.size()));
noCloudToCloud = false;
mark_divelist_changed(true);
emit syncStateChanged();
@ -894,8 +894,8 @@ void QMLManager::consumeFinishedLoad()
prefs.show_ccr_sensors = git_prefs.show_ccr_sensors;
prefs.pp_graphs.po2 = git_prefs.pp_graphs.po2;
process_loaded_dives();
appendTextToLog(QStringLiteral("%1 dives loaded").arg(divelog.dives->nr));
if (divelog.dives->nr == 0)
appendTextToLog(QStringLiteral("%1 dives loaded").arg(divelog.dives.size()));
if (divelog.dives.empty())
setStartPageText(tr("Cloud storage open successfully. No dives in dive list."));
}
@ -1168,7 +1168,7 @@ void QMLManager::commitChanges(QString diveId, QString number, QString date, QSt
QString airtemp, QString watertemp, QString suit, QString buddy, QString diveGuide, QString tags, QString weight, QString notes,
QStringList startpressure, QStringList endpressure, QStringList gasmix, QStringList usedCylinder, int rating, int visibility, QString state)
{
struct dive *orig = get_dive_by_uniq_id(diveId.toInt());
struct dive *orig = divelog.dives.get_by_uniq_id(diveId.toInt());
if (!orig) {
appendTextToLog("cannot commit changes: no dive");
@ -1389,7 +1389,7 @@ void QMLManager::updateTripDetails(QString tripIdString, QString tripLocation, Q
void QMLManager::removeDiveFromTrip(int id)
{
struct dive *d = get_dive_by_uniq_id(id);
struct dive *d = divelog.dives.get_by_uniq_id(id);
if (!d) {
appendTextToLog(QString("Asked to remove non-existing dive with id %1 from its trip.").arg(id));
return;
@ -1406,7 +1406,7 @@ void QMLManager::removeDiveFromTrip(int id)
void QMLManager::addTripForDive(int id)
{
struct dive *d = get_dive_by_uniq_id(id);
struct dive *d = divelog.dives.get_by_uniq_id(id);
if (!d) {
appendTextToLog(QString("Asked to create trip for non-existing dive with id %1").arg(id));
return;
@ -1423,7 +1423,7 @@ void QMLManager::addTripForDive(int id)
void QMLManager::addDiveToTrip(int id, int tripId)
{
struct dive *d = get_dive_by_uniq_id(id);
struct dive *d = divelog.dives.get_by_uniq_id(id);
if (!d) {
appendTextToLog(QString("Asked to add non-existing dive with id %1 to trip %2.").arg(id).arg(tripId));
return;
@ -1575,12 +1575,10 @@ void QMLManager::redo()
void QMLManager::selectDive(int id)
{
int i;
extern int amount_selected;
struct dive *dive = NULL;
amount_selected = 0;
for_each_dive (i, dive) {
for (auto &dive: divelog.dives) {
dive->selected = (dive->id == id);
if (dive->selected)
amount_selected++;
@ -1591,7 +1589,7 @@ void QMLManager::selectDive(int id)
void QMLManager::deleteDive(int id)
{
struct dive *d = get_dive_by_uniq_id(id);
struct dive *d = divelog.dives.get_by_uniq_id(id);
if (!d) {
appendTextToLog("trying to delete non-existing dive");
return;
@ -1602,7 +1600,7 @@ void QMLManager::deleteDive(int id)
void QMLManager::toggleDiveInvalid(int id)
{
struct dive *d = get_dive_by_uniq_id(id);
struct dive *d = divelog.dives.get_by_uniq_id(id);
if (!d) {
appendTextToLog("trying to toggle invalid flag of non-existing dive");
return;
@ -1693,7 +1691,7 @@ bool QMLManager::toggleWeights(bool toggle)
void QMLManager::copyDiveData(int id)
{
m_copyPasteDive = get_dive_by_uniq_id(id);
m_copyPasteDive = divelog.dives.get_by_uniq_id(id);
if (!m_copyPasteDive) {
appendTextToLog("trying to copy non-existing dive");
return;
@ -1781,7 +1779,7 @@ void QMLManager::setStartPageText(const QString& text)
QString QMLManager::getNumber(const QString& diveId)
{
int dive_id = diveId.toInt();
struct dive *d = get_dive_by_uniq_id(dive_id);
struct dive *d = divelog.dives.get_by_uniq_id(dive_id);
QString number;
if (d)
number = QString::number(d->number);
@ -1791,7 +1789,7 @@ QString QMLManager::getNumber(const QString& diveId)
QString QMLManager::getDate(const QString& diveId)
{
int dive_id = diveId.toInt();
struct dive *d = get_dive_by_uniq_id(dive_id);
struct dive *d = divelog.dives.get_by_uniq_id(dive_id);
QString datestring;
if (d)
datestring = get_short_dive_date_string(d->when);
@ -2360,7 +2358,7 @@ void QMLManager::importCacheRepo(QString repo)
QString repoPath = QString("%1/cloudstorage/%2").arg(system_default_directory()).arg(repo);
appendTextToLog(QString("importing %1").arg(repoPath));
parse_file(qPrintable(repoPath), &log);
add_imported_dives(&log, IMPORT_MERGE_ALL_TRIPS);
add_imported_dives(log, IMPORT_MERGE_ALL_TRIPS);
changesNeedSaving();
}

View file

@ -2,6 +2,7 @@
#include "qmlprofile.h"
#include "profilescene.h"
#include "mobile-widgets/qmlmanager.h"
#include "core/divelist.h"
#include "core/errorhelper.h"
#include "core/subsurface-float.h"
#include "core/metrics.h"
@ -60,7 +61,7 @@ void QMLProfile::paint(QPainter *painter)
painter->resetTransform();
if (m_diveId < 0)
return;
struct dive *d = get_dive_by_uniq_id(m_diveId);
struct dive *d = divelog.dives.get_by_uniq_id(m_diveId);
if (!d)
return;
m_profileWidget->draw(painter, painterRect, d, m_dc, nullptr, false);
@ -143,7 +144,7 @@ void QMLProfile::prevDC()
void QMLProfile::rotateDC(int dir)
{
struct dive *d = get_dive_by_uniq_id(m_diveId);
struct dive *d = divelog.dives.get_by_uniq_id(m_diveId);
if (!d)
return;
int numDC = number_of_computers(d);
@ -157,6 +158,6 @@ void QMLProfile::rotateDC(int dir)
int QMLProfile::numDC() const
{
struct dive *d = get_dive_by_uniq_id(m_diveId);
struct dive *d = divelog.dives.get_by_uniq_id(m_diveId);
return d ? number_of_computers(d) : 0;
}

View file

@ -1,6 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
#include "qt-models/completionmodels.h"
#include "core/dive.h"
#include "core/divelist.h"
#include "core/divelog.h"
#include "core/tag.h"
#include <QSet>
@ -31,10 +33,8 @@ void CompletionModelBase::divesChanged(const QVector<dive *> &, DiveField field)
static QStringList getCSVList(const std::string dive::*item)
{
QSet<QString> set;
struct dive *dive;
int i = 0;
for_each_dive (i, dive) {
QString str = QString::fromStdString(dive->*item);
for (auto &dive: divelog.dives) {
QString str = QString::fromStdString(dive.get()->*item);
for (const QString &value: str.split(",", SKIP_EMPTY))
set.insert(value.trimmed());
}
@ -66,9 +66,7 @@ bool DiveGuideCompletionModel::relevantDiveField(const DiveField &f)
QStringList SuitCompletionModel::getStrings()
{
QStringList list;
struct dive *dive;
int i = 0;
for_each_dive (i, dive) {
for (auto &dive: divelog.dives) {
QString suit = QString::fromStdString(dive->suit);
if (!list.contains(suit))
list.append(suit);

View file

@ -16,7 +16,7 @@ int DiveImportedModel::columnCount(const QModelIndex&) const
int DiveImportedModel::rowCount(const QModelIndex&) const
{
return log.dives->nr;
return static_cast<int>(log.dives.size());
}
QVariant DiveImportedModel::headerData(int section, Qt::Orientation orientation, int role) const
@ -46,15 +46,10 @@ QVariant DiveImportedModel::headerData(int section, Qt::Orientation orientation,
QVariant DiveImportedModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
if (index.row() < 0 || static_cast<size_t>(index.row()) >= log.dives.size())
return QVariant();
if (index.row() >= log.dives->nr)
return QVariant();
struct dive *d = get_dive_from_table(index.row(), log.dives.get());
if (!d)
return QVariant();
const struct dive &d = *log.dives[index.row()];
// widgets access the model via index.column(), qml via role.
int column = index.column();
@ -66,11 +61,11 @@ QVariant DiveImportedModel::data(const QModelIndex &index, int role) const
if (role == Qt::DisplayRole) {
switch (column) {
case 0:
return QVariant(get_short_dive_date_string(d->when));
return QVariant(get_short_dive_date_string(d.when));
case 1:
return QVariant(get_dive_duration_string(d->duration.seconds, tr("h"), tr("min")));
return QVariant(get_dive_duration_string(d.duration.seconds, tr("h"), tr("min")));
case 2:
return QVariant(get_depth_string(d->maxdepth.mm, true, false));
return QVariant(get_depth_string(d.maxdepth.mm, true, false));
case 3:
return checkStates[index.row()];
}
@ -90,8 +85,10 @@ void DiveImportedModel::changeSelected(QModelIndex clickedIndex)
void DiveImportedModel::selectAll()
{
if (log.dives.empty())
return;
std::fill(checkStates.begin(), checkStates.end(), true);
dataChanged(index(0, 0), index(log.dives->nr - 1, 0), QVector<int>() << Qt::CheckStateRole << Selected);
dataChanged(index(0, 0), index(log.dives.size() - 1, 0), QVector<int>() << Qt::CheckStateRole << Selected);
}
void DiveImportedModel::selectRow(int row)
@ -102,8 +99,10 @@ void DiveImportedModel::selectRow(int row)
void DiveImportedModel::selectNone()
{
if (log.dives.empty())
return;
std::fill(checkStates.begin(), checkStates.end(), false);
dataChanged(index(0, 0), index(log.dives->nr - 1, 0 ), QVector<int>() << Qt::CheckStateRole << Selected);
dataChanged(index(0, 0), index(log.dives.size() - 1, 0 ), QVector<int>() << Qt::CheckStateRole << Selected);
}
Qt::ItemFlags DiveImportedModel::flags(const QModelIndex &index) const
@ -129,7 +128,7 @@ void DiveImportedModel::downloadThreadFinished()
log.clear();
std::swap(log, thread.log);
checkStates.resize(log.dives->nr);
checkStates.resize(log.dives.size());
std::fill(checkStates.begin(), checkStates.end(), true);
endResetModel();
@ -166,24 +165,24 @@ struct divelog DiveImportedModel::consumeTables()
int DiveImportedModel::numDives() const
{
return log.dives->nr;
return static_cast<size_t>(log.dives.size());
}
// Delete non-selected dives
void DiveImportedModel::deleteDeselected()
{
int total = log.dives->nr;
int j = 0;
for (int i = 0; i < total; i++) {
size_t total = log.dives.size();
size_t j = 0;
for (size_t i = 0; i < total; i++) {
if (checkStates[i]) {
j++;
} else {
beginRemoveRows(QModelIndex(), j, j);
delete_dive_from_table(log.dives.get(), j);
log.dives.erase(log.dives.begin() + j);
endRemoveRows();
}
}
checkStates.resize(log.dives->nr);
checkStates.resize(log.dives.size());
std::fill(checkStates.begin(), checkStates.end(), true);
}
@ -194,7 +193,7 @@ void DiveImportedModel::recordDives(int flags)
deleteDeselected();
struct divelog log = consumeTables();
if (log.dives->nr > 0) {
if (!log.dives.empty()) {
auto data = thread.data();
Command::importDives(&log, flags, data->devName());
}

View file

@ -25,7 +25,7 @@ PictureEntry::PictureEntry(dive *dIn, const picture &p) : d(dIn),
// should give the same result].
bool PictureEntry::operator<(const PictureEntry &p2) const
{
if (int cmp = comp_dives(d, p2.d))
if (int cmp = comp_dives_ptr(d, p2.d))
return cmp < 0;
if (offsetSeconds != p2.offsetSeconds)
return offsetSeconds < p2.offsetSeconds;

View file

@ -102,9 +102,8 @@ void DivePlannerPointsModel::setupStartTime()
// if the latest dive is in the future, then start an hour after it ends
// otherwise start an hour from now
startTime = QDateTime::currentDateTimeUtc().addSecs(3600 + gettimezoneoffset());
if (divelog.dives->nr > 0) {
struct dive *d = get_dive(divelog.dives->nr - 1);
time_t ends = d->endtime();
if (!divelog.dives.empty()) {
time_t ends = divelog.dives.back()->endtime();
time_t diff = ends - dateTimeToTimestamp(startTime);
if (diff > 0)
startTime = startTime.addSecs(diff + 3600);
@ -1097,7 +1096,7 @@ void DivePlannerPointsModel::updateDiveProfile()
#if DEBUG_PLAN
save_dive(stderr, d);
save_dive(stderr, *d);
dump_plan(&diveplan);
#endif
}

View file

@ -1,6 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
#include "qt-models/divesummarymodel.h"
#include "core/dive.h"
#include "core/divelist.h"
#include "core/divelog.h"
#include "core/qthelper.h"
#include <QLocale>
@ -160,13 +162,10 @@ static void calculateDive(struct dive *dive, Stats &stats)
static Stats loopDives(timestamp_t start)
{
Stats stats;
struct dive *dive;
int i;
for_each_dive (i, dive) {
for (auto &dive: divelog.dives) {
// check if dive is newer than primaryStart (add to first column)
if (dive->when > start)
calculateDive(dive, stats);
calculateDive(dive.get(), stats);
}
return stats;
}

View file

@ -707,18 +707,15 @@ void DiveTripModelTree::populate()
// we want this to be two calls as the second text is overwritten below by the lines starting with "\r"
uiNotification(QObject::tr("populate data model"));
uiNotification(QObject::tr("start processing"));
for (int i = 0; i < divelog.dives->nr; ++i) {
dive *d = get_dive(i);
if (!d) // should never happen
continue;
update_cylinder_related_info(d);
for (auto &d: divelog.dives) {
update_cylinder_related_info(d.get());
if (d->hidden_by_filter)
continue;
dive_trip *trip = d->divetrip;
// If this dive doesn't have a trip, add as top-level item.
if (!trip) {
items.emplace_back(d);
items.emplace_back(d.get());
continue;
}
@ -728,16 +725,16 @@ void DiveTripModelTree::populate()
{ return item.d_or_t.trip == trip; });
if (it == items.end()) {
// We didn't find an entry for this trip -> add one
items.emplace_back(trip, d);
items.emplace_back(trip, d.get());
} else {
// We found the trip -> simply add the dive
it->dives.push_back(d);
it->dives.push_back(d.get());
}
}
// Remember the index of the current dive
oldCurrent = current_dive;
uiNotification(QObject::tr("%1 dives processed").arg(divelog.dives->nr));
uiNotification(QObject::tr("%1 dives processed").arg(divelog.dives.size()));
}
int DiveTripModelTree::rowCount(const QModelIndex &parent) const
@ -846,7 +843,7 @@ void processByTrip(QVector<dive *> dives, Function action)
{
// Sort lexicographically by trip then according to the dive_less_than() function.
std::sort(dives.begin(), dives.end(), [](const dive *d1, const dive *d2)
{ return d1->divetrip == d2->divetrip ? dive_less_than(d1, d2) : d1->divetrip < d2->divetrip; });
{ return d1->divetrip == d2->divetrip ? dive_less_than_ptr(d1, d2) : d1->divetrip < d2->divetrip; });
// Then, process the dives in batches by trip
int i, j; // Begin and end of batch
@ -995,7 +992,7 @@ void DiveTripModelTree::addDivesToTrip(int trip, const QVector<dive *> &dives)
QModelIndex parent = createIndex(trip, 0, noParent);
addInBatches(items[trip].dives, dives,
[](dive *d, dive *d2) { return dive_less_than(d, d2); }, // comp
[](dive *d, dive *d2) { return dive_less_than_ptr(d, d2); }, // comp
[&](std::vector<dive *> &items, const QVector<dive *> &dives, int idx, int from, int to) { // inserter
beginInsertRows(parent, idx, idx + to - from - 1);
items.insert(items.begin() + idx, dives.begin() + from, dives.begin() + to);
@ -1485,12 +1482,11 @@ void DiveTripModelList::populate()
DiveFilter::instance()->reset(); // The data was reset - update filter status. TODO: should this really be done here?
// Fill model
items.reserve(divelog.dives->nr);
for (int i = 0; i < divelog.dives->nr; ++i) {
dive *d = get_dive(i);
items.reserve(divelog.dives.size());
for (auto &d: divelog.dives) {
if (!d || d->hidden_by_filter)
continue;
items.push_back(d);
items.push_back(d.get());
}
// Remember the index of the current dive
@ -1555,9 +1551,9 @@ QVariant DiveTripModelList::data(const QModelIndex &index, int role) const
void DiveTripModelList::addDives(QVector<dive *> &dives)
{
std::sort(dives.begin(), dives.end(), dive_less_than);
std::sort(dives.begin(), dives.end(), dive_less_than_ptr);
addInBatches(items, dives,
&dive_less_than, // comp
&dive_less_than_ptr, // comp
[&](std::vector<dive *> &items, const QVector<dive *> &dives, int idx, int from, int to) { // inserter
beginInsertRows(QModelIndex(), idx, idx + to - from - 1);
items.insert(items.begin() + idx, dives.begin() + from, dives.begin() + to);
@ -1567,7 +1563,7 @@ void DiveTripModelList::addDives(QVector<dive *> &dives)
void DiveTripModelList::removeDives(QVector<dive *> dives)
{
std::sort(dives.begin(), dives.end(), dive_less_than);
std::sort(dives.begin(), dives.end(), dive_less_than_ptr);
processRangesZip(items, dives,
std::equal_to<const dive *>(), // Condition: dive-pointers are equal
[&](std::vector<dive *> &items, const QVector<dive *> &, int from, int to, int) -> int { // Action
@ -1607,7 +1603,7 @@ void DiveTripModelList::diveSiteChanged(dive_site *ds, int field)
void DiveTripModelList::divesChanged(const QVector<dive *> &divesIn)
{
QVector<dive *> dives = divesIn;
std::sort(dives.begin(), dives.end(), dive_less_than);
std::sort(dives.begin(), dives.end(), dive_less_than_ptr);
ShownChange shownChange = updateShown(dives);
removeDives(shownChange.newHidden);
@ -1641,7 +1637,7 @@ void DiveTripModelList::divesTimeChanged(timestamp_t delta, const QVector<dive *
QVector<dive *> dives = visibleDives(divesIn);
if (dives.empty())
return;
std::sort(dives.begin(), dives.end(), dive_less_than);
std::sort(dives.begin(), dives.end(), dive_less_than_ptr);
// See comment for DiveTripModelTree::divesTimeChanged above.
divesDeletedInternal(dives); // Use internal version to keep current dive

View file

@ -3,7 +3,7 @@
my $input = $ARGV[0];
my $source = `clang-format $input`;
# for_each_dive (...) and friends...
# for_each (...) and friends...
$source =~ s/(?:\G|^)(.*each.*\(.*) \* (\S.*\))$/$1 *$2/img; # if a variable is declared in the argument, '*' is an indicator for a pointer, not arithmatic
$source =~ s/(?:\G|^)(.*each.*\(.*) \& (\S.*\))$/$1 &$2/img; # if a variable is declared in the argument, '&' is an indicator for a reference, not bit logic
$source =~ s/(?:\G|^)(.*each[^\s(]*)\s*(\(.*)$/$1 $2/img; # we want exactly one space between keyword and opening parenthesis '('

View file

@ -1016,11 +1016,11 @@ void smartrak_import(const char *file, struct divelog *log)
smtk_parse_bookmarks(mdb_clon, smtkdive.get(), (char *)col[0]->bind_ptr);
concat(smtkdive->notes, "\n", std::string((char *)col[coln(REMARKS)]->bind_ptr));
record_dive_to_table(smtkdive.release(), log->dives.get());
log->dives.record_dive(std::move(smtkdive));
}
mdb_free_catalog(mdb_clon);
mdb->catalog = NULL;
mdb_close(mdb_clon);
mdb_close(mdb);
sort_dive_table(log->dives.get());
log->dives.sort();
}

View file

@ -1381,7 +1381,7 @@ struct DiveNrVariable : public StatsVariableTemplate<StatsVariable::Type::Numeri
return StatsTranslations::tr("Dive #");
}
std::vector<const StatsBinner *> binners() const override {
if (divelog.dives->nr > 1000)
if (divelog.dives.size() > 1000)
return { &dive_nr_binner_20, &dive_nr_binner_50, &dive_nr_binner_100, &dive_nr_binner_200 };
else
return { &dive_nr_binner_5, &dive_nr_binner_10, &dive_nr_binner_20, &dive_nr_binner_50 };

View file

@ -106,7 +106,6 @@ int main(int argc, char **argv)
if (!quit)
run_ui();
exit_ui();
divelog.clear();
parse_xml_exit();
subsurface_console_exit();

View file

@ -109,7 +109,6 @@ int main(int argc, char **argv)
printf("No log files given, not saving dive data.\n");
printf("Give a log file name as argument, or configure a cloud URL.\n");
}
divelog.clear();
parse_xml_exit();
// Sync struct preferences to disk

View file

@ -92,7 +92,6 @@ int main(int argc, char **argv)
if (!quit)
run_mobile_ui(initial_font_size);
exit_ui();
divelog.clear();
parse_xml_exit();
subsurface_console_exit();

View file

@ -363,7 +363,7 @@ void TestGitStorage::testGitStorageCloudMerge2()
QCOMPARE(parse_file(cloudTestRepo.c_str(), &divelog), 0);
process_loaded_dives();
struct dive *dive = get_dive(1);
divelog.delete_single_dive(1);
divelog.delete_multiple_dives(std::vector<struct dive *>{ dive });
QCOMPARE(save_dives("./SampleDivesMinus1.ssrf"), 0);
git_local_only = true;
QCOMPARE(save_dives(localCacheRepo.c_str()), 0);

View file

@ -28,9 +28,9 @@ void TestMerge::testMergeEmpty()
*/
struct divelog log;
QCOMPARE(parse_file(SUBSURFACE_TEST_DATA "/dives/test47.xml", &log), 0);
add_imported_dives(&log, IMPORT_MERGE_ALL_TRIPS);
add_imported_dives(log, IMPORT_MERGE_ALL_TRIPS);
QCOMPARE(parse_file(SUBSURFACE_TEST_DATA "/dives/test48.xml", &log), 0);
add_imported_dives(&log, IMPORT_MERGE_ALL_TRIPS);
add_imported_dives(log, IMPORT_MERGE_ALL_TRIPS);
QCOMPARE(save_dives("./testmerge47+48.ssrf"), 0);
QFile org(SUBSURFACE_TEST_DATA "/dives/test47+48.xml");
org.open(QFile::ReadOnly);
@ -51,9 +51,9 @@ void TestMerge::testMergeBackwards()
*/
struct divelog log;
QCOMPARE(parse_file(SUBSURFACE_TEST_DATA "/dives/test48.xml", &log), 0);
add_imported_dives(&log, IMPORT_MERGE_ALL_TRIPS);
add_imported_dives(log, IMPORT_MERGE_ALL_TRIPS);
QCOMPARE(parse_file(SUBSURFACE_TEST_DATA "/dives/test47.xml", &log), 0);
add_imported_dives(&log, IMPORT_MERGE_ALL_TRIPS);
add_imported_dives(log, IMPORT_MERGE_ALL_TRIPS);
QCOMPARE(save_dives("./testmerge47+48.ssrf"), 0);
QFile org(SUBSURFACE_TEST_DATA "/dives/test48+47.xml");
org.open(QFile::ReadOnly);

View file

@ -118,19 +118,21 @@ int TestParse::parseV3()
void TestParse::testParse()
{
// On some platforms (Windows) size_t has a different format string.
// Let's just cast to int.
QCOMPARE(parseCSV(0, SUBSURFACE_TEST_DATA "/dives/test41.csv"), 0);
fprintf(stderr, "number of dives %d \n", divelog.dives->nr);
fprintf(stderr, "number of dives %d \n", static_cast<int>(divelog.dives.size()));
QCOMPARE(parseDivingLog(), 0);
fprintf(stderr, "number of dives %d \n", divelog.dives->nr);
fprintf(stderr, "number of dives %d \n", static_cast<int>(divelog.dives.size()));
QCOMPARE(parseV2NoQuestion(), 0);
fprintf(stderr, "number of dives %d \n", divelog.dives->nr);
fprintf(stderr, "number of dives %d \n", static_cast<int>(divelog.dives.size()));
QCOMPARE(parseV3(), 0);
fprintf(stderr, "number of dives %d \n", divelog.dives->nr);
fprintf(stderr, "number of dives %d \n", static_cast<int>(divelog.dives.size()));
sort_dive_table(divelog.dives);
divelog.dives.sort();
QCOMPARE(save_dives("./testout.ssrf"), 0);
FILE_COMPARE("./testout.ssrf",
@ -142,7 +144,7 @@ void TestParse::testParseDM4()
QCOMPARE(sqlite3_open(SUBSURFACE_TEST_DATA "/dives/TestDiveDM4.db", &_sqlite3_handle), 0);
QCOMPARE(parse_dm4_buffer(_sqlite3_handle, 0, 0, 0, &divelog), 0);
sort_dive_table(divelog.dives);
divelog.dives.sort();
QCOMPARE(save_dives("./testdm4out.ssrf"), 0);
FILE_COMPARE("./testdm4out.ssrf",
@ -154,7 +156,7 @@ void TestParse::testParseDM5()
QCOMPARE(sqlite3_open(SUBSURFACE_TEST_DATA "/dives/TestDiveDM5.db", &_sqlite3_handle), 0);
QCOMPARE(parse_dm5_buffer(_sqlite3_handle, 0, 0, 0, &divelog), 0);
sort_dive_table(divelog.dives);
divelog.dives.sort();
QCOMPARE(save_dives("./testdm5out.ssrf"), 0);
FILE_COMPARE("./testdm5out.ssrf",
@ -186,19 +188,19 @@ void TestParse::testParseHUDC()
&params, "csv", &divelog),
0);
QCOMPARE(divelog.dives->nr, 1);
QCOMPARE(divelog.dives.size(), 1);
/*
* CSV import uses time and date stamps relative to current
* time, thus we need to use a static (random) timestamp
*/
if (divelog.dives->nr > 0) {
struct dive *dive = divelog.dives->dives[divelog.dives->nr - 1];
dive->when = 1255152761;
dive->dcs[0].when = 1255152761;
if (!divelog.dives.empty()) {
struct dive &dive = *divelog.dives.back();
dive.when = 1255152761;
dive.dcs[0].when = 1255152761;
}
sort_dive_table(divelog.dives);
divelog.dives.sort();
QCOMPARE(save_dives("./testhudcout.ssrf"), 0);
FILE_COMPARE("./testhudcout.ssrf",
@ -232,12 +234,12 @@ void TestParse::testParseNewFormat()
.toLatin1()
.data(), &divelog),
0);
QCOMPARE(divelog.dives->nr, i + 1);
QCOMPARE(divelog.dives.size(), i + 1);
}
sort_dive_table(divelog.dives);
divelog.dives.sort();
fprintf(stderr, "number of dives %d \n", divelog.dives->nr);
fprintf(stderr, "number of dives %d \n", static_cast<int>(divelog.dives.size()));
QCOMPARE(save_dives("./testsbnewout.ssrf"), 0);
// Currently the CSV parse fails
@ -253,9 +255,9 @@ void TestParse::testParseDLD()
QVERIFY(err > 0);
QVERIFY(try_to_open_zip(filename.toLatin1().data(), &divelog) > 0);
fprintf(stderr, "number of dives from DLD: %d \n", divelog.dives->nr);
fprintf(stderr, "number of dives from DLD: %d \n", static_cast<int>(divelog.dives.size()));
sort_dive_table(divelog.dives);
divelog.dives.sort();
// Compare output
QCOMPARE(save_dives("./testdldout.ssrf"), 0);
@ -271,7 +273,7 @@ void TestParse::testParseMerge()
QCOMPARE(parse_file(SUBSURFACE_TEST_DATA "/dives/ostc.xml", &divelog), 0);
QCOMPARE(parse_file(SUBSURFACE_TEST_DATA "/dives/vyper.xml", &divelog), 0);
sort_dive_table(divelog.dives);
divelog.dives.sort();
QCOMPARE(save_dives("./testmerge.ssrf"), 0);
FILE_COMPARE("./testmerge.ssrf",
@ -324,21 +326,16 @@ void TestParse::exportCSVDiveDetails()
export_dives_xslt("testcsvexportmanual.csv", 0, 0, "xml2manualcsv.xslt", false);
export_dives_xslt("testcsvexportmanualimperial.csv", 0, 1, "xml2manualcsv.xslt", false);
if (divelog.dives->nr > 0) {
struct dive *dive = divelog.dives->dives[divelog.dives->nr - 1];
saved_sac = dive->sac;
}
if (!divelog.dives.empty())
saved_sac = divelog.dives.back()->sac;
clear_dive_file_data();
parseCSVmanual(1, "testcsvexportmanualimperial.csv");
// We do not currently support reading SAC, thus faking it
if (divelog.dives->nr > 0) {
struct dive *dive = divelog.dives->dives[divelog.dives->nr - 1];
dive->sac = saved_sac;
}
sort_dive_table(divelog.dives);
if (!divelog.dives.empty())
divelog.dives.back()->sac = saved_sac;
divelog.dives.sort();
export_dives_xslt("testcsvexportmanual2.csv", 0, 0, "xml2manualcsv.xslt", false);
FILE_COMPARE("testcsvexportmanual2.csv",
@ -358,10 +355,8 @@ void TestParse::exportSubsurfaceCSV()
export_dives_xslt("testcsvexportmanual-cyl.csv", 0, 0, "xml2manualcsv.xslt", false);
export_dives_xslt("testcsvexportmanualimperial-cyl.csv", 0, 1, "xml2manualcsv.xslt", false);
if (divelog.dives->nr > 0) {
struct dive *dive = divelog.dives->dives[divelog.dives->nr - 1];
saved_sac = dive->sac;
}
if (!divelog.dives.empty())
saved_sac = divelog.dives.back()->sac;
clear_dive_file_data();
@ -370,12 +365,10 @@ void TestParse::exportSubsurfaceCSV()
parse_csv_file("testcsvexportmanualimperial-cyl.csv", &params, "SubsurfaceCSV", &divelog);
// We do not currently support reading SAC, thus faking it
if (divelog.dives->nr > 0) {
struct dive *dive = divelog.dives->dives[divelog.dives->nr - 1];
dive->sac = saved_sac;
}
if (!divelog.dives.empty())
divelog.dives.back()->sac = saved_sac;
sort_dive_table(divelog.dives);
divelog.dives.sort();
export_dives_xslt("testcsvexportmanual2-cyl.csv", 0, 0, "xml2manualcsv.xslt", false);
FILE_COMPARE("testcsvexportmanual2-cyl.csv",
@ -414,7 +407,7 @@ void TestParse::exportCSVDiveProfile()
clear_dive_file_data();
parseCSVprofile(1, "testcsvexportprofileimperial.csv");
sort_dive_table(divelog.dives);
divelog.dives.sort();
export_dives_xslt("testcsvexportprofile2.csv", 0, 0, "xml2csv.xslt", false);
FILE_COMPARE("testcsvexportprofile2.csv",
@ -432,7 +425,7 @@ void TestParse::exportUDDF()
clear_dive_file_data();
parse_file("testuddfexport.uddf", &divelog);
sort_dive_table(divelog.dives);
divelog.dives.sort();
export_dives_xslt("testuddfexport2.uddf", 0, 1, "uddf-export.xslt", false);
FILE_COMPARE("testuddfexport.uddf",
@ -478,9 +471,9 @@ void TestParse::parseDL7()
QCOMPARE(parse_csv_file(SUBSURFACE_TEST_DATA "/dives/DL7.zxu",
&params, "DL7", &divelog),
0);
QCOMPARE(divelog.dives->nr, 3);
QCOMPARE(divelog.dives.size(), 3);
sort_dive_table(divelog.dives);
divelog.dives.sort();
QCOMPARE(save_dives("./testdl7out.ssrf"), 0);
FILE_COMPARE("./testdl7out.ssrf",

View file

@ -487,7 +487,7 @@ void TestPlan::testMetric()
#if DEBUG
dive.notes.clear();
save_dive(stdout, &dive, false);
save_dive(stdout, dive, false);
#endif
// check minimum gas result
@ -527,7 +527,7 @@ void TestPlan::testImperial()
#if DEBUG
dive.notes.clear();
save_dive(stdout, &dive, false);
save_dive(stdout, dive, false);
#endif
// check minimum gas result
@ -566,7 +566,7 @@ void TestPlan::testVpmbMetric45m30minTx()
#if DEBUG
dive.notes.clear();
save_dive(stdout, &dive, false);
save_dive(stdout, dive, false);
#endif
// check minimum gas result
@ -595,7 +595,7 @@ void TestPlan::testVpmbMetric60m10minTx()
#if DEBUG
dive.notes.clear();
save_dive(stdout, &dive, false);
save_dive(stdout, dive, false);
#endif
// check minimum gas result
@ -624,7 +624,7 @@ void TestPlan::testVpmbMetric60m30minAir()
#if DEBUG
dive.notes.clear();
save_dive(stdout, &dive, false);
save_dive(stdout, dive, false);
#endif
// check minimum gas result
@ -653,7 +653,7 @@ void TestPlan::testVpmbMetric60m30minEan50()
#if DEBUG
dive.notes.clear();
save_dive(stdout, &dive, false);
save_dive(stdout, dive, false);
#endif
// check minimum gas result
@ -688,7 +688,7 @@ void TestPlan::testVpmbMetric60m30minTx()
#if DEBUG
dive.notes.clear();
save_dive(stdout, &dive, false);
save_dive(stdout, dive, false);
#endif
// check minimum gas result
@ -723,7 +723,7 @@ void TestPlan::testVpmbMetric100m60min()
#if DEBUG
dive.notes.clear();
save_dive(stdout, &dive, false);
save_dive(stdout, dive, false);
#endif
// check minimum gas result
@ -765,7 +765,7 @@ void TestPlan::testMultipleGases()
#if DEBUG
dive.notes.clear();
save_dive(stdout, &dive, false);
save_dive(stdout, dive, false);
#endif
gasmix gas;
@ -789,7 +789,7 @@ void TestPlan::testVpmbMetricMultiLevelAir()
#if DEBUG
dive.notes.clear();
save_dive(stdout, &dive, false);
save_dive(stdout, dive, false);
#endif
// check minimum gas result
@ -818,7 +818,7 @@ void TestPlan::testVpmbMetric100m10min()
#if DEBUG
dive.notes.clear();
save_dive(stdout, &dive, false);
save_dive(stdout, dive, false);
#endif
// check minimum gas result
@ -864,7 +864,7 @@ void TestPlan::testVpmbMetricRepeat()
#if DEBUG
dive.notes.clear();
save_dive(stdout, &dive, false);
save_dive(stdout, dive, false);
#endif
// check minimum gas result
@ -884,7 +884,7 @@ void TestPlan::testVpmbMetricRepeat()
#if DEBUG
dive.notes.clear();
save_dive(stdout, &dive, false);
save_dive(stdout, dive, false);
#endif
// check minimum gas result
@ -921,7 +921,7 @@ void TestPlan::testVpmbMetricRepeat()
#if DEBUG
dive.notes.clear();
save_dive(stdout, &dive, false);
save_dive(stdout, dive, false);
#endif
// check minimum gas result
@ -959,7 +959,7 @@ void TestPlan::testCcrBailoutGasSelection()
#if DEBUG
dive.notes.clear();
save_dive(stdout, &dive, false);
save_dive(stdout, dive, false);
#endif
// check diluent used

View file

@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include "testprofile.h"
#include "core/device.h"
#include "core/dive.h"
#include "core/divelog.h"
#include "core/divesite.h"
#include "core/trip.h"
@ -34,7 +35,7 @@ void TestProfile::testProfileExport()
{
prefs.planner_deco_mode = BUEHLMANN;
parse_file(SUBSURFACE_TEST_DATA "/dives/abitofeverything.ssrf", &divelog);
sort_dive_table(divelog.dives);
divelog.dives.sort();
save_profiledata("exportprofile.csv", false);
QFile org(SUBSURFACE_TEST_DATA "/dives/exportprofilereference.csv");
QCOMPARE(org.open(QFile::ReadOnly), true);
@ -51,7 +52,7 @@ void TestProfile::testProfileExportVPMB()
{
prefs.planner_deco_mode = VPMB;
parse_file(SUBSURFACE_TEST_DATA "/dives/abitofeverything.ssrf", &divelog);
sort_dive_table(divelog.dives);
divelog.dives.sort();
save_profiledata("exportprofileVPMB.csv", false);
QFile org(SUBSURFACE_TEST_DATA "/dives/exportprofilereferenceVPMB.csv");
QCOMPARE(org.open(QFile::ReadOnly), true);

View file

@ -20,16 +20,16 @@ void TestRenumber::testMerge()
{
struct divelog log;
QCOMPARE(parse_file(SUBSURFACE_TEST_DATA "/dives/test47b.xml", &log), 0);
add_imported_dives(&log, IMPORT_MERGE_ALL_TRIPS);
QCOMPARE(divelog.dives->nr, 1);
add_imported_dives(log, IMPORT_MERGE_ALL_TRIPS);
QCOMPARE(divelog.dives.size(), 1);
}
void TestRenumber::testMergeAndAppend()
{
struct divelog log;
QCOMPARE(parse_file(SUBSURFACE_TEST_DATA "/dives/test47c.xml", &log), 0);
add_imported_dives(&log, IMPORT_MERGE_ALL_TRIPS);
QCOMPARE(divelog.dives->nr, 2);
add_imported_dives(log, IMPORT_MERGE_ALL_TRIPS);
QCOMPARE(divelog.dives.size(), 2);
struct dive *d = get_dive(1);
QVERIFY(d != NULL);
if (d)