mirror of
				https://github.com/subsurface/subsurface.git
				synced 2025-02-19 22:16:15 +00:00 
			
		
		
		
	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:
		
							parent
							
								
									1e09ec77d7
								
							
						
					
					
						commit
						aa60e5d21d
					
				
					 6 changed files with 184 additions and 195 deletions
				
			
		| 
						 | 
				
			
			@ -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()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										309
									
								
								core/dive.cpp
									
										
									
									
									
								
							
							
						
						
									
										309
									
								
								core/dive.cpp
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										13
									
								
								core/dive.h
									
										
									
									
									
								
							
							
						
						
									
										13
									
								
								core/dive.h
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue