diff --git a/commands/command_divelist.cpp b/commands/command_divelist.cpp index 0ccb40991..9dabf4f80 100644 --- a/commands/command_divelist.cpp +++ b/commands/command_divelist.cpp @@ -14,11 +14,12 @@ namespace Command { // Helper function that takes care to unselect trips that are removed from the backend -static void remove_trip_from_backend(dive_trip *trip) +static std::unique_ptr remove_trip_from_backend(dive_trip *trip) { if (trip->selected) deselect_trip(trip); - remove_trip(trip, divelog.trips.get()); // Remove trip from backend + auto [t, idx] = divelog.trips->pull(trip); + return std::move(t); } // This helper function removes a dive, takes ownership of the dive and adds it to a DiveToAdd structure. @@ -40,8 +41,9 @@ DiveToAdd DiveListBase::removeDive(struct dive *d, std::vectordive_site); res.site = unregister_dive_from_dive_site(d); if (res.trip && res.trip->dives.nr == 0) { - remove_trip_from_backend(res.trip); // Remove trip from backend - tripsToAdd.emplace_back(res.trip); // Take ownership of trip + divelog.trips->sort(); // Removal of dives has changed order of trips! (TODO: remove this) + auto trip = remove_trip_from_backend(res.trip); // Remove trip from backend + tripsToAdd.push_back(std::move(trip)); // Take ownership of trip } int idx = get_divenr(d); @@ -210,8 +212,8 @@ DivesAndSitesToRemove DiveListBase::addDives(DivesAndTripsToAdd &toAdd) std::vector addedTrips; addedTrips.reserve(toAdd.trips.size()); for (std::unique_ptr &trip: toAdd.trips) { - addedTrips.push_back(trip.get()); - insert_trip(trip.release(), divelog.trips.get()); // Return ownership to backend + auto [t, idx] = divelog.trips->put(std::move(trip)); // Return ownership to backend + addedTrips.push_back(t); } toAdd.trips.clear(); @@ -271,10 +273,8 @@ static std::unique_ptr moveDiveToTrip(DiveToTrip &diveToTrip) // Remove dive from trip - if this is the last dive in the trip, remove the whole trip. dive_trip *trip = unregister_dive_from_trip(diveToTrip.dive); - if (trip && trip->dives.nr == 0) { - remove_trip_from_backend(trip); // Remove trip from backend - res.reset(trip); - } + if (trip && trip->dives.nr == 0) + res = remove_trip_from_backend(trip); // Remove trip from backend // Store old trip and get new trip we should associate this dive with std::swap(trip, diveToTrip.trip); @@ -299,9 +299,8 @@ static void moveDivesBetweenTrips(DivesToTrip &dives) // First, bring back the trip(s) for (std::unique_ptr &trip: dives.tripsToAdd) { - dive_trip *t = trip.release(); // Give up ownership + auto [t, idx] = divelog.trips->put(std::move(trip)); // Return ownership to backend createdTrips.push_back(t); - insert_trip(t, divelog.trips.get()); // Return ownership to backend } dives.tripsToAdd.clear(); @@ -425,10 +424,9 @@ AddDive::AddDive(dive *d, bool autogroup, bool newNumber) divePtr->divetrip = nullptr; divePtr->dive_site = nullptr; if (!trip && autogroup) { - bool alloc; - trip = get_trip_for_new_dive(divePtr.get(), &alloc); - if (alloc) - allocTrip.reset(trip); + auto [t, allocated] = get_trip_for_new_dive(divePtr.get()); + trip = t; + allocTrip = std::move(allocated); } int idx = dive_table_get_insertion_index(divelog.dives.get(), divePtr.get()); @@ -452,7 +450,7 @@ void AddDive::redoit() currentDive = current_dive; divesAndSitesToRemove = addDives(divesToAdd); - sort_trip_table(divelog.trips.get()); // Though unlikely, adding a dive may reorder trips + divelog.trips->sort(); // Though unlikely, adding a dive may reorder trips // Select the newly added dive setSelection(divesAndSitesToRemove.dives, divesAndSitesToRemove.dives[0], -1); @@ -462,7 +460,7 @@ void AddDive::undoit() { // Simply remove the dive that was previously added... divesToAdd = removeDives(divesAndSitesToRemove); - sort_trip_table(divelog.trips.get()); // Though unlikely, removing a dive may reorder trips + divelog.trips->sort(); // Though unlikely, removing a dive may reorder trips // ...and restore the selection setSelection(selection, currentDive, -1); @@ -477,16 +475,16 @@ ImportDives::ImportDives(struct divelog *log, int flags, const QString &source) struct dive_table dives_to_add = empty_dive_table; struct dive_table dives_to_remove = empty_dive_table; - struct trip_table trips_to_add = empty_trip_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, + &dives_to_add, &dives_to_remove, trips_to_add, sites_to_add, devicesToAddAndRemove); // Add trips to the divesToAdd.trips structure - divesToAdd.trips.reserve(trips_to_add.nr); - for (int i = 0; i < trips_to_add.nr; ++i) - divesToAdd.trips.emplace_back(trips_to_add.trips[i]); + divesToAdd.trips.reserve(trips_to_add.size()); + for (auto &trip: trips_to_add) + divesToAdd.trips.push_back(std::move(trip)); // Add sites to the divesToAdd.sites structure divesToAdd.sites = std::move(sites_to_add); @@ -522,7 +520,6 @@ ImportDives::ImportDives(struct divelog *log, int flags, const QString &source) free(dives_to_add.dives); free(dives_to_remove.dives); - free(trips_to_add.trips); } bool ImportDives::workToBeDone() @@ -606,7 +603,7 @@ bool DeleteDive::workToBeDone() void DeleteDive::undoit() { divesToDelete = addDives(divesToAdd); - sort_trip_table(divelog.trips.get()); // Though unlikely, removing a dive may reorder trips + divelog.trips->sort(); // Though unlikely, removing a dive may reorder trips // Select all re-added dives and make the first one current dive *currentDive = !divesToDelete.dives.empty() ? divesToDelete.dives[0] : nullptr; @@ -616,7 +613,7 @@ void DeleteDive::undoit() void DeleteDive::redoit() { divesToAdd = removeDives(divesToDelete); - sort_trip_table(divelog.trips.get()); // Though unlikely, adding a dive may reorder trips + divelog.trips->sort(); // Though unlikely, adding a dive may reorder trips // Deselect all dives and select dive that was close to the first deleted dive dive *newCurrent = nullptr; @@ -645,7 +642,7 @@ void ShiftTime::redoit() // Changing times may have unsorted the dive and trip tables sort_dive_table(divelog.dives.get()); - sort_trip_table(divelog.trips.get()); + divelog.trips->sort(); for (dive_trip *trip: trips) sort_dive_table(&trip->dives); // Keep the trip-table in order @@ -713,7 +710,7 @@ bool TripBase::workToBeDone() void TripBase::redoit() { moveDivesBetweenTrips(divesToMove); - sort_trip_table(divelog.trips.get()); // Though unlikely, moving dives may reorder trips + divelog.trips->sort(); // Though unlikely, moving dives may reorder trips // Select the moved dives std::vector dives; @@ -773,25 +770,22 @@ CreateTrip::CreateTrip(const QVector &divesToAddIn) if (divesToAddIn.isEmpty()) return; - dive_trip *trip = create_trip_from_dive(divesToAddIn[0]); - divesToMove.tripsToAdd.emplace_back(trip); + auto trip = create_trip_from_dive(divesToAddIn[0]); for (dive *d: divesToAddIn) - divesToMove.divesToMove.push_back( {d, trip} ); + divesToMove.divesToMove.push_back( { d, trip.get() }); + divesToMove.tripsToAdd.push_back(std::move(trip)); } AutogroupDives::AutogroupDives() { setText(Command::Base::tr("autogroup dives")); - dive_trip *trip; - bool alloc; - int from, to; - for(int i = 0; (trip = get_dives_to_autogroup(divelog.dives.get(), i, &from, &to, &alloc)) != NULL; i = to) { + for (auto &entry: get_dives_to_autogroup(divelog.dives.get())) { // If this is an allocated trip, take ownership - if (alloc) - divesToMove.tripsToAdd.emplace_back(trip); - for (int j = from; j < to; ++j) - divesToMove.divesToMove.push_back( { get_dive(j), trip } ); + 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 } ); } } @@ -799,12 +793,12 @@ MergeTrips::MergeTrips(dive_trip *trip1, dive_trip *trip2) { if (trip1 == trip2) return; - dive_trip *newTrip = combine_trips(trip1, trip2); - divesToMove.tripsToAdd.emplace_back(newTrip); + std::unique_ptr newTrip = combine_trips(trip1, trip2); for (int i = 0; i < trip1->dives.nr; ++i) - divesToMove.divesToMove.push_back( { trip1->dives.dives[i], newTrip } ); + divesToMove.divesToMove.push_back( { trip1->dives.dives[i], newTrip.get() } ); for (int i = 0; i < trip2->dives.nr; ++i) - divesToMove.divesToMove.push_back( { trip2->dives.dives[i], newTrip } ); + divesToMove.divesToMove.push_back( { trip2->dives.dives[i], newTrip.get() } ); + divesToMove.tripsToAdd.push_back(std::move(newTrip)); } // std::array is the same as struct *dive[2], with the fundamental diff --git a/commands/command_edit.cpp b/commands/command_edit.cpp index 664745829..f7eec4aec 100644 --- a/commands/command_edit.cpp +++ b/commands/command_edit.cpp @@ -1444,7 +1444,7 @@ void EditDive::exchangeDives() timestamp_t delta = oldDive->when - newDive->when; if (delta != 0) { sort_dive_table(divelog.dives.get()); - sort_trip_table(divelog.trips.get()); + divelog.trips->sort(); if (newDive->divetrip != oldDive->divetrip) qWarning("Command::EditDive::redo(): This command does not support moving between trips!"); if (oldDive->divetrip) diff --git a/core/divelist.cpp b/core/divelist.cpp index c43a07317..290509b97 100644 --- a/core/divelist.cpp +++ b/core/divelist.cpp @@ -638,6 +638,8 @@ static int comp_dc(const struct dive *d1, const struct dive *d2) int comp_dives(const struct dive *a, const struct dive *b) { int cmp; + if (a == b) + return 0; /* reflexivity */ if (a->when < b->when) return -1; if (a->when > b->when) @@ -647,9 +649,9 @@ int comp_dives(const struct dive *a, const struct dive *b) return -1; 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) @@ -662,7 +664,7 @@ int comp_dives(const struct dive *a, const struct dive *b) return -1; if (a->id > b->id) return 1; - return 0; /* this should not happen for a != b */ + return a < b ? -1 : 1; /* give up. */ } /* Dive table functions */ @@ -690,24 +692,19 @@ void insert_dive(struct dive_table *table, struct dive *d) * 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_arg) +static void autogroup_dives(struct dive_table *table, struct trip_table &trip_table) { - int from, to; - dive_trip *trip; - int i, j; - bool alloc; - if (!divelog.autogroup) return; - for (i = 0; (trip = get_dives_to_autogroup(table, i, &from, &to, &alloc)) != NULL; i = to) { - for (j = from; j < to; ++j) - add_dive_to_trip(table->dives[j], trip); + 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); /* If this was newly allocated, add trip to list */ - if (alloc) - insert_trip(trip, trip_table_arg); + if (entry.created_trip) + trip_table.put(std::move(entry.created_trip)); } - sort_trip_table(trip_table_arg); + trip_table.sort(); // Necessary? #ifdef DEBUG_TRIP dump_trip_list(); #endif @@ -751,10 +748,10 @@ struct dive *unregister_dive(int idx) void process_loaded_dives() { sort_dive_table(divelog.dives.get()); - sort_trip_table(divelog.trips.get()); + divelog.trips->sort(); /* Autogroup dives if desired by user. */ - autogroup_dives(divelog.dives.get(), divelog.trips.get()); + autogroup_dives(divelog.dives.get(), *divelog.trips); fulltext_populate(); @@ -932,13 +929,13 @@ 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 = empty_trip_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, + process_imported_dives(import_log, flags, &dives_to_add, &dives_to_remove, trips_to_add, dive_sites_to_add, devices_to_add); /* Start by deselecting all dives, so that we don't end up with an invalid selection */ @@ -969,9 +966,9 @@ void add_imported_dives(struct divelog *import_log, int flags) dives_to_add.nr = 0; /* Add new trips */ - for (i = 0; i < trips_to_add.nr; i++) - insert_trip(trips_to_add.trips[i], divelog.trips.get()); - trips_to_add.nr = 0; + for (auto &trip: trips_to_add) + divelog.trips->put(std::move(trip)); + trips_to_add.clear(); /* Add new dive sites */ for (auto &ds: dive_sites_to_add) @@ -987,7 +984,6 @@ void add_imported_dives(struct divelog *import_log, int flags) free(dives_to_add.dives); free(dives_to_remove.dives); - free(trips_to_add.trips); /* Inform frontend of reset data. This should reset all the models. */ emit_reset_signal(); @@ -1003,22 +999,17 @@ 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) { - int i; - struct dive_trip *trip_old; - - for (i = 0; i < divelog.trips->nr; i++) { - trip_old = divelog.trips->trips[i]; - if (trips_overlap(trip_import, trip_old)) { - *sequence_changed |= merge_dive_tables(&trip_import->dives, import_table, &trip_old->dives, - prefer_imported, trip_old, + 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, + prefer_imported, trip_old.get(), dives_to_add, dives_to_remove, start_renumbering_at); - free_trip(trip_import); /* All dives in trip have been consumed -> free */ return true; } } @@ -1062,11 +1053,10 @@ static bool try_to_merge_trip(dive_trip *trip_import, struct dive_table *import_ 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, + struct trip_table &trips_to_add, dive_site_table &sites_to_add, device_table &devices_to_add) { int i, j, nr, start_renumbering_at = 0; - dive_trip *new_trip; bool sequence_changed = false; bool new_dive_has_number = false; bool last_old_dive_is_numbered; @@ -1074,7 +1064,7 @@ void process_imported_dives(struct divelog *import_log, int flags, /* Make sure that output parameters don't contain garbage */ clear_dive_table(dives_to_add); clear_dive_table(dives_to_remove); - clear_trip_table(trips_to_add); + trips_to_add.clear(); sites_to_add.clear(); devices_to_add.clear(); @@ -1105,7 +1095,7 @@ void process_imported_dives(struct divelog *import_log, int flags, /* 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.get()); + autogroup_dives(import_log->dives.get(), *import_log->trips); /* If dive sites already exist, use the existing versions. */ for (auto &new_ds: *import_log->sites) { @@ -1140,10 +1130,9 @@ void process_imported_dives(struct divelog *import_log, int flags, * 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 (i = 0; i < import_log->trips->nr; i++) { - dive_trip *trip_import = import_log->trips->trips[i]; + 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, + 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)) continue; } @@ -1160,16 +1149,18 @@ void process_imported_dives(struct divelog *import_log, int flags, remove_dive(d, import_log->dives.get()); } - /* Then, add trip to list of trips to add */ - insert_trip(trip_import, trips_to_add); trip_import->dives.nr = 0; /* 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)); } - import_log->trips->nr = 0; /* All trips were consumed */ + import_log->trips->clear(); /* All trips were consumed */ if ((flags & IMPORT_ADD_TO_NEW_TRIP) && import_log->dives->nr > 0) { /* Create a new trip for unassigned dives, if desired. */ - new_trip = create_trip_from_dive(import_log->dives->dives[0]); - insert_trip(new_trip, trips_to_add); + auto [new_trip, idx] = trips_to_add.put( + create_trip_from_dive(import_log->dives->dives[0]) + ); /* Add all remaining dives to this trip */ for (i = 0; i < import_log->dives->nr; i++) { @@ -1296,7 +1287,7 @@ static int comp_dive_or_trip(struct dive_or_trip a, struct dive_or_trip b) if (a.dive && b.dive) return comp_dives(a.dive, b.dive); if (a.trip && b.trip) - return comp_trips(a.trip, b.trip); + return comp_trips(*a.trip, *b.trip); if (a.dive) return comp_dive_to_trip(a.dive, b.trip); else diff --git a/core/divelist.h b/core/divelist.h index e20583f7f..d84b85ba2 100644 --- a/core/divelist.h +++ b/core/divelist.h @@ -35,7 +35,7 @@ extern void process_loaded_dives(); 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, + struct trip_table &trips_to_add, dive_site_table &sites_to_add, std::vector &devices_to_add); extern int dive_table_get_insertion_index(struct dive_table *table, struct dive *dive); diff --git a/core/divelog.cpp b/core/divelog.cpp index 47f7dd8c1..837746db3 100644 --- a/core/divelog.cpp +++ b/core/divelog.cpp @@ -17,15 +17,12 @@ divelog::divelog() : autogroup(false) { *dives = empty_dive_table; - *trips = empty_trip_table; } divelog::~divelog() { if (dives) clear_dive_table(dives.get()); - if (trips) - clear_trip_table(trips.get()); } divelog::divelog(divelog &&) = default; @@ -40,7 +37,14 @@ void divelog::delete_single_dive(int idx) return; } struct dive *dive = dives->dives[idx]; - remove_dive_from_trip(dive, trips.get()); + struct dive_trip *trip = unregister_dive_from_trip(dive); + + // Deleting a dive may change the order of trips! + if (trip) + trips->sort(); + + if (trip && trip->dives.nr == 0) + trips->pull(trip); unregister_dive_from_dive_site(dive); delete_dive_from_table(dives.get(), idx); } @@ -48,12 +52,9 @@ void divelog::delete_single_dive(int idx) void divelog::clear() { while (dives->nr > 0) - delete_single_dive(dives->nr - 1); + delete_dive_from_table(dives.get(), dives->nr - 1); sites->clear(); - if (trips->nr != 0) { - report_info("Warning: trip table not empty in divelog::clear()!"); - trips->nr = 0; - } + trips->clear(); devices.clear(); filter_presets->clear(); } diff --git a/core/load-git.cpp b/core/load-git.cpp index 1881d6ba4..cebe09cb3 100644 --- a/core/load-git.cpp +++ b/core/load-git.cpp @@ -1384,7 +1384,7 @@ static void finish_active_trip(struct git_parser_state *state) auto &trip = state->active_trip; if (trip) - insert_trip(trip.release(), state->log->trips.get()); + state->log->trips->put(std::move(trip)); } static void finish_active_dive(struct git_parser_state *state) diff --git a/core/owning_ptrs.h b/core/owning_ptrs.h deleted file mode 100644 index 10d73d4fd..000000000 --- a/core/owning_ptrs.h +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -// Convenience classes defining owning pointers to C-objects that -// automatically clean up the objects if the pointers go out of -// scope. Based on unique_ptr<>. -// In the future, we should replace these by real destructors. -#ifndef OWNING_PTR_H -#define OWNING_PTR_H - -#include -#include - -#endif diff --git a/core/owning_table.h b/core/owning_table.h index d70287469..f8496207b 100644 --- a/core/owning_table.h +++ b/core/owning_table.h @@ -140,6 +140,10 @@ public: } 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 + // due course. pull_result pull(const T *item) { size_t idx = get_idx(item); if (idx == std::string::npos) { @@ -148,6 +152,9 @@ 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; }); + } }; #endif diff --git a/core/parse.cpp b/core/parse.cpp index 2baa37b8d..59bee0cdf 100644 --- a/core/parse.cpp +++ b/core/parse.cpp @@ -291,7 +291,7 @@ void trip_end(struct parser_state *state) { if (!state->cur_trip) return; - insert_trip(state->cur_trip.release(), state->log->trips.get()); + state->log->trips->put(std::move(state->cur_trip)); } void picture_start(struct parser_state *state) diff --git a/core/save-git.cpp b/core/save-git.cpp index db77baf92..8786c6f44 100644 --- a/core/save-git.cpp +++ b/core/save-git.cpp @@ -983,7 +983,6 @@ static int create_git_tree(git_repository *repo, struct dir *root, bool select_o { int i; struct dive *dive; - dive_trip *trip; git_storage_update_progress(translate("gettextFromC", "Start saving data")); save_settings(repo, root); @@ -991,8 +990,8 @@ static int create_git_tree(git_repository *repo, struct dir *root, bool select_o save_divesites(repo, root); save_filter_presets(repo, root); - for (i = 0; i < divelog.trips->nr; ++i) - divelog.trips->trips[i]->saved = 0; + for (auto &trip: *divelog.trips) + trip->saved = false; /* save the dives */ git_storage_update_progress(translate("gettextFromC", "Start saving dives")); @@ -1000,7 +999,7 @@ static int create_git_tree(git_repository *repo, struct dir *root, bool select_o struct tm tm; struct dir *tree; - trip = dive->divetrip; + dive_trip *trip = dive->divetrip; if (select_only) { if (!dive->selected) @@ -1010,7 +1009,7 @@ static int create_git_tree(git_repository *repo, struct dir *root, bool select_o } /* Create the date-based hierarchy */ - utc_mkdate(trip ? trip_date(trip) : dive->when, &tm); + utc_mkdate(trip ? trip_date(*trip) : dive->when, &tm); tree = mktree(repo, root, "%04d", tm.tm_year); tree = mktree(repo, tree, "%02d", tm.tm_mon + 1); diff --git a/core/save-html.cpp b/core/save-html.cpp index a8ddb7814..9b164fb7f 100644 --- a/core/save-html.cpp +++ b/core/save-html.cpp @@ -438,15 +438,14 @@ static void write_trips(struct membuffer *b, const char *photos_dir, bool select { int i, dive_no = 0; const struct dive *dive; - dive_trip *trip; char sep_ = ' '; char *sep = &sep_; - for (i = 0; i < divelog.trips->nr; ++i) - divelog.trips->trips[i]->saved = 0; + for (auto &trip: *divelog.trips) + trip->saved = 0; for_each_dive (i, dive) { - trip = dive->divetrip; + dive_trip *trip = dive->divetrip; /*Continue if the dive have no trips or we have seen this trip before*/ if (!trip || trip->saved) diff --git a/core/save-xml.cpp b/core/save-xml.cpp index e0cf01dac..b7b55f729 100644 --- a/core/save-xml.cpp +++ b/core/save-xml.cpp @@ -543,16 +543,16 @@ int save_dive(FILE *f, struct dive *dive, bool anonymize) return 0; } -static void save_trip(struct membuffer *b, dive_trip *trip, bool anonymize) +static void save_trip(struct membuffer *b, dive_trip &trip, bool anonymize) { int i; struct dive *dive; put_format(b, "location.c_str(), " location=\'", "\'", 1); + show_utf8(b, trip.location.c_str(), " location=\'", "\'", 1); put_format(b, ">\n"); - show_utf8(b, trip->notes.c_str(), "", "\n", 0); + show_utf8(b, trip.notes.c_str(), "", "\n", 0); /* * Incredibly cheesy: we want to save the dives sorted, and they @@ -561,7 +561,7 @@ static void save_trip(struct membuffer *b, dive_trip *trip, bool anonymize) * check the divetrip pointer.. */ for_each_dive(i, dive) { - if (dive->divetrip == trip) + if (dive->divetrip == &trip) save_one_dive_to_mb(b, dive, anonymize); } @@ -642,7 +642,6 @@ static void save_dives_buffer(struct membuffer *b, bool select_only, bool anonym { int i; struct dive *dive; - dive_trip *trip; put_format(b, "\n\n", DATAFORMAT_VERSION); @@ -686,8 +685,8 @@ static void save_dives_buffer(struct membuffer *b, bool select_only, bool anonym put_format(b, "\n"); } put_format(b, "\n\n"); - for (i = 0; i < divelog.trips->nr; ++i) - divelog.trips->trips[i]->saved = 0; + for (auto &trip: *divelog.trips) + trip->saved = 0; /* save the filter presets */ save_filter_presets(b); @@ -701,7 +700,7 @@ static void save_dives_buffer(struct membuffer *b, bool select_only, bool anonym save_one_dive_to_mb(b, dive, anonymize); } else { - trip = dive->divetrip; + dive_trip *trip = dive->divetrip; /* Bare dive without a trip? */ if (!trip) { @@ -715,7 +714,7 @@ static void save_dives_buffer(struct membuffer *b, bool select_only, bool anonym /* We haven't seen this trip before - save it and all dives */ trip->saved = 1; - save_trip(b, trip, anonymize); + save_trip(b, *trip, anonymize); } } put_format(b, "\n\n"); diff --git a/core/selection.cpp b/core/selection.cpp index 91d2e58b0..69b396488 100644 --- a/core/selection.cpp +++ b/core/selection.cpp @@ -173,8 +173,8 @@ QVector setSelectionCore(const std::vector &selection, dive *cur static void clear_trip_selection() { amount_trips_selected = 0; - for (int i = 0; i < divelog.trips->nr; ++i) - divelog.trips->trips[i]->selected = false; + for (auto &trip: *divelog.trips) + trip->selected = false; } // Reset the selection to the dives of the "selection" vector and send the appropriate signals. @@ -221,10 +221,8 @@ void setTripSelection(dive_trip *trip, dive *currentDive) dive &d = *divelog.dives->dives[i]; d.selected = d.divetrip == trip; } - for (int i = 0; i < divelog.trips->nr; ++i) { - dive_trip *t = divelog.trips->trips[i]; - t->selected = t == trip; - } + for (auto &t: *divelog.trips) + t->selected = t.get() == trip; amount_selected = trip->dives.nr; amount_trips_selected = 1; @@ -315,9 +313,9 @@ struct dive_trip *single_selected_trip() { if (amount_trips_selected != 1) return NULL; - for (int i = 0; i < divelog.trips->nr; ++i) { - if (divelog.trips->trips[i]->selected) - return divelog.trips->trips[i]; + for (auto &trip: *divelog.trips) { + if (trip->selected) + return trip.get(); } report_info("warning: found no selected trip even though one should be selected"); return NULL; // shouldn't happen diff --git a/core/string-format.cpp b/core/string-format.cpp index 767d2a3e3..1f6cf48e0 100644 --- a/core/string-format.cpp +++ b/core/string-format.cpp @@ -299,26 +299,23 @@ QString formatMinutes(int seconds) return QString::asprintf("%d:%.2d", FRACTION_TUPLE(seconds, 60)); } -QString formatTripTitle(const dive_trip *trip) +QString formatTripTitle(const dive_trip &trip) { - if (!trip) - return QString(); - timestamp_t when = trip_date(trip); bool getday = trip_is_single_day(trip); QDateTime localTime = timestampToDateTime(when); - QString prefix = !trip->location.empty() ? QString::fromStdString(trip->location) + ", " : QString(); + QString prefix = !trip.location.empty() ? QString::fromStdString(trip.location) + ", " : QString(); if (getday) return prefix + loc.toString(localTime, prefs.date_format); else return prefix + loc.toString(localTime, "MMM yyyy"); } -QString formatTripTitleWithDives(const dive_trip *trip) +QString formatTripTitleWithDives(const dive_trip &trip) { - int nr = trip->dives.nr; + int nr = trip.dives.nr; return formatTripTitle(trip) + " " + gettextFromC::tr("(%n dive(s))", "", nr); } diff --git a/core/string-format.h b/core/string-format.h index c83ff8e70..1956db1cc 100644 --- a/core/string-format.h +++ b/core/string-format.h @@ -30,7 +30,7 @@ QString formatDiveDateTime(const dive *d); QString formatDiveGasString(const dive *d); QString formatDayOfWeek(int day); QString formatMinutes(int seconds); -QString formatTripTitle(const dive_trip *trip); -QString formatTripTitleWithDives(const dive_trip *trip); +QString formatTripTitle(const dive_trip &trip); +QString formatTripTitleWithDives(const dive_trip &trip); #endif diff --git a/core/trip.cpp b/core/trip.cpp index 39c445070..a10c59b7b 100644 --- a/core/trip.cpp +++ b/core/trip.cpp @@ -12,22 +12,19 @@ #ifdef DEBUG_TRIP void dump_trip_list() { - dive_trip *trip; - int i = 0; timestamp_t last_time = 0; - for (i = 0; i < divelog.trips->nr; ++i) { + for (auto &trip: divelog.trips) { struct tm tm; - trip = divelog.trips->trips[i]; - utc_mkdate(trip_date(trip), &tm); - if (trip_date(trip) < last_time) + utc_mkdate(trip_date(*trip), &tm); + if (trip_date(*trip) < last_time) printf("\n\ntrip_table OUT OF ORDER!!!\n\n\n"); printf("%s trip %d to \"%s\" on %04u-%02u-%02u %02u:%02u:%02u (%d dives - %p)\n", trip->autogen ? "autogen " : "", i + 1, trip->location.c_str(), tm.tm_year, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, - trip->dives.nr, trip); - last_time = trip_date(trip); + trip->dives.nr, trip.get()); + last_time = trip_date(*trip); } printf("-----\n"); } @@ -42,35 +39,18 @@ dive_trip::~dive_trip() free(dives.dives); } -/* free resources associated with a trip structure */ -void free_trip(dive_trip *trip) +timestamp_t trip_date(const struct dive_trip &trip) { - delete trip; + if (trip.dives.nr == 0) + return 0; + return trip.dives.dives[0]->when; } -/* Trip table functions */ -static MAKE_GET_IDX(trip_table, struct dive_trip *, trips) -static MAKE_GROW_TABLE(trip_table, struct dive_trip *, trips) -static MAKE_GET_INSERTION_INDEX(trip_table, struct dive_trip *, trips, trip_less_than) -static MAKE_ADD_TO(trip_table, struct dive_trip *, trips) -static MAKE_REMOVE_FROM(trip_table, trips) -MAKE_SORT(trip_table, struct dive_trip *, trips, comp_trips) -MAKE_REMOVE(trip_table, struct dive_trip *, trip) -MAKE_CLEAR_TABLE(trip_table, trips, trip) -MAKE_MOVE_TABLE(trip_table, trips) - -timestamp_t trip_date(const struct dive_trip *trip) +static timestamp_t trip_enddate(const struct dive_trip &trip) { - if (!trip || trip->dives.nr == 0) + if (trip.dives.nr == 0) return 0; - return trip->dives.dives[0]->when; -} - -timestamp_t trip_enddate(const struct dive_trip *trip) -{ - if (!trip || trip->dives.nr == 0) - return 0; - return dive_endtime(trip->dives.dives[trip->dives.nr - 1]); + return dive_endtime(trip.dives.dives[trip.dives.nr - 1]); } /* check if we have a trip right before / after this dive */ @@ -117,39 +97,9 @@ struct dive_trip *unregister_dive_from_trip(struct dive *dive) return trip; } -static void delete_trip(dive_trip *trip, struct trip_table *trip_table_arg) +std::unique_ptr create_trip_from_dive(const struct dive *dive) { - remove_trip(trip, trip_table_arg); - free_trip(trip); -} - -void remove_dive_from_trip(struct dive *dive, struct trip_table *trip_table_arg) -{ - struct dive_trip *trip = unregister_dive_from_trip(dive); - if (trip && trip->dives.nr == 0) - delete_trip(trip, trip_table_arg); -} - -dive_trip *alloc_trip() -{ - return new dive_trip; -} - -/* insert the trip into the trip table */ -void insert_trip(struct dive_trip *dive_trip, struct trip_table *trip_table_arg) -{ - int idx = trip_table_get_insertion_index(trip_table_arg, dive_trip); - add_to_trip_table(trip_table_arg, idx, dive_trip); -#ifdef DEBUG_TRIP - dump_trip_list(); -#endif -} - -dive_trip *create_trip_from_dive(struct dive *dive) -{ - dive_trip *trip; - - trip = alloc_trip(); + auto trip = std::make_unique(); trip->location = get_dive_location(dive); return trip; @@ -162,13 +112,12 @@ dive_trip *create_trip_from_dive(struct dive *dive) /* * Find a trip a new dive should be autogrouped with. If no such trips - * exist, allocate a new trip. The bool "*allocated" is set to true - * if a new trip was allocated. + * exist, allocate a new trip. A unique_ptr is returned if a new trip + * was allocated. The caller has to store it. */ -dive_trip *get_trip_for_new_dive(struct dive *new_dive, bool *allocated) +std::pair> get_trip_for_new_dive(const struct dive *new_dive) { - struct dive *d; - dive_trip *trip; + dive *d; int i; /* Find dive that is within TRIP_THRESHOLD of current dive */ @@ -177,35 +126,30 @@ dive_trip *get_trip_for_new_dive(struct dive *new_dive, bool *allocated) if (d->when >= new_dive->when + TRIP_THRESHOLD) break; - if (d->when + TRIP_THRESHOLD >= new_dive->when && d->divetrip) { - /* Found a dive with trip in the range */ - *allocated = false; - return d->divetrip; - } + if (d->when + TRIP_THRESHOLD >= new_dive->when && d->divetrip) + return { d->divetrip, nullptr }; /* Found a dive with trip in the range */ } /* Didn't find a trip -> allocate a new one */ - trip = create_trip_from_dive(new_dive); + auto trip = create_trip_from_dive(new_dive); trip->autogen = true; - *allocated = true; - return trip; + auto t = trip.get(); + return { t, std::move(trip) }; } /* lookup of trip in main trip_table based on its id */ dive_trip *get_trip_by_uniq_id(int tripId) { - for (int i = 0; i < divelog.trips->nr; i++) { - if (divelog.trips->trips[i]->id == tripId) - return divelog.trips->trips[i]; - } - return NULL; + auto it = std::find_if(divelog.trips->begin(), divelog.trips->end(), + [tripId](auto &t) { return t->id == tripId; }); + return it != divelog.trips->end() ? it->get() : nullptr; } /* Check if two trips overlap time-wise up to trip threshold. */ -bool trips_overlap(const struct dive_trip *t1, const struct dive_trip *t2) +bool trips_overlap(const struct dive_trip &t1, const struct dive_trip &t2) { /* First, handle the empty-trip cases. */ - if (t1->dives.nr == 0 || t2->dives.nr == 0) + if (t1.dives.nr == 0 || t2.dives.nr == 0) return 0; if (trip_date(t1) < trip_date(t2)) @@ -217,21 +161,22 @@ bool trips_overlap(const struct dive_trip *t1, const struct dive_trip *t2) /* * Collect dives for auto-grouping. Pass in first dive which should be checked. * Returns range of dives that should be autogrouped and trip it should be - * associated to. If the returned trip was newly allocated, the last bool + * associated to. If the returned trip was newly allocated, a std::unique_ptr<> + * to the trip is returned. * is set to true. Caller still has to register it in the system. Note * whereas this looks complicated - it is needed by the undo-system, which * manually injects the new trips. If there are no dives to be autogrouped, * return NULL. */ -dive_trip *get_dives_to_autogroup(struct dive_table *table, int start, int *from, int *to, bool *allocated) +std::vector get_dives_to_autogroup(struct dive_table *table) { - int i; + std::vector res; struct dive *lastdive = NULL; /* Find first dive that should be merged and remember any previous * dive that could be merged into. */ - for (i = start; i < table->nr; i++) { + for (int i = 0; i < table->nr; ++i) { struct dive *dive = table->dives[i]; dive_trip *trip; @@ -248,22 +193,22 @@ dive_trip *get_dives_to_autogroup(struct dive_table *table, int start, int *from } /* We found a dive, let's see if we have to allocate a new trip */ + std::unique_ptr allocated; if (!lastdive || dive->when >= lastdive->when + TRIP_THRESHOLD) { /* allocate new trip */ - trip = create_trip_from_dive(dive); - trip->autogen = true; - *allocated = true; + allocated = create_trip_from_dive(dive); + allocated->autogen = true; + trip = allocated.get(); } else { /* use trip of previous dive */ trip = lastdive->divetrip; - *allocated = false; } // Now, find all dives that will be added to this trip lastdive = dive; - *from = i; - for (*to = *from + 1; *to < table->nr; (*to)++) { - dive = table->dives[*to]; + int to; + for (to = i + 1; to < table->nr; to++) { + dive = table->dives[to]; if (dive->divetrip || dive->notrip || dive->when >= lastdive->when + TRIP_THRESHOLD) break; @@ -271,11 +216,11 @@ dive_trip *get_dives_to_autogroup(struct dive_table *table, int start, int *from trip->location = get_dive_location(dive); lastdive = dive; } - return trip; + res.push_back({ i, to, trip, std::move(allocated) }); + i = to - 1; } - /* Did not find anyhting - mark as end */ - return NULL; + return res; } /* Out of two strings, get the string that is not empty (if any). */ @@ -286,11 +231,10 @@ static std::string non_empty_string(const std::string &a, const std::string &b) /* This combines the information of two trips, generating a * new trip. To support undo, we have to preserve the old trips. */ -dive_trip *combine_trips(struct dive_trip *trip_a, struct dive_trip *trip_b) +std::unique_ptr combine_trips(struct dive_trip *trip_a, struct dive_trip *trip_b) { - dive_trip *trip; + auto trip = std::make_unique(); - trip = alloc_trip(); trip->location = non_empty_string(trip_a->location, trip_b->location); trip->notes = non_empty_string(trip_a->notes, trip_b->notes); @@ -298,20 +242,19 @@ dive_trip *combine_trips(struct dive_trip *trip_a, struct dive_trip *trip_b) } /* Trips are compared according to the first dive in the trip. */ -int comp_trips(const struct dive_trip *a, const struct dive_trip *b) +int comp_trips(const struct dive_trip &a, const struct dive_trip &b) { - /* This should never happen, nevertheless don't crash on trips - * with no (or worse a negative number of) dives. */ - if (a->dives.nr <= 0) - return b->dives.nr <= 0 ? 0 : -1; - if (b->dives.nr <= 0) + // To make sure that trips never compare equal, compare by + // address if both are empty. + if (&a == &b) + return 0; // reflexivity. shouldn't happen. + if (a.dives.nr <= 0 && b.dives.nr <= 0) + return &a < &b ? -1 : 1; + if (a.dives.nr <= 0) + return -1; + if (b.dives.nr <= 0) return 1; - return comp_dives(a->dives.dives[0], b->dives.dives[0]); -} - -bool trip_less_than(const struct dive_trip *a, const struct dive_trip *b) -{ - return comp_trips(a, b) < 0; + return comp_dives(a.dives.dives[0], b.dives.dives[0]); } static bool is_same_day(timestamp_t trip_when, timestamp_t dive_when) @@ -330,12 +273,12 @@ static bool is_same_day(timestamp_t trip_when, timestamp_t dive_when) return (tmd.tm_mday == tmt.tm_mday) && (tmd.tm_mon == tmt.tm_mon) && (tmd.tm_year == tmt.tm_year); } -bool trip_is_single_day(const struct dive_trip *trip) +bool trip_is_single_day(const struct dive_trip &trip) { - if (trip->dives.nr <= 1) + if (trip.dives.nr <= 1) return true; - return is_same_day(trip->dives.dives[0]->when, - trip->dives.dives[trip->dives.nr - 1]->when); + return is_same_day(trip.dives.dives[0]->when, + trip.dives.dives[trip.dives.nr - 1]->when); } int trip_shown_dives(const struct dive_trip *trip) diff --git a/core/trip.h b/core/trip.h index d1047ec8b..51c5a798c 100644 --- a/core/trip.h +++ b/core/trip.h @@ -3,6 +3,7 @@ #define TRIP_H #include "divelist.h" +#include "owning_table.h" #include @@ -21,42 +22,37 @@ struct dive_trip ~dive_trip(); }; -typedef struct trip_table { - int nr, allocated; - struct dive_trip **trips; -} trip_table_t; +int comp_trips(const dive_trip &t1, const dive_trip &t2); -static const trip_table_t empty_trip_table = { 0, 0, (struct dive_trip **)0 }; +struct trip_table : public sorted_owning_table { +}; extern void add_dive_to_trip(struct dive *, dive_trip *); extern struct dive_trip *unregister_dive_from_trip(struct dive *dive); -extern void remove_dive_from_trip(struct dive *dive, struct trip_table *trip_table_arg); -extern void insert_trip(dive_trip *trip, struct trip_table *trip_table_arg); -extern int remove_trip(const dive_trip *trip, struct trip_table *trip_table_arg); -extern void free_trip(dive_trip *trip); -extern timestamp_t trip_date(const struct dive_trip *trip); -extern timestamp_t trip_enddate(const struct dive_trip *trip); +extern timestamp_t trip_date(const struct dive_trip &trip); -extern bool trip_less_than(const struct dive_trip *a, const struct dive_trip *b); -extern int comp_trips(const struct dive_trip *a, const struct dive_trip *b); -extern void sort_trip_table(struct trip_table *table); +extern std::unique_ptr create_trip_from_dive(const struct dive *dive); +extern dive_trip *create_and_hookup_trip_from_dive(const struct dive *dive, struct trip_table &trip_table_arg); -extern dive_trip *alloc_trip(); -extern dive_trip *create_trip_from_dive(struct dive *dive); -extern dive_trip *get_dives_to_autogroup(struct dive_table *table, int start, int *from, int *to, bool *allocated); -extern dive_trip *get_trip_for_new_dive(struct dive *new_dive, bool *allocated); +// Result item of get_dives_to_autogroup() +struct dives_to_autogroup_result { + int 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 dive_trip *get_trip_by_uniq_id(int tripId); -extern bool trips_overlap(const struct dive_trip *t1, const struct dive_trip *t2); +extern bool trips_overlap(const struct dive_trip &t1, const struct dive_trip &t2); -extern dive_trip *combine_trips(struct dive_trip *trip_a, struct dive_trip *trip_b); +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 bool trip_is_single_day(const struct dive_trip &trip); extern int trip_shown_dives(const struct dive_trip *trip); -void move_trip_table(struct trip_table *src, struct trip_table *dst); -void clear_trip_table(struct trip_table *table); - #ifdef DEBUG_TRIP extern void dump_trip_list(); #endif @@ -65,6 +61,6 @@ extern void dump_trip_list(); * passed through QVariants and through QML. See comment in dive.h. */ #include Q_DECLARE_METATYPE(struct dive_trip *); -Q_DECLARE_METATYPE(trip_table_t *); +Q_DECLARE_METATYPE(trip_table *); #endif diff --git a/desktop-widgets/tab-widgets/TabDiveNotes.cpp b/desktop-widgets/tab-widgets/TabDiveNotes.cpp index 5b4aa61d6..b0a50e83c 100644 --- a/desktop-widgets/tab-widgets/TabDiveNotes.cpp +++ b/desktop-widgets/tab-widgets/TabDiveNotes.cpp @@ -169,7 +169,7 @@ void TabDiveNotes::updateDateTime(const struct dive *d) void TabDiveNotes::updateTripDate(const struct dive_trip *t) { - QDateTime localTime = timestampToDateTime(trip_date(t)); + QDateTime localTime = timestampToDateTime(trip_date(*t)); ui.dateEdit->setDate(localTime.date()); } diff --git a/desktop-widgets/tripselectiondialog.cpp b/desktop-widgets/tripselectiondialog.cpp index e4eef72aa..ad6928152 100644 --- a/desktop-widgets/tripselectiondialog.cpp +++ b/desktop-widgets/tripselectiondialog.cpp @@ -18,9 +18,9 @@ TripSelectionDialog::TripSelectionDialog(QWidget *parent) : QDialog(parent) // We could use a model, but it seems barely worth the hassle. QStringList list; - list.reserve(divelog.trips->nr); - for (int i = 0; i < divelog.trips->nr; ++i) - list.push_back(formatTripTitleWithDives(divelog.trips->trips[i])); + list.reserve(divelog.trips->size()); + for (auto &trip: *divelog.trips) + list.push_back(formatTripTitleWithDives(*trip)); ui.trips->addItems(list); } @@ -37,9 +37,9 @@ dive_trip *TripSelectionDialog::selectedTrip() const if (rows.size() != 1) return nullptr; int idx = rows[0].row(); - if (idx < 0 || idx >= divelog.trips->nr) + if (idx < 0 || static_cast(idx) >= divelog.trips->size()) return nullptr; - return divelog.trips->trips[idx]; + return (*divelog.trips)[idx].get(); } dive_trip *TripSelectionDialog::getTrip() diff --git a/qt-models/divetripmodel.cpp b/qt-models/divetripmodel.cpp index bae532eb3..d00410bb8 100644 --- a/qt-models/divetripmodel.cpp +++ b/qt-models/divetripmodel.cpp @@ -69,7 +69,7 @@ QString DiveTripModelBase::tripShortDate(const dive_trip *trip) { if (!trip) return QString(); - QDateTime firstTime = timestampToDateTime(trip_date(trip)); + QDateTime firstTime = timestampToDateTime(trip_date(*trip)); QString firstMonth = firstTime.toString("MMM"); return QStringLiteral("%1\n'%2").arg(firstMonth,firstTime.toString("yy")); } @@ -85,7 +85,7 @@ QString DiveTripModelBase::tripTitle(const dive_trip *trip) if (title.isEmpty()) { // so use the date range - QDateTime firstTime = timestampToDateTime(trip_date(trip)); + QDateTime firstTime = timestampToDateTime(trip_date(*trip)); QString firstMonth = firstTime.toString("MMM"); QString firstYear = firstTime.toString("yyyy"); QDateTime lastTime = timestampToDateTime(trip->dives.dives[0]->when); @@ -128,7 +128,7 @@ QVariant DiveTripModelBase::tripData(const dive_trip *trip, int column, int role int countShown = trip_shown_dives(trip); if (countShown < trip->dives.nr) shownText = tr("(%1 shown)").arg(countShown); - return formatTripTitleWithDives(trip) + " " + shownText; + return formatTripTitleWithDives(*trip) + " " + shownText; } } @@ -817,7 +817,7 @@ dive *DiveTripModelTree::Item::getDive() const timestamp_t DiveTripModelTree::Item::when() const { - return d_or_t.trip ? trip_date(d_or_t.trip) : d_or_t.dive->when; + return d_or_t.trip ? trip_date(*d_or_t.trip) : d_or_t.dive->when; } dive_or_trip DiveTripModelTree::tripOrDive(const QModelIndex &index) const diff --git a/stats/statsvariables.cpp b/stats/statsvariables.cpp index dddbd69d7..1a3891f9d 100644 --- a/stats/statsvariables.cpp +++ b/stats/statsvariables.cpp @@ -74,8 +74,8 @@ struct TripWrapper { QString name; timestamp_t date; TripWrapper(const dive_trip *t) : t(t), - name(formatTripTitle(t)), // safe to pass null - date(trip_date(t)) // safe to pass null + name(t ? formatTripTitle(*t) : QString()), + date(t ? trip_date(*t) : 0) { } bool operator<(const TripWrapper &t2) const { @@ -1868,7 +1868,7 @@ struct TripVariable : public StatsVariableTemplatedivetrip); + return d->divetrip ? formatTripTitle(*d->divetrip) : QString(); } std::vector binners() const override { return { &trip_binner };