core: return unique_ptr<> from merge-dive functions

Try to remove plain owning pointers.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2024-06-04 13:22:25 +02:00 committed by bstoeger
parent 1e09ec77d7
commit aa60e5d21d
6 changed files with 184 additions and 195 deletions

View file

@ -943,9 +943,7 @@ MergeDives::MergeDives(const QVector <dive *> &dives)
return;
}
dive_trip *preferred_trip;
dive_site *preferred_site;
std::unique_ptr<dive> d(merge_dives(dives[0], dives[1], dives[1]->when - dives[0]->when, false, &preferred_trip, &preferred_site));
auto [d, trip, site] = merge_dives(*dives[0], *dives[1], dives[1]->when - dives[0]->when, false);
// Currently, the core code selects the dive -> this is not what we want, as
// we manually manage the selection post-command.
@ -953,18 +951,15 @@ MergeDives::MergeDives(const QVector <dive *> &dives)
d->selected = false;
// Set the preferred dive trip, so that for subsequent merges the better trip can be selected
d->divetrip = preferred_trip;
d->divetrip = trip;
for (int i = 2; i < dives.count(); ++i) {
d.reset(merge_dives(d.get(), dives[i], dives[i]->when - d->when, false, &preferred_trip, &preferred_site));
auto [d2, trip, site] = merge_dives(*d, *dives[i], dives[i]->when - d->when, false);
d = std::move(d2);
// Set the preferred dive trip and site, so that for subsequent merges the better trip and site can be selected
d->divetrip = preferred_trip;
d->dive_site = preferred_site;
d->divetrip = trip;
d->dive_site = site;
}
// We got our preferred trip and site, so now the references can be deleted from the newly generated dive
d->divetrip = nullptr;
d->dive_site = nullptr;
// The merged dive gets the number of the first dive with a non-zero number
for (const dive *dive: dives) {
if (dive->number) {
@ -1016,10 +1011,15 @@ MergeDives::MergeDives(const QVector <dive *> &dives)
}
mergedDive.dives.resize(1);
mergedDive.dives[0].dive = std::move(d);
mergedDive.dives[0].trip = preferred_trip;
mergedDive.dives[0].site = preferred_site;
mergedDive.dives[0].trip = d->divetrip;
mergedDive.dives[0].site = d->dive_site;
divesToMerge.dives = std::vector<dive *>(dives.begin(), dives.end());
// We got our preferred trip and site, so now the references can be deleted from the newly generated dive
d->divetrip = nullptr;
d->dive_site = nullptr;
mergedDive.dives[0].dive = std::move(d);
}
bool MergeDives::workToBeDone()

View file

