core: turn C dive-table into an owning table

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

27
core/divesitetable.h Normal file
View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

21
core/triptable.h Normal file
View file

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

View file

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

View file

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

View file

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