From adbd8b1a0a106e7ca32f15a447c85d5aa27bb41b Mon Sep 17 00:00:00 2001 From: Berthold Stoeger Date: Fri, 7 Jun 2024 10:25:09 +0200 Subject: [PATCH] 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 --- .clang-format | 2 +- Subsurface-mobile.pro | 3 + backend-shared/exportfuncs.cpp | 31 +- commands/command_base.cpp | 2 +- commands/command_divelist.cpp | 75 ++- commands/command_edit.cpp | 8 +- core/CMakeLists.txt | 2 + core/cochran.cpp | 2 +- core/datatrak.cpp | 4 +- core/dive.cpp | 48 +- core/dive.h | 21 +- core/divefilter.cpp | 32 +- core/divelist.cpp | 554 ++++++++----------- core/divelist.h | 41 +- core/divelog.cpp | 64 ++- core/divelog.h | 3 + core/divesite.cpp | 7 + core/divesite.h | 28 +- core/divesitetable.h | 27 + core/downloadfromdcthread.cpp | 4 +- core/equipment.cpp | 3 +- core/fulltext.cpp | 12 +- core/import-csv.cpp | 4 +- core/libdivecomputer.cpp | 23 +- core/liquivision.cpp | 3 +- core/load-git.cpp | 2 +- core/ostctools.cpp | 3 +- core/owning_table.h | 11 + core/parse.cpp | 15 +- core/picture.cpp | 35 +- core/planner.cpp | 2 +- core/qthelper.cpp | 4 +- core/save-git.cpp | 113 ++-- core/save-html.cpp | 123 ++-- core/save-html.h | 12 +- core/save-profiledata.cpp | 8 +- core/save-xml.cpp | 203 ++++--- core/selection.cpp | 64 +-- core/statistics.cpp | 85 ++- core/string-format.cpp | 6 +- core/trip.cpp | 55 +- core/trip.h | 17 +- core/triptable.h | 21 + core/uemis-downloader.cpp | 75 +-- core/uploadDiveLogsDE.cpp | 11 +- core/worldmap-save.cpp | 34 +- desktop-widgets/divelistview.cpp | 4 +- desktop-widgets/downloadfromdivecomputer.cpp | 2 +- desktop-widgets/findmovedimagesdialog.cpp | 10 +- desktop-widgets/mainwindow.cpp | 2 +- desktop-widgets/printer.cpp | 11 +- desktop-widgets/simplewidgets.cpp | 6 +- map-widget/qmlmapwidgethelper.cpp | 17 +- mobile-widgets/qmlmanager.cpp | 40 +- profile-widget/qmlprofile.cpp | 7 +- qt-models/completionmodels.cpp | 12 +- qt-models/diveimportedmodel.cpp | 41 +- qt-models/divepicturemodel.cpp | 2 +- qt-models/diveplannermodel.cpp | 7 +- qt-models/divesummarymodel.cpp | 6 +- qt-models/divetripmodel.cpp | 36 +- scripts/whitespace.pl | 2 +- smtk-import/smartrak.cpp | 4 +- stats/statsvariables.cpp | 2 +- subsurface-desktop-main.cpp | 1 - subsurface-downloader-main.cpp | 1 - subsurface-mobile-main.cpp | 1 - tests/testgitstorage.cpp | 2 +- tests/testmerge.cpp | 8 +- tests/testparse.cpp | 54 +- tests/testplan.cpp | 30 +- tests/testrenumber.cpp | 8 +- 72 files changed, 1009 insertions(+), 1209 deletions(-) create mode 100644 core/divesitetable.h create mode 100644 core/triptable.h diff --git a/.clang-format b/.clang-format index e753e2b49..30d424e2c 100644 --- a/.clang-format +++ b/.clang-format @@ -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 diff --git a/Subsurface-mobile.pro b/Subsurface-mobile.pro index 8062ca057..3b79311e6 100644 --- a/Subsurface-mobile.pro +++ b/Subsurface-mobile.pro @@ -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 \ diff --git a/backend-shared/exportfuncs.cpp b/backend-shared/exportfuncs.cpp index 0383a56cc..33beedbe7 100644 --- a/backend-shared/exportfuncs.cpp +++ b/backend-shared/exportfuncs.cpp @@ -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 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(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(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(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; diff --git a/commands/command_base.cpp b/commands/command_base.cpp index a33c31b86..7072951e9 100644 --- a/commands/command_base.cpp +++ b/commands/command_base.cpp @@ -66,7 +66,7 @@ QString diveNumberOrDate(struct dive *d) QString getListOfDives(const std::vector &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) { diff --git a/commands/command_divelist.cpp b/commands/command_divelist.cpp index f233e4bc7..eeb827df9 100644 --- a/commands/command_divelist.cpp +++ b/commands/command_divelist.cpp @@ -44,13 +44,13 @@ DiveToAdd DiveListBase::removeDive(struct dive *d, std::vectorget_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 = std::move(divelog.dives->unregister_dive(idx)); // Remove dive from backend return res; } @@ -88,7 +88,7 @@ void processByTrip(std::vector> &dives, Function // Sort lexicographically by trip then according to the dive_less_than() function. std::sort(dives.begin(), dives.end(), [](const std::pair &e1, const std::pair &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 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 &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 &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 &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 &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(divelog.dives->dives[i], newnr)); + divesToRenumber.append(QPair((*divelog.dives)[i].get(), newnr)); previousnr = newnr; } } diff --git a/commands/command_edit.cpp b/commands/command_edit.cpp index bd5678a0f..765a8cb0b 100644 --- a/commands/command_edit.cpp +++ b/commands/command_edit.cpp @@ -62,11 +62,9 @@ static std::vector getDives(bool currentDiveOnly) : std::vector { }; std::vector 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 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!"); diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 8d7948b03..22237a79f 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -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 diff --git a/core/cochran.cpp b/core/cochran.cpp index 5cad4cd0b..bedd4e696 100644 --- a/core/cochran.cpp +++ b/core/cochran.cpp @@ -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); } diff --git a/core/datatrak.cpp b/core/datatrak.cpp index 41707bd30..89a8909ee 100644 --- a/core/datatrak.cpp +++ b/core/datatrak.cpp @@ -699,12 +699,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; diff --git a/core/dive.cpp b/core/dive.cpp index 9f60701b0..edc8de895 100644 --- a/core/dive.cpp +++ b/core/dive.cpp @@ -2377,10 +2377,10 @@ static void force_fixup_dive(struct dive *d) */ static std::array, 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 */ @@ -2462,7 +2462,7 @@ static std::array, 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; @@ -2894,9 +2894,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(nr) >= divelog.dives->size()) + return nullptr; + return (*divelog.dives)[nr].get(); } struct dive_site *get_dive_site_for_dive(const struct dive *dive) @@ -2934,42 +2934,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); diff --git a/core/dive.h b/core/dive.h index 5d0c8c253..238a25402 100644 --- a/core/dive.h +++ b/core/dive.h @@ -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 clone_make_first_dc(const struct dive &d, int dc_nu extern std::unique_ptr clone_delete_divecomputer(const struct dive &d, int dc_number); extern std::array, 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 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); diff --git a/core/divefilter.cpp b/core/divefilter.cpp index 6cca6a12d..34ce8f0a6 100644 --- a/core/divefilter.cpp +++ b/core/divefilter.cpp @@ -74,10 +74,8 @@ ShownChange DiveFilter::update(const QVector &dives) const void DiveFilter::reset() { - int i; - dive *d; - shown_dives = divelog.dives->nr; - for_each_dive(i, d) + shown_dives = static_cast(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 selection = getDiveSelection(); std::vector 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(), 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 DiveFilter::visibleDives() const std::vector 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; } diff --git a/core/divelist.cpp b/core/divelist.cpp index 4e2ee3a5e..9d4894804 100644 --- a/core/divelist.cpp +++ b/core/divelist.cpp @@ -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 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(divenr) + : static_cast(divelog.dives->size()); + int nr_dives = static_cast(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(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(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(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(divelog.dives->size()); + size_t divenr = divelog.dives->get_idx(dive); + int i = divenr != std::string::npos ? static_cast(divenr) + : static_cast(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(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(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_table::unregister_dive(int idx) { - struct dive *dive = get_dive(idx); - if (!dive) - return NULL; /* this should never happen */ + if (idx < 0 || static_cast(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 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 &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 &dives_from, struct dive_table *delete_from, +static bool merge_dive_tables(const std::vector &dives_from, struct dive_table &delete_from, const std::vector &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 &dives_to_remove, + int &num_merged) { bool sequence_changed = false; @@ -884,11 +843,18 @@ static bool merge_dive_tables(const std::vector &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 &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 &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 &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 &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_table_to_non_owning(const dive_table &dives) { std::vector 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_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(), + 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(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() @@ -1261,28 +1194,25 @@ void report_datafile_version(int version) int get_dive_id_closest_to(timestamp_t when) { - int i; - int nr = divelog.dives->nr; - // deal with pathological cases - if (nr == 0) + if (divelog.dives->empty()) return 0; - else if (nr == 1) - return divelog.dives->dives[0]->id; + else if (divelog.dives->size() == 1) + return divelog.dives->front()->id; - for (i = 0; i < nr && divelog.dives->dives[i]->when <= when; i++) - ; // nothing + auto it = std::find_if(divelog.dives->begin(), divelog.dives->end(), + [when] (auto &d) { return d->when > when; }); // again, capture the two edge cases first - if (i == nr) - return divelog.dives->dives[i - 1]->id; - else if (i == 0) - return divelog.dives->dives[0]->id; + if (it == divelog.dives->end()) + return divelog.dives->back()->id; + else if (it == divelog.dives->begin()) + return (*it)->id; - if (when - divelog.dives->dives[i - 1]->when < divelog.dives->dives[i]->when - when) - return divelog.dives->dives[i - 1]->id; + if (when - (*std::prev(it))->when < (*it)->when - when) + return (*std::prev(it))->id; else - return divelog.dives->dives[i]->id; + return (*it)->id; } void clear_dive_file_data() @@ -1304,11 +1234,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) { @@ -1316,7 +1251,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) @@ -1334,7 +1269,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) @@ -1360,18 +1295,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; @@ -1381,43 +1313,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; + }); + }); } diff --git a/core/divelist.h b/core/divelist.h index 58000c146..998df6dd0 100644 --- a/core/divelist.h +++ b/core/divelist.h @@ -2,27 +2,29 @@ #ifndef DIVELIST_H #define DIVELIST_H +#include "triptable.h" +#include "divesitetable.h" #include "units.h" #include #include 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 *get_by_uniq_id(int id) const; + void record_dive(std::unique_ptr d); // call fixup_dive() before adding dive to table. + std::unique_ptr 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,31 +35,28 @@ 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 &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 dives_to_remove; + trip_table trips_to_add; + dive_site_table sites_to_add; + std::vector 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); int get_dive_id_closest_to(timestamp_t when); 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 d); extern bool has_dive(unsigned int deviceid, unsigned int diveid); diff --git a/core/divelog.cpp b/core/divelog.cpp index 208e583eb..c97cf11a0 100644 --- a/core/divelog.cpp +++ b/core/divelog.cpp @@ -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" @@ -16,15 +17,9 @@ divelog::divelog() : filter_presets(std::make_unique()), 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 +27,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(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 +41,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 &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; + } +} diff --git a/core/divelog.h b/core/divelog.h index e105ebe80..7d17f68e2 100644 --- a/core/divelog.h +++ b/core/divelog.h @@ -6,6 +6,7 @@ #include #include +struct dive; struct dive_table; struct trip_table; class dive_site_table; @@ -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 &dives); void clear(); + bool is_trip_before_after(const struct dive *dive, bool before) const; }; extern struct divelog divelog; diff --git a/core/divesite.cpp b/core/divesite.cpp index 3a6bdf0e6..77a5f0b3a 100644 --- a/core/divesite.cpp +++ b/core/divesite.cpp @@ -11,6 +11,13 @@ #include +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 dive_site *get_by_predicate(const dive_site_table &ds_table, PRED pred) { diff --git a/core/divesite.h b/core/divesite.h index 07604cda7..4b542518c 100644 --- a/core/divesite.h +++ b/core/divesite.h @@ -3,13 +3,10 @@ #define DIVESITE_H #include "divelist.h" -#include "owning_table.h" #include "taxonomy.h" #include "units.h" #include -#include - 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 { -public: - put_result register_site(std::unique_ptr 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 Q_DECLARE_METATYPE(dive_site *); #endif // DIVESITE_H diff --git a/core/divesitetable.h b/core/divesitetable.h new file mode 100644 index 000000000..e4bbc9bb6 --- /dev/null +++ b/core/divesitetable.h @@ -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 { +public: + put_result register_site(std::unique_ptr 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 diff --git a/core/downloadfromdcthread.cpp b/core/downloadfromdcthread.cpp index 79a95ccb7..170513a42 100644 --- a/core/downloadfromdcthread.cpp +++ b/core/downloadfromdcthread.cpp @@ -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(log.dives->size())); } qPrefDiveComputer::set_vendor(internalData->vendor.c_str()); qPrefDiveComputer::set_product(internalData->product.c_str()); diff --git a/core/equipment.cpp b/core/equipment.cpp index c5a8cf1bb..c3f331eee 100644 --- a/core/equipment.cpp +++ b/core/equipment.cpp @@ -284,8 +284,7 @@ void reset_tank_info_table(std::vector &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); } diff --git a/core/fulltext.cpp b/core/fulltext.cpp index a8dd45bc1..61e9b8e69 100644 --- a/core/fulltext.cpp +++ b/core/fulltext.cpp @@ -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(); } diff --git a/core/import-csv.cpp b/core/import-csv.cpp index 347b52ab4..72eebac89 100644 --- a/core/import-csv.cpp +++ b/core/import-csv.cpp @@ -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; diff --git a/core/libdivecomputer.cpp b/core/libdivecomputer.cpp index 7bb040cb1..0a59d409b 100644 --- a/core/libdivecomputer.cpp +++ b/core/libdivecomputer.cpp @@ -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); diff --git a/core/liquivision.cpp b/core/liquivision.cpp index cda12b1d2..e611b61ca 100644 --- a/core/liquivision.cpp +++ b/core/liquivision.cpp @@ -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; diff --git a/core/load-git.cpp b/core/load-git.cpp index ed951f19f..96caca5e2 100644 --- a/core/load-git.cpp +++ b/core/load-git.cpp @@ -1386,7 +1386,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) diff --git a/core/ostctools.cpp b/core/ostctools.cpp index 225aa145c..4fa4fa839 100644 --- a/core/ostctools.cpp +++ b/core/ostctools.cpp @@ -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)); } diff --git a/core/owning_table.h b/core/owning_table.h index cfc7765c1..8276e7a07 100644 --- a/core/owning_table.h +++ b/core/owning_table.h @@ -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; }); } diff --git a/core/parse.cpp b/core/parse.cpp index 59bee0cdf..2e1057515 100644 --- a/core/parse.cpp +++ b/core/parse.cpp @@ -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; diff --git a/core/picture.cpp b/core/picture.cpp index 508cdfb54..9a999508a 100644 --- a/core/picture.cpp +++ b/core/picture.cpp @@ -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, 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, 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 diff --git a/core/planner.cpp b/core/planner.cpp index 3bf63227a..f30bd1883 100644 --- a/core/planner.cpp +++ b/core/planner.cpp @@ -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; } diff --git a/core/qthelper.cpp b/core/qthelper.cpp index d89c40d48..e799f56a6 100644 --- a/core/qthelper.cpp +++ b/core/qthelper.cpp @@ -989,13 +989,13 @@ 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"); + 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"); + return !dives.empty() ? get_dive_only_date_string(dives.back()->when) : gettextFromC::tr("no dives"); } std::string get_current_date() diff --git a/core/save-git.cpp b/core/save-git.cpp index 0dc8bf9d8..e7d7095db 100644 --- a/core/save-git.cpp +++ b/core/save-git.cpp @@ -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(divelog.dives->size()); struct dive *dive = get_dive(nr-1); std::string changes_made = get_changes_made(); diff --git a/core/save-html.cpp b/core/save-html.cpp index 494d1dd0a..7741e1e8e 100644 --- a/core/save-html.cpp +++ b/core/save-html.cpp @@ -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*/ diff --git a/core/save-html.h b/core/save-html.h index 03b24a117..03eb66c73 100644 --- a/core/save-html.h +++ b/core/save-html.h @@ -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); diff --git a/core/save-profiledata.cpp b/core/save-profiledata.cpp index e3ac11136..99c779188 100644 --- a/core/save-profiledata.cpp +++ b/core/save-profiledata.cpp @@ -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++) diff --git a/core/save-xml.cpp b/core/save-xml.cpp index 74f5852bf..d144cfbd6 100644 --- a/core/save-xml.cpp +++ b/core/save-xml.cpp @@ -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, " 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, " 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, " 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_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, " 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(), " ", "\n", 0, anonymize); - show_utf8_blanked(b, dive->buddy.c_str(), " ", "\n", 0, anonymize); - show_utf8_blanked(b, dive->notes.c_str(), " ", "\n", 0, anonymize); - show_utf8_blanked(b, dive->suit.c_str(), " ", "\n", 0, anonymize); + show_utf8_blanked(b, dive.diveguide.c_str(), " ", "\n", 0, anonymize); + show_utf8_blanked(b, dive.buddy.c_str(), " ", "\n", 0, anonymize); + show_utf8_blanked(b, dive.notes.c_str(), " ", "\n", 0, anonymize); + show_utf8_blanked(b, dive.suit.c_str(), " ", "\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, " \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, " = 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, " = 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, " 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, " ", " min\n"); + put_duration(b, dc.surfacetime, " ", " min\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, "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, "\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, "divetrip == &trip) - save_one_dive_to_mb(b, dive, anonymize); + save_one_dive_to_mb(b, *dive, anonymize); } put_format(b, "\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, "\n\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; } diff --git a/core/selection.cpp b/core/selection.cpp index c201bf8ec..b50480864 100644 --- a/core/selection.cpp +++ b/core/selection.cpp @@ -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 setSelectionCore(const std::vector &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 setSelectionCore(const std::vector &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 getDiveSelection() std::vector 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 getDiveSelection() bool diveInSelection(const std::vector &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 &selection, const std::vector & { // 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 &selection, const std::vector & // 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 &selection, const std::vector & // 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 diff --git a/core/statistics.cpp b/core/statistics.cpp index d022af023..221b761e9 100644 --- a/core/statistics.cpp +++ b/core/statistics.cpp @@ -19,15 +19,15 @@ #include #include -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 get_gas_parts(struct gasmix mix, volume_t v std::pair 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; } diff --git a/core/string-format.cpp b/core/string-format.cpp index 5aa22f66c..cdddd5e59 100644 --- a/core/string-format.cpp +++ b/core/string-format.cpp @@ -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); } diff --git a/core/trip.cpp b/core/trip.cpp index 5ed1a151d..c7ba54b56 100644 --- a/core/trip.cpp +++ b/core/trip.cpp @@ -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 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> get_trip_for_new_dive(const struct dive *new_dive) +std::pair> 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 get_dives_to_autogroup(struct dive_table *table) +std::vector get_dives_to_autogroup(const struct dive_table &table) { std::vector res; struct dive *lastdive = NULL; @@ -172,12 +153,11 @@ std::vector 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 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 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 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; }); } diff --git a/core/trip.h b/core/trip.h index defd20a7a..1ada441bd 100644 --- a/core/trip.h +++ b/core/trip.h @@ -3,9 +3,8 @@ #define TRIP_H #include "divelist.h" -#include "owning_table.h" -#include +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 *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 created_trip; // Is set if the trip was newly created - caller has to store it. }; -extern std::vector get_dives_to_autogroup(struct dive_table *table); -extern std::pair> get_trip_for_new_dive(const struct dive *new_dive); +extern std::vector get_dives_to_autogroup(const struct dive_table &table); +extern std::pair> 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 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 Q_DECLARE_METATYPE(struct dive_trip *); -Q_DECLARE_METATYPE(trip_table *); #endif diff --git a/core/triptable.h b/core/triptable.h new file mode 100644 index 000000000..1b4facc0c --- /dev/null +++ b/core/triptable.h @@ -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 *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 +Q_DECLARE_METATYPE(trip_table *); + +#endif + diff --git a/core/uemis-downloader.cpp b/core/uemis-downloader.cpp index 609c5416a..f73042282 100644 --- a/core/uemis-downloader.cpp +++ b/core/uemis-downloader.cpp @@ -190,9 +190,9 @@ static std::unique_ptr 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 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 uemis_get_divenr(uint32_t deviceid, struct * * Otherwise, use the global dive table. */ - if (!force && !table->nr) + if (!force && table->empty()) table = divelog.dives.get(); - 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) { @@ -1039,17 +1023,17 @@ static bool do_dump_buffer_to_file(std::string_view buf, const char *prefix) */ 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(td->size()) > max_mem_used) + max_mem_used = filenr / static_cast(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(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; @@ -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 */ @@ -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; @@ -1292,7 +1275,7 @@ 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(); @@ -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) @@ -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; } diff --git a/core/uploadDiveLogsDE.cpp b/core/uploadDiveLogsDE.cpp index 7990bd44c..9a5af43d4 100644 --- a/core/uploadDiveLogsDE.cpp +++ b/core/uploadDiveLogsDE.cpp @@ -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, "\n\n"); } - save_one_dive_to_mb(&mb, dive, false); + save_one_dive_to_mb(&mb, *dive, false); if (ds) { put_format(&mb, "\n"); diff --git a/core/worldmap-save.cpp b/core/worldmap-save.cpp index bf22d8a5a..93baae3ce 100644 --- a/core/worldmap-save.cpp +++ b/core/worldmap-save.cpp @@ -10,10 +10,12 @@ #include #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: '
'+'
'+'
'+'
"); - pre = format_string_std("

%s ", translate("gettextFromC", "Date:")); - put_HTML_date(b, dive, pre.c_str(), "

"); + std::string pre = format_string_std("

%s ", translate("gettextFromC", "Date:")); + put_HTML_date(b, *dive, pre.c_str(), "

"); pre = format_string_std("

%s ", translate("gettextFromC", "Time:")); - put_HTML_time(b, dive, pre.c_str(), "

"); + put_HTML_time(b, *dive, pre.c_str(), "

"); pre = format_string_std("

%s ", translate("gettextFromC", "Duration:")); - post = format_string_std(" %s

", translate("gettextFromC", "min")); + std::string post = format_string_std(" %s

", translate("gettextFromC", "min")); put_duration(b, dive->duration, pre.c_str(), post.c_str()); put_string(b, "

"); put_HTML_quoted(b, translate("gettextFromC", "Max. depth:")); - put_HTML_depth(b, dive, " ", "

"); + put_HTML_depth(b, *dive, " ", "

"); put_string(b, "

"); put_HTML_quoted(b, translate("gettextFromC", "Air temp.:")); - put_HTML_airtemp(b, dive, " ", "

"); + put_HTML_airtemp(b, *dive, " ", "

"); put_string(b, "

"); put_HTML_quoted(b, translate("gettextFromC", "Water temp.:")); - put_HTML_watertemp(b, dive, " ", "

"); + put_HTML_watertemp(b, *dive, " ", "

"); pre = format_string_std("

%s ", 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, "

"); pre = format_string_std("

%s ", translate("gettextFromC", "Notes:")); - put_HTML_notes(b, dive, pre.c_str(), "

"); + put_HTML_notes(b, *dive, pre.c_str(), "

"); put_string(b, "

'+'
'+'
'});\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); diff --git a/desktop-widgets/divelistview.cpp b/desktop-widgets/divelistview.cpp index e54f96b3a..e0b1de12c 100644 --- a/desktop-widgets/divelistview.cpp +++ b/desktop-widgets/divelistview.cpp @@ -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); } } diff --git a/desktop-widgets/downloadfromdivecomputer.cpp b/desktop-widgets/downloadfromdivecomputer.cpp index bec0cce1f..96a95ae6c 100644 --- a/desktop-widgets/downloadfromdivecomputer.cpp +++ b/desktop-widgets/downloadfromdivecomputer.cpp @@ -456,7 +456,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(divelog.dives->size()); diveImportedModel->startDownload(); // FIXME: We should get the _actual_ device info instead of whatever diff --git a/desktop-widgets/findmovedimagesdialog.cpp b/desktop-widgets/findmovedimagesdialog.cpp index 0d4b75997..4f9db564d 100644 --- a/desktop-widgets/findmovedimagesdialog.cpp +++ b/desktop-widgets/findmovedimagesdialog.cpp @@ -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 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> future = QtConcurrent::run( // Note that we capture everything but "this" by copy to avoid dangling references. diff --git a/desktop-widgets/mainwindow.cpp b/desktop-widgets/mainwindow.cpp index 75bd9ba54..529a47cf0 100644 --- a/desktop-widgets/mainwindow.cpp +++ b/desktop-widgets/mainwindow.cpp @@ -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; } diff --git a/desktop-widgets/printer.cpp b/desktop-widgets/printer.cpp index 1491caed1..dbbf8237c 100644 --- a/desktop-widgets/printer.cpp +++ b/desktop-widgets/printer.cpp @@ -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 Printer::getDives() const return getDiveSelection(); } else { std::vector 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; } } diff --git a/desktop-widgets/simplewidgets.cpp b/desktop-widgets/simplewidgets.cpp index 85f38ebae..1a16be1d0 100644 --- a/desktop-widgets/simplewidgets.cpp +++ b/desktop-widgets/simplewidgets.cpp @@ -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> 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); } diff --git a/map-widget/qmlmapwidgethelper.cpp b/map-widget/qmlmapwidgethelper.cpp index e510c28ee..a5ea07918 100644 --- a/map-widget/qmlmapwidgethelper.cpp +++ b/map-widget/qmlmapwidgethelper.cpp @@ -5,9 +5,12 @@ #include #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 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 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; diff --git a/mobile-widgets/qmlmanager.cpp b/mobile-widgets/qmlmanager.cpp index ac5bba6d0..7fd56c286 100644 --- a/mobile-widgets/qmlmanager.cpp +++ b/mobile-widgets/qmlmanager.cpp @@ -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(); } diff --git a/profile-widget/qmlprofile.cpp b/profile-widget/qmlprofile.cpp index e085fe5bb..f388d5c16 100644 --- a/profile-widget/qmlprofile.cpp +++ b/profile-widget/qmlprofile.cpp @@ -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; } diff --git a/qt-models/completionmodels.cpp b/qt-models/completionmodels.cpp index 89c374e5f..9ff3caa0e 100644 --- a/qt-models/completionmodels.cpp +++ b/qt-models/completionmodels.cpp @@ -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 @@ -31,10 +33,8 @@ void CompletionModelBase::divesChanged(const QVector &, DiveField field) static QStringList getCSVList(const std::string dive::*item) { QSet 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); diff --git a/qt-models/diveimportedmodel.cpp b/qt-models/diveimportedmodel.cpp index 840c3a030..5b41dc5f6 100644 --- a/qt-models/diveimportedmodel.cpp +++ b/qt-models/diveimportedmodel.cpp @@ -16,7 +16,7 @@ int DiveImportedModel::columnCount(const QModelIndex&) const int DiveImportedModel::rowCount(const QModelIndex&) const { - return log.dives->nr; + return static_cast(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(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() << Qt::CheckStateRole << Selected); + dataChanged(index(0, 0), index(log.dives->size() - 1, 0), QVector() << 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() << Qt::CheckStateRole << Selected); + dataChanged(index(0, 0), index(log.dives->size() - 1, 0 ), QVector() << 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(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()); } diff --git a/qt-models/divepicturemodel.cpp b/qt-models/divepicturemodel.cpp index d49ef414c..5cc8b07c2 100644 --- a/qt-models/divepicturemodel.cpp +++ b/qt-models/divepicturemodel.cpp @@ -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; diff --git a/qt-models/diveplannermodel.cpp b/qt-models/diveplannermodel.cpp index 4cb3e38b2..49b34874e 100644 --- a/qt-models/diveplannermodel.cpp +++ b/qt-models/diveplannermodel.cpp @@ -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 } diff --git a/qt-models/divesummarymodel.cpp b/qt-models/divesummarymodel.cpp index 43cb8d6ce..bdcf3ab1d 100644 --- a/qt-models/divesummarymodel.cpp +++ b/qt-models/divesummarymodel.cpp @@ -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 @@ -163,10 +165,10 @@ static Stats loopDives(timestamp_t start) 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; } diff --git a/qt-models/divetripmodel.cpp b/qt-models/divetripmodel.cpp index 7e8ea02f0..32ade0c1a 100644 --- a/qt-models/divetripmodel.cpp +++ b/qt-models/divetripmodel.cpp @@ -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 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 &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 &items, const QVector &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 &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 &items, const QVector &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 &dives) void DiveTripModelList::removeDives(QVector 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(), // Condition: dive-pointers are equal [&](std::vector &items, const QVector &, int from, int to, int) -> int { // Action @@ -1607,7 +1603,7 @@ void DiveTripModelList::diveSiteChanged(dive_site *ds, int field) void DiveTripModelList::divesChanged(const QVector &divesIn) { QVector 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 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 diff --git a/scripts/whitespace.pl b/scripts/whitespace.pl index be1c4416a..3e96a2b0c 100755 --- a/scripts/whitespace.pl +++ b/scripts/whitespace.pl @@ -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 '(' diff --git a/smtk-import/smartrak.cpp b/smtk-import/smartrak.cpp index 73ece6ff3..ddf96d0cd 100644 --- a/smtk-import/smartrak.cpp +++ b/smtk-import/smartrak.cpp @@ -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(); } diff --git a/stats/statsvariables.cpp b/stats/statsvariables.cpp index 1a3891f9d..8d44708a8 100644 --- a/stats/statsvariables.cpp +++ b/stats/statsvariables.cpp @@ -1381,7 +1381,7 @@ struct DiveNrVariable : public StatsVariableTemplate 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 }; diff --git a/subsurface-desktop-main.cpp b/subsurface-desktop-main.cpp index 9750a5588..449fb4130 100644 --- a/subsurface-desktop-main.cpp +++ b/subsurface-desktop-main.cpp @@ -106,7 +106,6 @@ int main(int argc, char **argv) if (!quit) run_ui(); exit_ui(); - divelog.clear(); parse_xml_exit(); subsurface_console_exit(); diff --git a/subsurface-downloader-main.cpp b/subsurface-downloader-main.cpp index f526e8631..13259b28d 100644 --- a/subsurface-downloader-main.cpp +++ b/subsurface-downloader-main.cpp @@ -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 diff --git a/subsurface-mobile-main.cpp b/subsurface-mobile-main.cpp index da2b87bf2..0eba478b4 100644 --- a/subsurface-mobile-main.cpp +++ b/subsurface-mobile-main.cpp @@ -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(); diff --git a/tests/testgitstorage.cpp b/tests/testgitstorage.cpp index 7a1cdec64..e2e9a863f 100644 --- a/tests/testgitstorage.cpp +++ b/tests/testgitstorage.cpp @@ -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{ dive }); QCOMPARE(save_dives("./SampleDivesMinus1.ssrf"), 0); git_local_only = true; QCOMPARE(save_dives(localCacheRepo.c_str()), 0); diff --git a/tests/testmerge.cpp b/tests/testmerge.cpp index bc7fe1db7..a60cc5c80 100644 --- a/tests/testmerge.cpp +++ b/tests/testmerge.cpp @@ -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); diff --git a/tests/testparse.cpp b/tests/testparse.cpp index 8fd48889c..1835b47b3 100644 --- a/tests/testparse.cpp +++ b/tests/testparse.cpp @@ -118,17 +118,19 @@ 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(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(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(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(divelog.dives->size())); QCOMPARE(save_dives("./testout.ssrf"), 0); FILE_COMPARE("./testout.ssrf", @@ -180,16 +182,16 @@ void TestParse::testParseHUDC() ¶ms, "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; } QCOMPARE(save_dives("./testhudcout.ssrf"), 0); @@ -224,10 +226,10 @@ void TestParse::testParseNewFormat() .toLatin1() .data(), &divelog), 0); - QCOMPARE(divelog.dives->nr, i + 1); + QCOMPARE(divelog.dives->size(), i + 1); } - fprintf(stderr, "number of dives %d \n", divelog.dives->nr); + fprintf(stderr, "number of dives %d \n", static_cast(divelog.dives->size())); QCOMPARE(save_dives("./testsbnewout.ssrf"), 0); // Currently the CSV parse fails @@ -243,7 +245,7 @@ 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(divelog.dives->size())); // Compare output QCOMPARE(save_dives("./testdldout.ssrf"), 0); @@ -309,21 +311,15 @@ 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; - } - - + if (!divelog.dives->empty()) + divelog.dives->back()->sac = saved_sac; export_dives_xslt("testcsvexportmanual2.csv", 0, 0, "xml2manualcsv.xslt", false); @@ -344,10 +340,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(); @@ -356,10 +350,8 @@ void TestParse::exportSubsurfaceCSV() parse_csv_file("testcsvexportmanualimperial-cyl.csv", ¶ms, "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; export_dives_xslt("testcsvexportmanual2-cyl.csv", 0, 0, "xml2manualcsv.xslt", false); @@ -461,7 +453,7 @@ void TestParse::parseDL7() QCOMPARE(parse_csv_file(SUBSURFACE_TEST_DATA "/dives/DL7.zxu", ¶ms, "DL7", &divelog), 0); - QCOMPARE(divelog.dives->nr, 3); + QCOMPARE(divelog.dives->size(), 3); QCOMPARE(save_dives("./testdl7out.ssrf"), 0); FILE_COMPARE("./testdl7out.ssrf", diff --git a/tests/testplan.cpp b/tests/testplan.cpp index 22b46d7b1..1dea75547 100644 --- a/tests/testplan.cpp +++ b/tests/testplan.cpp @@ -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 diff --git a/tests/testrenumber.cpp b/tests/testrenumber.cpp index dfe8f5e18..c675f597a 100644 --- a/tests/testrenumber.cpp +++ b/tests/testrenumber.cpp @@ -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)