From 834f2278fc0499a3b1bf5f41adc8253f46c186a1 Mon Sep 17 00:00:00 2001 From: Berthold Stoeger Date: Fri, 3 May 2024 06:50:23 +0200 Subject: [PATCH] core: convert gaspressures.c to C++ Replace "poor man's" linked list implementation by std::vector<>. Signed-off-by: Berthold Stoeger --- Subsurface-mobile.pro | 2 +- core/CMakeLists.txt | 2 +- core/{gaspressures.c => gaspressures.cpp} | 210 ++++++++-------------- 3 files changed, 81 insertions(+), 133 deletions(-) rename core/{gaspressures.c => gaspressures.cpp} (71%) diff --git a/Subsurface-mobile.pro b/Subsurface-mobile.pro index 95c64eced..a421c7d6f 100644 --- a/Subsurface-mobile.pro +++ b/Subsurface-mobile.pro @@ -58,7 +58,7 @@ SOURCES += subsurface-mobile-main.cpp \ core/divelist.cpp \ core/divelog.cpp \ core/gas-model.cpp \ - core/gaspressures.c \ + core/gaspressures.cpp \ core/git-access.cpp \ core/globals.cpp \ core/liquivision.cpp \ diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 6b7aab7ab..e8867217f 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -102,7 +102,7 @@ set(SUBSURFACE_CORE_LIB_SRCS gas.c gas.h gas-model.cpp - gaspressures.c + gaspressures.cpp gaspressures.h gettext.h gettextfromc.cpp diff --git a/core/gaspressures.c b/core/gaspressures.cpp similarity index 71% rename from core/gaspressures.c rename to core/gaspressures.cpp index 3e440c5df..10f7a17ba 100644 --- a/core/gaspressures.c +++ b/core/gaspressures.cpp @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 -/* gaspressures.c - * --------------- +/* gaspressures.cpp + * ---------------- * This file contains the routines to calculate the gas pressures in the cylinders. * The functions below support the code in profile.cpp. * The high-level function is populate_pressure_information(), called by function @@ -10,12 +10,6 @@ * populate_pressure_information() -> calc_pressure_time() * -> fill_missing_tank_pressures() -> fill_missing_segment_pressures() * -> get_pr_interpolate_data() - * - * The pr_track_t related functions below implement a linked list that is used by - * the majority of the functions below. The linked list covers a part of the dive profile - * for which there are no cylinder pressure data. Each element in the linked list - * represents a segment between two consecutive points on the dive profile. - * pr_track_t is defined in gaspressures.h */ #include "ssrf.h" @@ -26,23 +20,29 @@ #include "pref.h" #include +#include /* * simple structure to track the beginning and end tank pressure as * well as the integral of depth over time spent while we have no * pressure reading from the tank */ -typedef struct pr_track_struct pr_track_t; -struct pr_track_struct { +struct pr_track_t { int start; int end; int t_start; int t_end; int pressure_time; - pr_track_t *next; + pr_track_t(int start, int t_start) : + start(start), + end(0), + t_start(t_start), + t_end(t_start), + pressure_time(0) + { + } }; -typedef struct pr_interpolate_struct pr_interpolate_t; -struct pr_interpolate_struct { +struct pr_interpolate_t { int start; int end; int pressure_time; @@ -51,61 +51,17 @@ struct pr_interpolate_struct { enum interpolation_strategy {SAC, TIME, CONSTANT}; -static pr_track_t *pr_track_alloc(int start, int t_start) -{ - pr_track_t *pt = malloc(sizeof(pr_track_t)); - pt->start = start; - pt->end = 0; - pt->t_start = pt->t_end = t_start; - pt->pressure_time = 0; - pt->next = NULL; - return pt; -} - -/* poor man's linked list */ -static pr_track_t *list_last(pr_track_t *list) -{ - pr_track_t *tail = list; - if (!tail) - return NULL; - while (tail->next) { - tail = tail->next; - } - return tail; -} - -static pr_track_t *list_add(pr_track_t *list, pr_track_t *element) -{ - pr_track_t *tail = list_last(list); - if (!tail) - return element; - tail->next = element; - return list; -} - -static void list_free(pr_track_t *list) -{ - if (!list) - return; - list_free(list->next); - free(list); -} - #ifdef DEBUG_PR_TRACK -static void dump_pr_track(int cyl, pr_track_t *track_pr) +static void dump_pr_track(int cyl, std::vector &track_pr) { - pr_track_t *list; - printf("cyl%d:\n", cyl); - list = track_pr; - while (list) { + for (const auto &item: track_pr) { printf(" start %f end %f t_start %d:%02d t_end %d:%02d pt %d\n", - mbar_to_PSI(list->start), - mbar_to_PSI(list->end), - FRACTION_TUPLE(list->t_start, 60), - FRACTION_TUPLE(list->t_end, 60), - list->pressure_time); - list = list->next; + mbar_to_PSI(item.start), + mbar_to_PSI(item.end), + FRACTION_TUPLE(item.t_start, 60), + FRACTION_TUPLE(item.t_end, 60), + item.pressure_time); } } #endif @@ -128,24 +84,24 @@ static void dump_pr_track(int cyl, pr_track_t *track_pr) * segments according to how big of a time_pressure area * they have. */ -static void fill_missing_segment_pressures(pr_track_t *list, enum interpolation_strategy strategy) +static void fill_missing_segment_pressures(std::vector &list, enum interpolation_strategy strategy) { double magic; - while (list) { - int start = list->start, end; - pr_track_t *tmp = list; + for (auto it = list.begin(); it != list.end(); ++it) { + int start = it->start, end; int pt_sum = 0, pt = 0; + auto tmp = it; for (;;) { pt_sum += tmp->pressure_time; end = tmp->end; if (end) break; end = start; - if (!tmp->next) + if (std::next(tmp) == list.end()) break; - tmp = tmp->next; + ++tmp; } if (!start) @@ -159,37 +115,34 @@ static void fill_missing_segment_pressures(pr_track_t *list, enum interpolation_ * * Now dole out the pressures relative to pressure-time. */ - list->start = start; + it->start = start; tmp->end = end; switch (strategy) { case SAC: for (;;) { int pressure; - pt += list->pressure_time; + pt += it->pressure_time; pressure = start; if (pt_sum) pressure -= lrint((start - end) * (double)pt / pt_sum); - list->end = pressure; - if (list == tmp) + it->end = pressure; + if (it == tmp) break; - list = list->next; - list->start = pressure; + ++it; + it->start = pressure; } break; case TIME: - if (list->t_end && (tmp->t_start - tmp->t_end)) { - magic = (list->t_start - tmp->t_end) / (tmp->t_start - tmp->t_end); - list->end = lrint(start - (start - end) * magic); + if (it->t_end && (tmp->t_start - tmp->t_end)) { + magic = (it->t_start - tmp->t_end) / (tmp->t_start - tmp->t_end); + it->end = lrint(start - (start - end) * magic); } else { - list->end = start; + it->end = start; } break; case CONSTANT: - list->end = start; + it->end = start; } - - /* Ok, we've done that set of segments */ - list = list->next; } } @@ -202,24 +155,24 @@ void dump_pr_interpolate(int i, pr_interpolate_t interpolate_pr) #endif -static struct pr_interpolate_struct get_pr_interpolate_data(pr_track_t *segment, struct plot_info *pi, int cur) +static pr_interpolate_t get_pr_interpolate_data(const pr_track_t &segment, struct plot_info *pi, int cur) { // cur = index to pi->entry corresponding to t_end of segment; - struct pr_interpolate_struct interpolate; + pr_interpolate_t interpolate; int i; struct plot_data *entry; - interpolate.start = segment->start; - interpolate.end = segment->end; + interpolate.start = segment.start; + interpolate.end = segment.end; interpolate.acc_pressure_time = 0; interpolate.pressure_time = 0; for (i = 0; i < pi->nr; i++) { entry = pi->entry + i; - if (entry->sec < segment->t_start) + if (entry->sec < segment.t_start) continue; interpolate.pressure_time += entry->pressure_time; - if (entry->sec >= segment->t_end) + if (entry->sec >= segment.t_end) break; if (i <= cur) interpolate.acc_pressure_time += entry->pressure_time; @@ -227,17 +180,16 @@ static struct pr_interpolate_struct get_pr_interpolate_data(pr_track_t *segment, return interpolate; } -static void fill_missing_tank_pressures(const struct dive *dive, struct plot_info *pi, pr_track_t *track_pr, int cyl) +static void fill_missing_tank_pressures(const struct dive *dive, struct plot_info *pi, std::vector &track_pr, int cyl) { int i; struct plot_data *entry; pr_interpolate_t interpolate = { 0, 0, 0, 0 }; - pr_track_t *last_segment = NULL; int cur_pr; enum interpolation_strategy strategy; /* no segment where this cylinder is used */ - if (!track_pr) + if (track_pr.empty()) return; if (get_cylinder(dive, cyl)->cylinder_use == OC_GAS) @@ -245,7 +197,7 @@ static void fill_missing_tank_pressures(const struct dive *dive, struct plot_inf else strategy = TIME; fill_missing_segment_pressures(track_pr, strategy); // Interpolate the missing tank pressure values .. - cur_pr = track_pr->start; // in the pr_track_t lists of structures + cur_pr = track_pr[0].start; // in the pr_track_t lists of structures // and keep the starting pressure for each cylinder. #ifdef DEBUG_PR_TRACK dump_pr_track(cyl, track_pr); @@ -261,47 +213,47 @@ static void fill_missing_tank_pressures(const struct dive *dive, struct plot_inf * * The first two pi structures are "fillers", but in case we don't have a sample * at time 0 we need to process the second of them here, therefore i=1 */ + auto last_segment = track_pr.end(); for (i = 1; i < pi->nr; i++) { // For each point on the profile: double magic; - pr_track_t *segment; int pressure; entry = pi->entry + i; pressure = get_plot_pressure(pi, i, cyl); - if (pressure) { // If there is a valid pressure value, - last_segment = NULL; // get rid of interpolation data, - cur_pr = pressure; // set current pressure - continue; // and skip to next point. + if (pressure) { // If there is a valid pressure value, + last_segment = track_pr.end(); // get rid of interpolation data, + cur_pr = pressure; // set current pressure + continue; // and skip to next point. } // If there is NO valid pressure value.. // Find the pressure segment corresponding to this entry.. - segment = track_pr; - while (segment && segment->t_end < entry->sec) // Find the track_pr with end time.. - segment = segment->next; // ..that matches the plot_info time (entry->sec) + auto it = track_pr.begin(); + while (it != track_pr.end() && it->t_end < entry->sec) // Find the track_pr with end time.. + ++it; // ..that matches the plot_info time (entry->sec) // After last segment? All done. - if (!segment) + if (it == track_pr.end()) break; // Before first segment, or between segments.. Go on, no interpolation. - if (segment->t_start > entry->sec) + if (it->t_start > entry->sec) continue; - if (!segment->pressure_time) { // Empty segment? + if (!it->pressure_time) { // Empty segment? set_plot_pressure_data(pi, i, SENSOR_PR, cyl, cur_pr); // Just use our current pressure continue; // and skip to next point. } // If there is a valid segment but no tank pressure .. - if (segment == last_segment) { + if (it == last_segment) { interpolate.acc_pressure_time += entry->pressure_time; } else { // Set up an interpolation structure - interpolate = get_pr_interpolate_data(segment, pi, i); - last_segment = segment; + interpolate = get_pr_interpolate_data(*it, pi, i); + last_segment = it; } if(get_cylinder(dive, cyl)->cylinder_use == OC_GAS) { @@ -315,14 +267,13 @@ static void fill_missing_tank_pressures(const struct dive *dive, struct plot_inf cur_pr = lrint(interpolate.start + magic * interpolate.acc_pressure_time); } } else { - magic = (interpolate.end - interpolate.start) / (segment->t_end - segment->t_start); - cur_pr = lrint(segment->start + magic * (entry->sec - segment->t_start)); + magic = (interpolate.end - interpolate.start) / (it->t_end - it->t_start); + cur_pr = lrint(it->start + magic * (entry->sec - it->t_start)); } set_plot_pressure_data(pi, i, INTERPOLATED_PR, cyl, cur_pr); // and store the interpolated data in plot_info } } - /* * What's the pressure-time between two plot data entries? * We're calculating the integral of pressure over time by @@ -357,20 +308,20 @@ static void debug_print_pressures(struct plot_info *pi) /* This function goes through the list of tank pressures, of structure plot_info for the dive profile where each * item in the list corresponds to one point (node) of the profile. It finds values for which there are no tank - * pressures (pressure==0). For each missing item (node) of tank pressure it creates a pr_track_alloc structure + * pressures (pressure==0). For each missing item (node) of tank pressure it creates a pr_track_t structure * that represents a segment on the dive profile and that contains tank pressures. There is a linked list of - * pr_track_alloc structures for each cylinder. These pr_track_alloc structures ultimately allow for filling + * pr_track_t structures for each cylinder. These pr_track_t structures ultimately allow for filling * the missing tank pressure values on the dive profile using the depth_pressure of the dive. To do this, it - * calculates the summed pressure-time value for the duration of the dive and stores these * in the pr_track_alloc + * calculates the summed pressure-time value for the duration of the dive and stores these in the pr_track_t * structures. This function is called by create_plot_info_new() in profile.cpp */ +extern "C" void populate_pressure_information(const struct dive *dive, const struct divecomputer *dc, struct plot_info *pi, int sensor) { - UNUSED(dc); int first, last, cyl; cylinder_t *cylinder = get_cylinder(dive, sensor); - pr_track_t *track = NULL; - pr_track_t *current = NULL; + std::vector track; + size_t current = std::string::npos; const struct event *ev, *b_ev; int missing_pr = 0, dense = 1; enum divemode_t dmode = dc->divemode; @@ -427,16 +378,16 @@ void populate_pressure_information(const struct dive *dive, const struct divecom } while (b_ev && b_ev->time.seconds <= time) { // Keep existing divemode, then - dmode = b_ev->value; // find 1st divemode change event after the current + dmode = static_cast(b_ev->value); // find 1st divemode change event after the current b_ev = get_next_event(b_ev->next, "modechange"); // divemode change. } - if (current) { // calculate pressure-time, taking into account the dive mode for this specific segment. + if (current != std::string::npos) { // calculate pressure-time, taking into account the dive mode for this specific segment. entry->pressure_time = (int)(calc_pressure_time(dive, entry - 1, entry) * gasfactor[dmode] + 0.5); - current->pressure_time += entry->pressure_time; - current->t_end = entry->sec; + track[current].pressure_time += entry->pressure_time; + track[current].t_end = entry->sec; if (pressure) - current->end = pressure; + track[current].end = pressure; } // We have a final pressure for 'current' @@ -444,7 +395,7 @@ void populate_pressure_information(const struct dive *dive, const struct divecom // current pressure track entry and continue // until we get back to this cylinder. if (cyl != sensor) { - current = NULL; + current = std::string::npos; set_plot_pressure_data(pi, i, SENSOR_PR, sensor, 0); continue; } @@ -453,7 +404,7 @@ void populate_pressure_information(const struct dive *dive, const struct divecom // continue with or without a tracking entry. Mark any // existing tracking entry as non-dense, and remember // to fill in interpolated data. - if (current && !pressure) { + if (current != std::string::npos && !pressure) { missing_pr = 1; dense = 0; continue; @@ -462,7 +413,7 @@ void populate_pressure_information(const struct dive *dive, const struct divecom // If we already have a pressure tracking entry, and // it has not had any missing samples, just continue // using it - there's nothing to interpolate yet. - if (current && dense) + if (current != std::string::npos && dense) continue; // We need to start a new tracking entry, either @@ -471,18 +422,15 @@ void populate_pressure_information(const struct dive *dive, const struct divecom // missing entries that need to be interpolated. // Or maybe we didn't have a previous one at all, // and this is the first pressure entry. - current = pr_track_alloc(pressure, entry->sec); - track = list_add(track, current); + track.emplace_back(pressure, entry->sec); + current = track.size() - 1; dense = 1; } - if (missing_pr) { + if (missing_pr) fill_missing_tank_pressures(dive, pi, track, sensor); - } #ifdef PRINT_PRESSURES_DEBUG debug_print_pressures(pi); #endif - - list_free(track); }