@ -1202,7 +1202,7 @@ void RemoveCylinder::undo()
for (size_t i = 0; i < dives.size(); ++i) {
std::vector<int> mapping = get_cylinder_map_for_add(dives[i]->cylinders.size(), indexes[i]);
add_cylinder(&dives[i]->cylinders, indexes[i], cyl[i]);
cylinder_renumber(dives[i], &mapping[0]);
cylinder_renumber(*dives[i], &mapping[0]);
update_cylinder_related_info(dives[i]);
emit diveListNotifier.cylinderAdded(dives[i], indexes[i]);
invalidate_dive_cache(dives[i]); // Ensure that dive is written in git_save()
@ -1214,7 +1214,7 @@ void RemoveCylinder::redo()
for (size_t i = 0; i < dives.size(); ++i) {
std::vector<int> mapping = get_cylinder_map_for_remove(dives[i]->cylinders.size(), indexes[i]);
remove_cylinder(dives[i], indexes[i]);
cylinder_renumber(dives[i], &mapping[0]);
cylinder_renumber(*dives[i], &mapping[0]);
update_cylinder_related_info(dives[i]);
emit diveListNotifier.cylinderRemoved(dives[i], indexes[i]);
invalidate_dive_cache(dives[i]); // Ensure that dive is written in git_save()

View file

@ -148,14 +148,14 @@ int dive_getUniqID()
return maxId;
}
static void dc_cylinder_renumber(struct dive *dive, struct divecomputer &dc, const int mapping[]);
static void dc_cylinder_renumber(struct dive &dive, struct divecomputer &dc, const int mapping[]);
/* copy dive computer list and renumber the cylinders */
static void copy_dc_renumber(struct dive *d, const struct dive *s, const int cylinders_map[])
static void copy_dc_renumber(struct dive &d, const struct dive &s, const int cylinders_map[])
{
for (const divecomputer &dc: s->dcs) {
d->dcs.push_back(dc);
dc_cylinder_renumber(d, d->dcs.back(), cylinders_map);
for (const divecomputer &dc: s.dcs) {
d.dcs.push_back(dc);
dc_cylinder_renumber(d, d.dcs.back(), cylinders_map);
}
}
@ -714,10 +714,10 @@ static void fixup_airtemp(struct dive *dive)
/* if the air temperature in the dive data is redundant to the one in its
* first divecomputer (i.e., it was added by running fixup on the dive)
* return 0, otherwise return the air temperature given in the dive */
static temperature_t un_fixup_airtemp(const struct dive *a)
static temperature_t un_fixup_airtemp(const struct dive &a)
{
temperature_t res = a->airtemp;
if (a->airtemp.mkelvin && a->airtemp.mkelvin == dc_airtemp(a).mkelvin)
temperature_t res = a.airtemp;
if (a.airtemp.mkelvin && a.airtemp.mkelvin == dc_airtemp(&a).mkelvin)
res.mkelvin = 0;
return res;
}
@ -1110,7 +1110,7 @@ struct dive *fixup_dive(struct dive *dive)
#define MERGE_MAX(res, a, b, n) res->n = std::max(a->n, b->n)
#define MERGE_MIN(res, a, b, n) res->n = (a->n) ? (b->n) ? std::min(a->n, b->n) : (a->n) : (b->n)
#define MERGE_TXT(res, a, b, n, sep) res->n = merge_text(a->n, b->n, sep)
#define MERGE_NONZERO(res, a, b, n) res->n = a->n ? a->n : b->n
#define MERGE_NONZERO(res, a, b, n) (res)->n = (a)->n ? (a)->n : (b)->n
/*
* This is like append_sample(), but if the distance from the last sample
@ -1120,10 +1120,10 @@ struct dive *fixup_dive(struct dive *dive)
* that the time in between the dives is at the surface, not some "last
* sample that happened to be at a depth of 1.2m".
*/
static void merge_one_sample(const struct sample &sample, struct divecomputer *dc)
static void merge_one_sample(const struct sample &sample, struct divecomputer &dc)
{
if (!dc->samples.empty()) {
const struct sample &prev = dc->samples.back();
if (!dc.samples.empty()) {
const struct sample &prev = dc.samples.back();
int last_time = prev.time.seconds;
int last_depth = prev.depth.mm;
@ -1139,30 +1139,30 @@ static void merge_one_sample(const struct sample &sample, struct divecomputer *d
surface.ndl.seconds = prev.ndl.seconds;
surface.time.seconds = last_time + 20;
append_sample(surface, dc);
append_sample(surface, &dc);
surface.time.seconds = sample.time.seconds - 20;
append_sample(surface, dc);
append_sample(surface, &dc);
}
}
append_sample(sample, dc);
append_sample(sample, &dc);
}
static void renumber_last_sample(struct divecomputer *dc, const int mapping[]);
static void renumber_last_sample(struct divecomputer &dc, const int mapping[]);
static void sample_renumber(struct sample &s, const struct sample *next, const int mapping[]);
/*
* Merge samples. Dive 'a' is "offset" seconds before Dive 'b'
*/
static void merge_samples(struct divecomputer *res,
const struct divecomputer *a, const struct divecomputer *b,
static void merge_samples(struct divecomputer &res,
const struct divecomputer &a, const struct divecomputer &b,
const int *cylinders_map_a, const int *cylinders_map_b,
int offset)
{
auto as = a->samples.begin();
auto bs = b->samples.begin();
auto a_end = a->samples.end();
auto b_end = b->samples.end();
auto as = a.samples.begin();
auto bs = b.samples.begin();
auto a_end = a.samples.end();
auto b_end = b.samples.end();
/*
* We want a positive sample offset, so that sample
@ -1179,9 +1179,6 @@ static void merge_samples(struct divecomputer *res,
}
for (;;) {
if (!res)
return;
int at = as != a_end ? as->time.seconds : -1;
int bt = bs != b_end ? bs->time.seconds + offset : -1;
@ -1266,14 +1263,14 @@ static bool operator==(const struct extra_data &e1, const struct extra_data &e2)
* every value you merge" it's O(n**2)) but it's not like we
* have very many extra_data entries per dive computer anyway.
*/
static void merge_extra_data(struct divecomputer *res,
const struct divecomputer *a, const struct divecomputer *b)
static void merge_extra_data(struct divecomputer &res,
const struct divecomputer &a, const struct divecomputer &b)
{
for (auto &ed: b->extra_data) {
if (range_contains(a->extra_data, ed))
for (auto &ed: b.extra_data) {
if (range_contains(a.extra_data, ed))
continue;
res->extra_data.push_back(ed);
res.extra_data.push_back(ed);
}
}
@ -1312,28 +1309,22 @@ static int same_gas(const struct event *a, const struct event *b)
}
static void event_renumber(struct event &ev, const int mapping[]);
static void add_initial_gaschange(struct dive *dive, struct divecomputer *dc, int offset, int idx);
static void add_initial_gaschange(struct dive &dive, struct divecomputer &dc, int offset, int idx);
static void merge_events(struct dive *d, struct divecomputer *res,
const struct divecomputer *src1, const struct divecomputer *src2,
static void merge_events(struct dive &d, struct divecomputer &res,
const struct divecomputer &src1_in, const struct divecomputer &src2_in,
const int *cylinders_map1, const int *cylinders_map2,
int offset)
{
const struct event *last_gas = NULL;
/* Always use positive offsets */
auto src1 = &src1_in;
auto src2 = &src2_in;
if (offset < 0) {
const struct divecomputer *tmp;
const int *cylinders_map_tmp;
offset = -offset;
tmp = src1;
src1 = src2;
src2 = tmp;
cylinders_map_tmp = cylinders_map1;
cylinders_map1 = cylinders_map2;
cylinders_map2 = cylinders_map_tmp;
std::swap(src1, src2);
std::swap(cylinders_map1, cylinders_map2); // The pointers, not the contents are swapped.
}
auto a = src1->events.begin();
@ -1385,9 +1376,9 @@ pick_b:
}
/* Add it to the target list */
res->events.push_back(*pick);
res->events.back().time.seconds += event_offset;
event_renumber(res->events.back(), cylinders_map);
res.events.push_back(*pick);
res.events.back().time.seconds += event_offset;
event_renumber(res.events.back(), cylinders_map);
}
/* If the initial cylinder of a divecomputer was remapped, add a gas change event to that cylinder */
@ -1411,12 +1402,12 @@ int get_cylinder_idx_by_use(const struct dive *dive, enum cylinderuse cylinder_u
}
/* Force an initial gaschange event to the (old) gas #0 */
static void add_initial_gaschange(struct dive *dive, struct divecomputer *dc, int offset, int idx)
static void add_initial_gaschange(struct dive &dive, struct divecomputer &dc, int offset, int idx)
{
/* if there is a gaschange event up to 30 sec after the initial event,
* refrain from adding the initial event */
event_loop loop("gaschange");
while(auto ev = loop.next(*dc)) {
while(auto ev = loop.next(dc)) {
if (ev->time.seconds > offset + 30)
break;
else if (ev->time.seconds > offset)
@ -1424,7 +1415,7 @@ static void add_initial_gaschange(struct dive *dive, struct divecomputer *dc, in
}
/* Old starting gas mix */
add_gas_switch_event(dive, dc, offset, idx);
add_gas_switch_event(&dive, &dc, offset, idx);
}
static void sample_renumber(struct sample &s, const struct sample *prev, const int mapping[])
@ -1449,12 +1440,12 @@ static void sample_renumber(struct sample &s, const struct sample *prev, const i
}
}
static void renumber_last_sample(struct divecomputer *dc, const int mapping[])
static void renumber_last_sample(struct divecomputer &dc, const int mapping[])
{
if (dc->samples.empty())
if (dc.samples.empty())
return;
sample *prev = dc->samples.size() > 1 ? &dc->samples[dc->samples.size() - 2] : nullptr;
sample_renumber(dc->samples.back(), prev, mapping);
sample *prev = dc.samples.size() > 1 ? &dc.samples[dc.samples.size() - 2] : nullptr;
sample_renumber(dc.samples.back(), prev, mapping);
}
static void event_renumber(struct event &ev, const int mapping[])
@ -1466,7 +1457,7 @@ static void event_renumber(struct event &ev, const int mapping[])
ev.gas.index = mapping[ev.gas.index];
}
static void dc_cylinder_renumber(struct dive *dive, struct divecomputer &dc, const int mapping[])
static void dc_cylinder_renumber(struct dive &dive, struct divecomputer &dc, const int mapping[])
{
/* Remap or delete the sensor indices */
for (auto [i, sample]: enumerated_range(dc.samples))
@ -1478,7 +1469,7 @@ static void dc_cylinder_renumber(struct dive *dive, struct divecomputer &dc, con
/* If the initial cylinder of a dive was remapped, add a gas change event to that cylinder */
if (mapping[0] > 0)
add_initial_gaschange(dive, &dc, 0, mapping[0]);
add_initial_gaschange(dive, dc, 0, mapping[0]);
}
/*
@ -1489,9 +1480,9 @@ static void dc_cylinder_renumber(struct dive *dive, struct divecomputer &dc, con
* Also note that we assume that the initial cylinder is cylinder 0,
* so if that got renamed, we need to create a fake gas change event
*/
void cylinder_renumber(struct dive *dive, int mapping[])
void cylinder_renumber(struct dive &dive, int mapping[])
{
for (auto &dc: dive->dcs)
for (auto &dc: dive.dcs)
dc_cylinder_renumber(dive, dc, mapping);
}
@ -1527,9 +1518,9 @@ static int different_manual_pressures(const cylinder_t *a, const cylinder_t *b)
* same cylinder use (ie OC/Diluent/Oxygen), and if pressures
* have been added manually they need to match.
*/
static int match_cylinder(const cylinder_t *cyl, const struct dive *dive, const bool try_match[])
static int match_cylinder(const cylinder_t *cyl, const struct dive &dive, const bool try_match[])
{
for (auto [i, target]: enumerated_range(dive->cylinders)) {
for (auto [i, target]: enumerated_range(dive.cylinders)) {
if (!try_match[i])
continue;
@ -1645,26 +1636,26 @@ static bool cylinder_in_use(const struct dive *dive, int idx)
*
* For each dive, a cylinder-renumbering table is returned.
*/
static void merge_cylinders(struct dive *res, const struct dive *a, const struct dive *b,
static void merge_cylinders(struct dive &res, const struct dive &a, const struct dive &b,
int mapping_a[], int mapping_b[])
{
size_t max_cylinders = a->cylinders.size() + b->cylinders.size();
size_t max_cylinders = a.cylinders.size() + b.cylinders.size();
auto used_in_a = std::make_unique<bool[]>(max_cylinders);
auto used_in_b = std::make_unique<bool[]>(max_cylinders);
auto try_to_match = std::make_unique<bool[]>(max_cylinders);
std::fill(try_to_match.get(), try_to_match.get() + max_cylinders, false);
/* First, clear all cylinders in destination */
res->cylinders.clear();
res.cylinders.clear();
/* Clear all cylinder mappings */
std::fill(mapping_a, mapping_a + a->cylinders.size(), -1);
std::fill(mapping_b, mapping_b + b->cylinders.size(), -1);
std::fill(mapping_a, mapping_a + a.cylinders.size(), -1);
std::fill(mapping_b, mapping_b + b.cylinders.size(), -1);
/* Calculate usage map of cylinders, clear matching map */
for (size_t i = 0; i < max_cylinders; i++) {
used_in_a[i] = cylinder_in_use(a, i);
used_in_b[i] = cylinder_in_use(b, i);
used_in_a[i] = cylinder_in_use(&a, i);
used_in_b[i] = cylinder_in_use(&b, i);
}
/*
@ -1672,37 +1663,37 @@ static void merge_cylinders(struct dive *res, const struct dive *a, const struct
* These are also potential matches for 'b' to use.
*/
for (size_t i = 0; i < max_cylinders; i++) {
size_t res_nr = res->cylinders.size();
size_t res_nr = res.cylinders.size();
if (!used_in_a[i])
continue;
mapping_a[i] = static_cast<int>(res_nr);
try_to_match[res_nr] = true;
res->cylinders.push_back(a->cylinders[i]);
res.cylinders.push_back(a.cylinders[i]);
}
/*
* For each cylinder in 'b' that is used, try to match it
* with an existing cylinder in 'res' from 'a'
*/
for (size_t i = 0; i < b->cylinders.size(); i++) {
for (size_t i = 0; i < b.cylinders.size(); i++) {
int j;
if (!used_in_b[i])
continue;
j = match_cylinder(get_cylinder(b, i), res, try_to_match.get());
j = match_cylinder(get_cylinder(&b, i), res, try_to_match.get());
/* No match? Add it to the result */
if (j < 0) {
size_t res_nr = res->cylinders.size();
size_t res_nr = res.cylinders.size();
mapping_b[i] = static_cast<int>(res_nr);
res->cylinders.push_back(b->cylinders[i]);
res.cylinders.push_back(b.cylinders[i]);
continue;
}
/* Otherwise, merge the result to the one we found */
mapping_b[i] = j;
merge_one_cylinder(get_cylinder(res,j), get_cylinder(b, i));
merge_one_cylinder(get_cylinder(&res, j), get_cylinder(&b, i));
/* Don't match the same target more than once */
try_to_match[j] = false;
@ -1715,24 +1706,24 @@ static bool has_weightsystem(const weightsystem_table &t, const weightsystem_t &
return any_of(t.begin(), t.end(), [&w] (auto &w2) { return same_weightsystem(w, w2); });
}
static void merge_equipment(struct dive *res, const struct dive *a, const struct dive *b)
static void merge_equipment(struct dive &res, const struct dive &a, const struct dive &b)
{
for (auto &ws: a->weightsystems) {
if (!has_weightsystem(res->weightsystems, ws))
res->weightsystems.push_back(ws);
for (auto &ws: a.weightsystems) {
if (!has_weightsystem(res.weightsystems, ws))
res.weightsystems.push_back(ws);
}
for (auto &ws: b->weightsystems) {
if (!has_weightsystem(res->weightsystems, ws))
res->weightsystems.push_back(ws);
for (auto &ws: b.weightsystems) {
if (!has_weightsystem(res.weightsystems, ws))
res.weightsystems.push_back(ws);
}
}
static void merge_temperatures(struct dive *res, const struct dive *a, const struct dive *b)
static void merge_temperatures(struct dive &res, const struct dive &a, const struct dive &b)
{
temperature_t airtemp_a = un_fixup_airtemp(a);
temperature_t airtemp_b = un_fixup_airtemp(b);
res->airtemp = airtemp_a.mkelvin ? airtemp_a : airtemp_b;
MERGE_NONZERO(res, a, b, watertemp.mkelvin);
res.airtemp = airtemp_a.mkelvin ? airtemp_a : airtemp_b;
MERGE_NONZERO(&res, &a, &b, watertemp.mkelvin);
}
/*
@ -2014,39 +2005,35 @@ static int match_dc_dive(const struct dive &a, const struct dive &b)
* dives together manually. But this tries to handle the sane
* cases.
*/
static int likely_same_dive(const struct dive *a, const struct dive *b)
static bool likely_same_dive(const struct dive &a, const struct dive &b)
{
int match, fuzz = 20 * 60;
/* don't merge manually added dives with anything */
if (is_dc_manually_added_dive(&a->dcs[0]) ||
is_dc_manually_added_dive(&b->dcs[0]))
if (is_dc_manually_added_dive(&a.dcs[0]) ||
is_dc_manually_added_dive(&b.dcs[0]))
return 0;
/*
* Do some basic sanity testing of the values we
* have filled in during 'fixup_dive()'
*/
if (!similar(a->maxdepth.mm, b->maxdepth.mm, 1000) ||
(a->meandepth.mm && b->meandepth.mm && !similar(a->meandepth.mm, b->meandepth.mm, 1000)) ||
!a->duration.seconds || !b->duration.seconds ||
!similar(a->duration.seconds, b->duration.seconds, 5 * 60))
if (!similar(a.maxdepth.mm, b.maxdepth.mm, 1000) ||
(a.meandepth.mm && b.meandepth.mm && !similar(a.meandepth.mm, b.meandepth.mm, 1000)) ||
!a.duration.seconds || !b.duration.seconds ||
!similar(a.duration.seconds, b.duration.seconds, 5 * 60))
return 0;
/* See if we can get an exact match on the dive computer */
match = match_dc_dive(*a, *b);
if (match)
return match > 0;
if (match_dc_dive(a, b))
return true;
/*
* Allow a time difference due to dive computer time
* setting etc. Check if they overlap.
*/
fuzz = std::max(a->duration.seconds, b->duration.seconds) / 2;
if (fuzz < 60)
fuzz = 60;
int fuzz = std::max(a.duration.seconds, b.duration.seconds) / 2;
fuzz = std::max(fuzz, 60);
return (a->when <= b->when + fuzz) && (a->when >= b->when - fuzz);
return (a.when <= b.when + fuzz) && (a.when >= b.when - fuzz);
}
/*
@ -2062,17 +2049,14 @@ static int likely_same_dive(const struct dive *a, const struct dive *b)
* Attn: The dive_site parameter of the dive will be set, but the caller
* still has to register the dive in the dive site!
*/
struct dive *try_to_merge(struct dive *a, struct dive *b, bool prefer_downloaded)
struct std::unique_ptr<dive> try_to_merge(const struct dive &a, const struct dive &b, bool prefer_downloaded)
{
struct dive *res;
struct dive_site *site;
if (!likely_same_dive(a, b))
return NULL;
return {};
res = merge_dives(a, b, 0, prefer_downloaded, NULL, &site);
auto [res, trip, site] = merge_dives(a, b, 0, prefer_downloaded);
res->dive_site = site; /* Caller has to call site->add_dive()! */
return res;
return std::move(res);
}
static bool operator==(const sample &a, const sample &b)
@ -2119,27 +2103,27 @@ static int might_be_same_device(const struct divecomputer &a, const struct divec
return a.deviceid == b.deviceid;
}
static void remove_redundant_dc(struct dive *d, bool prefer_downloaded)
static void remove_redundant_dc(struct dive &d, bool prefer_downloaded)
{
// Note: since the vector doesn't grow and we only erase
// elements after the iterator, this is fine.
for (auto it = d->dcs.begin(); it != d->dcs.end(); ++it) {
for (auto it = d.dcs.begin(); it != d.dcs.end(); ++it) {
// Remove all following DCs that compare as equal.
// Use the (infamous) erase-remove idiom.
auto it2 = std::remove_if(std::next(it), d->dcs.end(),
auto it2 = std::remove_if(std::next(it), d.dcs.end(),
[d, prefer_downloaded, &it] (const divecomputer &dc) {
return same_dc(*it, dc) ||
(prefer_downloaded && might_be_same_device(*it, dc));
});
d->dcs.erase(it2, d->dcs.end());
d.dcs.erase(it2, d.dcs.end());
prefer_downloaded = false;
}
}
static const struct divecomputer *find_matching_computer(const struct divecomputer &match, const struct dive *d)
static const struct divecomputer *find_matching_computer(const struct divecomputer &match, const struct dive &d)
{
for (const auto &dc: d->dcs) {
for (const auto &dc: d.dcs) {
if (might_be_same_device(match, dc))
return &dc;
}
@ -2161,26 +2145,26 @@ static void copy_dive_computer(struct divecomputer &res, const struct divecomput
* to match them up. If we find a matching dive computer, we
* merge them. If not, we just take the data from 'a'.
*/
static void interleave_dive_computers(struct dive *res,
const struct dive *a, const struct dive *b,
static void interleave_dive_computers(struct dive &res,
const struct dive &a, const struct dive &b,
const int cylinders_map_a[], const int cylinders_map_b[],
int offset)
{
res->dcs.clear();
for (const auto &dc1: a->dcs) {
res->dcs.emplace_back();
divecomputer &newdc = res->dcs.back();
res.dcs.clear();
for (const auto &dc1: a.dcs) {
res.dcs.emplace_back();
divecomputer &newdc = res.dcs.back();
copy_dive_computer(newdc, dc1);
const divecomputer *match = find_matching_computer(dc1, b);
if (match) {
merge_events(res, &newdc, &dc1, match, cylinders_map_a, cylinders_map_b, offset);
merge_samples(&newdc, &dc1, match, cylinders_map_a, cylinders_map_b, offset);
merge_extra_data(&newdc, &dc1, match);
merge_events(res, newdc, dc1, *match, cylinders_map_a, cylinders_map_b, offset);
merge_samples(newdc, dc1, *match, cylinders_map_a, cylinders_map_b, offset);
merge_extra_data(newdc, dc1, *match);
/* Use the diveid of the later dive! */
if (offset > 0)
newdc.diveid = match->diveid;
} else {
dc_cylinder_renumber(res, res->dcs.back(), cylinders_map_a);
dc_cylinder_renumber(res, res.dcs.back(), cylinders_map_a);
}
}
}
@ -2198,17 +2182,17 @@ static void interleave_dive_computers(struct dive *res,
* try to throw out old information that *might* be from
* that one.
*/
static void join_dive_computers(struct dive *d,
const struct dive *a, const struct dive *b,
static void join_dive_computers(struct dive &d,
const struct dive &a, const struct dive &b,
const int cylinders_map_a[], const int cylinders_map_b[],
bool prefer_downloaded)
{
d->dcs.clear();
if (!a->dcs[0].model.empty() && b->dcs[0].model.empty()) {
d.dcs.clear();
if (!a.dcs[0].model.empty() && b.dcs[0].model.empty()) {
copy_dc_renumber(d, a, cylinders_map_a);
return;
}
if (!b->dcs[0].model.empty() && a->dcs[0].model.empty()) {
if (!b.dcs[0].model.empty() && a.dcs[0].model.empty()) {
copy_dc_renumber(d, b, cylinders_map_b);
return;
}
@ -2266,9 +2250,9 @@ bool is_logged(const struct dive *dive)
* The dive site the new dive should be added to (if any) is returned
* in the "dive_site" output parameter.
*/
struct dive *merge_dives(const struct dive *a, const struct dive *b, int offset, bool prefer_downloaded, struct dive_trip **trip, struct dive_site **site)
merge_result merge_dives(const struct dive &a_in, const struct dive &b_in, int offset, bool prefer_downloaded)
{
struct dive *res = new dive;
merge_result res = { std::make_unique<dive>(), nullptr, nullptr };
if (offset) {
/*
@ -2277,60 +2261,59 @@ struct dive *merge_dives(const struct dive *a, const struct dive *b, int offset,
* to try to turn it into a single longer dive. So we'd
* join them as two separate dive computers at zero offset.
*/
if (likely_same_dive(a, b))
if (likely_same_dive(a_in, b_in))
offset = 0;
}
if (is_dc_planner(&a->dcs[0])) {
const struct dive *tmp = a;
a = b;
b = tmp;
}
res->when = prefer_downloaded ? b->when : a->when;
res->selected = a->selected || b->selected;
if (trip)
*trip = get_preferred_trip(a, b);
MERGE_TXT(res, a, b, notes, "\n--\n");
MERGE_TXT(res, a, b, buddy, ", ");
MERGE_TXT(res, a, b, diveguide, ", ");
MERGE_MAX(res, a, b, rating);
MERGE_TXT(res, a, b, suit, ", ");
MERGE_MAX(res, a, b, number);
MERGE_NONZERO(res, a, b, visibility);
MERGE_NONZERO(res, a, b, wavesize);
MERGE_NONZERO(res, a, b, current);
MERGE_NONZERO(res, a, b, surge);
MERGE_NONZERO(res, a, b, chill);
res->pictures = !a->pictures.empty() ? a->pictures : b->pictures;
res->tags = taglist_merge(a->tags, b->tags);
const dive *a = &a_in;
const dive *b = &a_in;
if (is_dc_planner(&a->dcs[0]))
std::swap(a, b);
res.dive->when = prefer_downloaded ? b->when : a->when;
res.dive->selected = a->selected || b->selected;
res.trip = get_preferred_trip(a, b);
MERGE_TXT(res.dive, a, b, notes, "\n--\n");
MERGE_TXT(res.dive, a, b, buddy, ", ");
MERGE_TXT(res.dive, a, b, diveguide, ", ");
MERGE_MAX(res.dive, a, b, rating);
MERGE_TXT(res.dive, a, b, suit, ", ");
MERGE_MAX(res.dive, a, b, number);
MERGE_NONZERO(res.dive, a, b, visibility);
MERGE_NONZERO(res.dive, a, b, wavesize);
MERGE_NONZERO(res.dive, a, b, current);
MERGE_NONZERO(res.dive, a, b, surge);
MERGE_NONZERO(res.dive, a, b, chill);
res.dive->pictures = !a->pictures.empty() ? a->pictures : b->pictures;
res.dive->tags = taglist_merge(a->tags, b->tags);
/* if we get dives without any gas / cylinder information in an import, make sure
* that there is at leatst one entry in the cylinder map for that dive */
auto cylinders_map_a = std::make_unique<int[]>(std::max(size_t(1), a->cylinders.size()));
auto cylinders_map_b = std::make_unique<int[]>(std::max(size_t(1), b->cylinders.size()));
merge_cylinders(res, a, b, cylinders_map_a.get(), cylinders_map_b.get());
merge_equipment(res, a, b);
merge_temperatures(res, a, b);
merge_cylinders(*res.dive, *a, *b, cylinders_map_a.get(), cylinders_map_b.get());
merge_equipment(*res.dive, *a, *b);
merge_temperatures(*res.dive, *a, *b);
if (prefer_downloaded) {
/* If we prefer downloaded, do those first, and get rid of "might be same" computers */
join_dive_computers(res, b, a, cylinders_map_b.get(), cylinders_map_a.get(), true);
join_dive_computers(*res.dive, *b, *a, cylinders_map_b.get(), cylinders_map_a.get(), true);
} else if (offset && might_be_same_device(a->dcs[0], b->dcs[0])) {
interleave_dive_computers(res, a, b, cylinders_map_a.get(), cylinders_map_b.get(), offset);
interleave_dive_computers(*res.dive, *a, *b, cylinders_map_a.get(), cylinders_map_b.get(), offset);
} else {
join_dive_computers(res, a, b, cylinders_map_a.get(), cylinders_map_b.get(), false);
join_dive_computers(*res.dive, *a, *b, cylinders_map_a.get(), cylinders_map_b.get(), false);
}
/* The CNS values will be recalculated from the sample in fixup_dive() */
res->cns = res->maxcns = 0;
res.dive->cns = res.dive->maxcns = 0;
/* we take the first dive site, unless it's empty */
*site = a->dive_site && !a->dive_site->is_empty() ? a->dive_site : b->dive_site;
if (!dive_site_has_gps_location(*site) && dive_site_has_gps_location(b->dive_site)) {
res.site = a->dive_site && !a->dive_site->is_empty() ? a->dive_site : b->dive_site;
if (!dive_site_has_gps_location(res.site) && dive_site_has_gps_location(b->dive_site)) {
/* we picked the first dive site and that didn't have GPS data, but the new dive has
* GPS data (that could be a download from a GPS enabled dive computer).
* Keep the dive site, but add the GPS data */
(*site)->location = b->dive_site->location;
res.site->location = b->dive_site->location;
}
fixup_dive(res);
fixup_dive(res.dive.get());
return res;
}

View file

@ -90,7 +90,7 @@ extern void invalidate_dive_cache(struct dive *dive);
extern bool dive_cache_is_valid(const struct dive *dive);
extern int get_cylinder_idx_by_use(const struct dive *dive, enum cylinderuse cylinder_use_type);
extern void cylinder_renumber(struct dive *dive, int mapping[]);
extern void cylinder_renumber(struct dive &dive, int mapping[]);
extern int same_gasmix_cylinder(const cylinder_t &cyl, int cylid, const struct dive *dive, bool check_unused);
/* when selectively copying dive information, which parts should be copied? */
@ -196,8 +196,15 @@ extern int get_dive_salinity(const struct dive *dive);
extern int dive_getUniqID();
extern std::array<std::unique_ptr<dive>, 2> split_dive(const struct dive &dive);
extern std::array<std::unique_ptr<dive>, 2> split_dive_at_time(const struct dive &dive, duration_t time);
extern struct dive *merge_dives(const struct dive *a, const struct dive *b, int offset, bool prefer_downloaded, struct dive_trip **trip, struct dive_site **site);
extern struct dive *try_to_merge(struct dive *a, struct dive *b, bool prefer_downloaded);
struct merge_result {
std::unique_ptr<struct dive> dive;
dive_trip *trip;
dive_site *site;
};
extern merge_result merge_dives(const struct dive &a, const struct dive &b, int offset, bool prefer_downloaded);
extern std::unique_ptr<dive> try_to_merge(const struct dive &a, const struct dive &b, bool prefer_downloaded);
extern void copy_events_until(const struct dive *sd, struct dive *dd, int dcNr, int time);
extern void copy_used_cylinders(const struct dive *s, struct dive *d, bool used_only);
extern bool is_cylinder_used(const struct dive *dive, int idx);

View file

@ -773,7 +773,6 @@ static void merge_imported_dives(struct dive_table *table)
for (i = 1; i < table->nr; i++) {
struct dive *prev = table->dives[i - 1];
struct dive *dive = table->dives[i];
struct dive *merged;
struct dive_site *ds;
/* only try to merge overlapping dives - or if one of the dives has
@ -782,7 +781,7 @@ static void merge_imported_dives(struct dive_table *table)
dive_endtime(prev) < dive->when)
continue;
merged = try_to_merge(prev, dive, false);
auto merged = try_to_merge(*prev, *dive, false);
if (!merged)
continue;
@ -790,7 +789,7 @@ static void merge_imported_dives(struct dive_table *table)
ds = merged->dive_site;
if (ds) {
merged->dive_site = NULL;
ds->add_dive(merged);
ds->add_dive(merged.get());
}
unregister_dive_from_dive_site(prev);
unregister_dive_from_dive_site(dive);
@ -799,7 +798,7 @@ static void merge_imported_dives(struct dive_table *table)
/* Overwrite the first of the two dives and remove the second */
delete prev;
table->dives[i - 1] = merged;
table->dives[i - 1] = merged.release();
delete_dive_from_table(table, i);
/* Redo the new 'i'th dive */
@ -814,17 +813,17 @@ 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 *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);
merged->divetrip = old_dive.divetrip;
insert_dive(dives_to_remove, &old_dive);
insert_dive(dives_to_add, merged.release());
return true;
}
@ -882,7 +881,7 @@ static bool merge_dive_tables(const std::vector<dive *> &dives_from, struct dive
* transitive. But let's just go *completely* sure for the odd corner-case. */
if (j > 0 && (last_merged_into == std::string::npos || j > last_merged_into + 1) &&
dive_endtime(dives_to[j - 1]) > 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;
@ -895,7 +894,7 @@ static bool merge_dive_tables(const std::vector<dive *> &dives_from, struct dive
* Try to merge into next dive. */
if (j < dives_to.size() && (last_merged_into == std::string::npos || j > last_merged_into) &&
dive_endtime(dive_to_add) > 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;

View file

@ -547,7 +547,7 @@ void CylindersModel::remove(QModelIndex index)
endRemoveRows();
std::vector<int> mapping = get_cylinder_map_for_remove(static_cast<int>(d->cylinders.size() + 1), index.row());
cylinder_renumber(d, mapping.data());
cylinder_renumber(*d, mapping.data());
DivePlannerPointsModel::instance()->cylinderRenumber(mapping.data());
}
@ -621,7 +621,7 @@ void CylindersModel::moveAtFirst(int cylid)
std::iota(mapping.begin(), mapping.begin() + cylid, 1);
mapping[cylid] = 0;
std::iota(mapping.begin() + (cylid + 1), mapping.end(), cylid);
cylinder_renumber(d, mapping.data());
cylinder_renumber(*d, mapping.data());
if (inPlanner)
DivePlannerPointsModel::instance()->cylinderRenumber(mapping.data());
endMoveRows();