From ae299d5e663cd672d1114c3fe90cf026b9ab463e Mon Sep 17 00:00:00 2001 From: Berthold Stoeger Date: Sun, 10 Mar 2024 23:11:23 +0100 Subject: [PATCH] profile: use C++ string functions to format plot data This may appear a bit ominous, as it doesn't generate a string, but a vector of strings (one for each line). However, that is in preparation for the QtQuickification of the profile, where the text-items take such a list. Signed-off-by: Berthold Stoeger --- core/profile.cpp | 275 +++++++++++++---------------- core/profile.h | 10 +- profile-widget/divetooltipitem.cpp | 12 +- profile-widget/ruleritem.cpp | 10 +- 4 files changed, 149 insertions(+), 158 deletions(-) diff --git a/core/profile.cpp b/core/profile.cpp index fb93245b2..c24ac7df5 100644 --- a/core/profile.cpp +++ b/core/profile.cpp @@ -57,8 +57,17 @@ static void dump_pi(struct plot_info *pi) } #endif -#define ROUND_UP(x, y) ((((x) + (y) - 1) / (y)) * (y)) -#define DIV_UP(x, y) (((x) + (y) - 1) / (y)) +template +static T round_up(T x, T y) +{ + return ((x + y - 1) / y) * y; +} + +template +static T div_up(T x, T y) +{ + return (x + y - 1) / y; +} /* * When showing dive profiles, we scale things to the @@ -530,7 +539,7 @@ static void populate_plot_entries(const struct dive *dive, const struct divecomp * * Everything in between has a cylinder pressure for at least some of the cylinders. */ -static int sac_between(const struct dive *dive, struct plot_info *pi, int first, int last, const bool gases[]) +static int sac_between(const struct dive *dive, struct plot_info *pi, int first, int last, const char gases[]) { int i, airuse; double pressuretime; @@ -578,7 +587,7 @@ static int sac_between(const struct dive *dive, struct plot_info *pi, int first, } /* Is there pressure data for all gases? */ -static bool all_pressures(struct plot_info *pi, int idx, const bool gases[]) +static bool all_pressures(struct plot_info *pi, int idx, const char gases[]) { int i; @@ -591,7 +600,7 @@ static bool all_pressures(struct plot_info *pi, int idx, const bool gases[]) } /* Which of the set of gases have pressure data? Returns false if none of them. */ -static bool filter_pressures(struct plot_info *pi, int idx, const bool gases_in[], bool gases_out[]) +static bool filter_pressures(struct plot_info *pi, int idx, const char gases_in[], char gases_out[]) { int i; bool has_pressure = false; @@ -610,7 +619,7 @@ static bool filter_pressures(struct plot_info *pi, int idx, const bool gases_in[ * an array of gases, the caller passes in scratch memory in the last * argument. */ -static void fill_sac(const struct dive *dive, struct plot_info *pi, int idx, const bool gases_in[], bool gases[]) +static void fill_sac(const struct dive *dive, struct plot_info *pi, int idx, const char gases_in[], char gases[]) { struct plot_data *entry = pi->entry + idx; int first, last; @@ -668,7 +677,7 @@ static void fill_sac(const struct dive *dive, struct plot_info *pi, int idx, con /* * Create a bitmap of cylinders that match our current gasmix */ -static void matching_gases(const struct dive *dive, struct gasmix gasmix, bool gases[]) +static void matching_gases(const struct dive *dive, struct gasmix gasmix, char gases[]) { int i; @@ -680,32 +689,28 @@ static void calculate_sac(const struct dive *dive, const struct divecomputer *dc { struct gasmix gasmix = gasmix_invalid; const struct event *ev = NULL; - bool *gases, *gases_scratch; - gases = (bool *)calloc(pi->nr_cylinders, sizeof(*gases)); + std::vector gases(pi->nr_cylinders, false); /* This might be premature optimization, but let's allocate the gas array for * the fill_sac function only once an not once per sample */ - gases_scratch = (bool *)malloc(pi->nr_cylinders * sizeof(*gases)); + std::vector gases_scratch(pi->nr_cylinders); for (int i = 0; i < pi->nr; i++) { struct plot_data *entry = pi->entry + i; struct gasmix newmix = get_gasmix(dive, dc, entry->sec, &ev, gasmix); if (!same_gasmix(newmix, gasmix)) { gasmix = newmix; - matching_gases(dive, newmix, gases); + matching_gases(dive, newmix, gases.data()); } - fill_sac(dive, pi, i, gases, gases_scratch); + fill_sac(dive, pi, i, gases.data(), gases_scratch.data()); } - - free(gases); - free(gases_scratch); } static void populate_secondary_sensor_data(const struct divecomputer *dc, struct plot_info *pi) { - int *seen = (int *)calloc(pi->nr_cylinders, sizeof(*seen)); + std::vector seen(pi->nr_cylinders, 0); for (int idx = 0; idx < pi->nr; ++idx) for (int c = 0; c < pi->nr_cylinders; ++c) if (get_plot_pressure_data(pi, idx, SENSOR_PR, c)) @@ -725,7 +730,6 @@ static void populate_secondary_sensor_data(const struct divecomputer *dc, struct if (sample->sensor[s] != NO_SENSOR && seen[sample->sensor[s]] < 3 && sample->pressure[s].mbar) set_plot_pressure_data(pi, idx, SENSOR_PR, sample->sensor[s], sample->pressure[s].mbar); } - free(seen); } /* @@ -752,16 +756,11 @@ static void setup_gas_sensor_pressure(const struct dive *dive, const struct dive /* FIXME: The planner uses a dummy one-past-end cylinder for surface air! */ int num_cyl = pi->nr_cylinders + 1; - int *seen = (int *)malloc(num_cyl * sizeof(*seen)); - int *first = (int *)malloc(num_cyl * sizeof(*first)); - int *last = (int *)malloc(num_cyl * sizeof(*last)); + std::vector seen(num_cyl, 0); + std::vector first(num_cyl, 0); + std::vector last(num_cyl, INT_MAX); const struct divecomputer *secondary; - for (i = 0; i < num_cyl; i++) { - seen[i] = 0; - first[i] = 0; - last[i] = INT_MAX; - } prev = explicit_first_cylinder(dive, dc); seen[prev] = 1; @@ -839,10 +838,6 @@ static void setup_gas_sensor_pressure(const struct dive *dive, const struct dive continue; populate_secondary_sensor_data(secondary, pi); } while ((secondary = secondary->next) != NULL); - - free(seen); - free(first); - free(last); } /* calculate DECO STOP / TTS / NDL */ @@ -857,7 +852,7 @@ static void calculate_ndl_tts(struct deco_state *ds, const struct dive *dive, st const int time_stepsize = 60; const int deco_stepsize = M_OR_FT(3, 10); /* at what depth is the current deco-step? */ - int next_stop = ROUND_UP(deco_allowed_depth( + int next_stop = round_up(deco_allowed_depth( tissue_tolerance_calc(ds, dive, depth_to_bar(entry->depth, dive), in_planner), surface_pressure, dive, 1), deco_stepsize); int ascent_depth = entry->depth; @@ -892,7 +887,7 @@ static void calculate_ndl_tts(struct deco_state *ds, const struct dive *dive, st for (; ascent_depth > next_stop; ascent_depth -= ascent_s_per_step * ascent_velocity(ascent_depth, entry->running_sum / entry->sec, 0), entry->tts_calc += ascent_s_per_step) { add_segment(ds, depth_to_bar(ascent_depth, dive), gasmix, ascent_s_per_step, entry->o2pressure.mbar, divemode, prefs.decosac, in_planner); - next_stop = ROUND_UP(deco_allowed_depth(tissue_tolerance_calc(ds, dive, depth_to_bar(ascent_depth, dive), in_planner), + next_stop = round_up(deco_allowed_depth(tissue_tolerance_calc(ds, dive, depth_to_bar(ascent_depth, dive), in_planner), surface_pressure, dive, 1), deco_stepsize); } ascent_depth = next_stop; @@ -1098,7 +1093,7 @@ static void calculate_deco_information(struct deco_state *ds, const struct deco_ * at end of whole minute after clearing ceiling. The deepest ceiling when planning a dive * comes typically 10-60s after the end of the bottom time, so add 20s to the calculated * deco time. */ - ds->deco_time = ROUND_UP(time_clear_ceiling - time_deep_ceiling + 20, 60) + 20; + ds->deco_time = round_up(time_clear_ceiling - time_deep_ceiling + 20, 60) + 20; vpmb_next_gradient(ds, ds->deco_time, surface_pressure / 1000.0, in_planner); final_tts = 0; last_ndl_tts_calc_time = 0; @@ -1360,7 +1355,7 @@ extern "C" void create_plot_info_new(const struct dive *dive, const struct divec analyze_plot_info(pi); } -static void plot_string(const struct dive *d, const struct plot_info *pi, int idx, struct membuffer *b) +static std::vector plot_string(const struct dive *d, const struct plot_info *pi, int idx) { int pressurevalue, mod, ead, end, eadd; const char *depth_unit, *pressure_unit, *temp_unit, *vertical_speed_unit; @@ -1368,43 +1363,45 @@ static void plot_string(const struct dive *d, const struct plot_info *pi, int id int decimals, cyl; const char *unit; const struct plot_data *entry = pi->entry + idx; + std::vector res; depthvalue = get_depth_units(entry->depth, NULL, &depth_unit); - put_format_loc(b, translate("gettextFromC", "@: %d:%02d\nD: %.1f%s\n"), FRACTION(entry->sec, 60), depthvalue, depth_unit); + res.push_back(casprintf_loc(translate("gettextFromC", "@: %d:%02d"), FRACTION(entry->sec, 60), depthvalue)); + res.push_back(casprintf_loc(translate("gettextFromC", "D: %.1f%s"), depth_unit)); for (cyl = 0; cyl < pi->nr_cylinders; cyl++) { int mbar = get_plot_pressure(pi, idx, cyl); if (!mbar) continue; struct gasmix mix = get_cylinder(d, cyl)->gasmix; pressurevalue = get_pressure_units(mbar, &pressure_unit); - put_format_loc(b, translate("gettextFromC", "P: %d%s (%s)\n"), pressurevalue, pressure_unit, gasname(mix)); + res.push_back(casprintf_loc(translate("gettextFromC", "P: %d%s (%s)"), pressurevalue, pressure_unit, gasname(mix))); } if (entry->temperature) { tempvalue = get_temp_units(entry->temperature, &temp_unit); - put_format_loc(b, translate("gettextFromC", "T: %.1f%s\n"), tempvalue, temp_unit); + res.push_back(casprintf_loc(translate("gettextFromC", "T: %.1f%s"), tempvalue, temp_unit)); } speedvalue = get_vertical_speed_units(abs(entry->speed), NULL, &vertical_speed_unit); /* Ascending speeds are positive, descending are negative */ if (entry->speed > 0) speedvalue *= -1; - put_format_loc(b, translate("gettextFromC", "V: %.1f%s\n"), speedvalue, vertical_speed_unit); + res.push_back(casprintf_loc(translate("gettextFromC", "V: %.1f%s"), speedvalue, vertical_speed_unit)); sacvalue = get_volume_units(entry->sac, &decimals, &unit); if (entry->sac && prefs.show_sac) - put_format_loc(b, translate("gettextFromC", "SAC: %.*f%s/min\n"), decimals, sacvalue, unit); + res.push_back(casprintf_loc(translate("gettextFromC", "SAC: %.*f%s/min"), decimals, sacvalue, unit)); if (entry->cns) - put_format_loc(b, translate("gettextFromC", "CNS: %u%%\n"), entry->cns); + res.push_back(casprintf_loc(translate("gettextFromC", "CNS: %u%%"), entry->cns)); if (prefs.pp_graphs.po2 && entry->pressures.o2 > 0) { - put_format_loc(b, translate("gettextFromC", "pO₂: %.2fbar\n"), entry->pressures.o2); + res.push_back(casprintf_loc(translate("gettextFromC", "pO₂: %.2fbar"), entry->pressures.o2)); if (entry->scr_OC_pO2.mbar) - put_format_loc(b, translate("gettextFromC", "SCR ΔpO₂: %.2fbar\n"), entry->scr_OC_pO2.mbar/1000.0 - entry->pressures.o2); + res.push_back(casprintf_loc(translate("gettextFromC", "SCR ΔpO₂: %.2fbar"), entry->scr_OC_pO2.mbar/1000.0 - entry->pressures.o2)); } if (prefs.pp_graphs.pn2 && entry->pressures.n2 > 0) - put_format_loc(b, translate("gettextFromC", "pN₂: %.2fbar\n"), entry->pressures.n2); + res.push_back(casprintf_loc(translate("gettextFromC", "pN₂: %.2fbar"), entry->pressures.n2)); if (prefs.pp_graphs.phe && entry->pressures.he > 0) - put_format_loc(b, translate("gettextFromC", "pHe: %.2fbar\n"), entry->pressures.he); + res.push_back(casprintf_loc(translate("gettextFromC", "pHe: %.2fbar"), entry->pressures.he)); if (prefs.mod && entry->mod > 0) { mod = lrint(get_depth_units(entry->mod, NULL, &depth_unit)); - put_format_loc(b, translate("gettextFromC", "MOD: %d%s\n"), mod, depth_unit); + res.push_back(casprintf_loc(translate("gettextFromC", "MOD: %d%s"), mod, depth_unit)); } eadd = lrint(get_depth_units(entry->eadd, NULL, &depth_unit)); @@ -1413,18 +1410,20 @@ static void plot_string(const struct dive *d, const struct plot_info *pi, int id case plot_info::NITROX: if (entry->ead > 0) { ead = lrint(get_depth_units(entry->ead, NULL, &depth_unit)); - put_format_loc(b, translate("gettextFromC", "EAD: %d%s\nEADD: %d%s / %.1fg/ℓ\n"), ead, depth_unit, eadd, depth_unit, entry->density); + res.push_back(casprintf_loc(translate("gettextFromC", "EAD: %d%s"), ead, depth_unit)); + res.push_back(casprintf_loc(translate("gettextFromC", "EADD: %d%s / %.1fg/ℓ"), eadd, depth_unit, entry->density)); break; } case plot_info::TRIMIX: if (entry->end > 0) { end = lrint(get_depth_units(entry->end, NULL, &depth_unit)); - put_format_loc(b, translate("gettextFromC", "END: %d%s\nEADD: %d%s / %.1fg/ℓ\n"), end, depth_unit, eadd, depth_unit, entry->density); + res.push_back(casprintf_loc(translate("gettextFromC", "END: %d%s"), end, depth_unit)); + res.push_back(casprintf_loc(translate("gettextFromC", "EADD: %d%s / %.1fg/ℓ"), eadd, depth_unit, entry->density)); break; } case plot_info::AIR: if (entry->density > 0) { - put_format_loc(b, translate("gettextFromC", "Density: %.1fg/ℓ\n"), entry->density); + res.push_back(casprintf_loc(translate("gettextFromC", "Density: %.1fg/ℓ"), entry->density)); } case plot_info::FREEDIVING: /* nothing */ @@ -1436,151 +1435,142 @@ static void plot_string(const struct dive *d, const struct plot_info *pi, int id if (entry->ndl > 0) { /* this is a safety stop as we still have ndl */ if (entry->stoptime) - put_format_loc(b, translate("gettextFromC", "Safety stop: %umin @ %.0f%s\n"), DIV_UP(entry->stoptime, 60), - depthvalue, depth_unit); + res.push_back(casprintf_loc(translate("gettextFromC", "Safety stop: %umin @ %.0f%s"), div_up(entry->stoptime, 60), + depthvalue, depth_unit)); else - put_format_loc(b, translate("gettextFromC", "Safety stop: unknown time @ %.0f%s\n"), - depthvalue, depth_unit); + res.push_back(casprintf_loc(translate("gettextFromC", "Safety stop: unknown time @ %.0f%s"), + depthvalue, depth_unit)); } else { /* actual deco stop */ if (entry->stoptime) - put_format_loc(b, translate("gettextFromC", "Deco: %umin @ %.0f%s\n"), DIV_UP(entry->stoptime, 60), - depthvalue, depth_unit); + res.push_back(casprintf_loc(translate("gettextFromC", "Deco: %umin @ %.0f%s"), div_up(entry->stoptime, 60), + depthvalue, depth_unit)); else - put_format_loc(b, translate("gettextFromC", "Deco: unknown time @ %.0f%s\n"), - depthvalue, depth_unit); + res.push_back(casprintf_loc(translate("gettextFromC", "Deco: unknown time @ %.0f%s"), + depthvalue, depth_unit)); } } else if (entry->in_deco) { - put_string(b, translate("gettextFromC", "In deco\n")); + res.push_back(translate("gettextFromC", "In deco")); } else if (entry->ndl >= 0) { - put_format_loc(b, translate("gettextFromC", "NDL: %umin\n"), DIV_UP(entry->ndl, 60)); + res.push_back(casprintf_loc(translate("gettextFromC", "NDL: %umin"), div_up(entry->ndl, 60))); } if (entry->tts) - put_format_loc(b, translate("gettextFromC", "TTS: %umin\n"), DIV_UP(entry->tts, 60)); + res.push_back(casprintf_loc(translate("gettextFromC", "TTS: %umin"), div_up(entry->tts, 60))); if (entry->stopdepth_calc && entry->stoptime_calc) { depthvalue = get_depth_units(entry->stopdepth_calc, NULL, &depth_unit); - put_format_loc(b, translate("gettextFromC", "Deco: %umin @ %.0f%s (calc)\n"), DIV_UP(entry->stoptime_calc, 60), - depthvalue, depth_unit); + res.push_back(casprintf_loc(translate("gettextFromC", "Deco: %umin @ %.0f%s (calc)"), div_up(entry->stoptime_calc, 60), + depthvalue, depth_unit)); } else if (entry->in_deco_calc) { /* This means that we have no NDL left, * and we have no deco stop, * so if we just accend to the surface slowly * (ascent_mm_per_step / ascent_s_per_step) * everything will be ok. */ - put_string(b, translate("gettextFromC", "In deco (calc)\n")); + res.push_back(translate("gettextFromC", "In deco (calc)")); } else if (prefs.calcndltts && entry->ndl_calc != 0) { if(entry->ndl_calc < MAX_PROFILE_DECO) - put_format_loc(b, translate("gettextFromC", "NDL: %umin (calc)\n"), DIV_UP(entry->ndl_calc, 60)); + res.push_back(casprintf_loc(translate("gettextFromC", "NDL: %umin (calc)"), div_up(entry->ndl_calc, 60))); else - put_string(b, translate("gettextFromC", "NDL: >2h (calc)\n")); + res.push_back(translate("gettextFromC", "NDL: >2h (calc)")); } if (entry->tts_calc) { if (entry->tts_calc < MAX_PROFILE_DECO) - put_format_loc(b, translate("gettextFromC", "TTS: %umin (calc)\n"), DIV_UP(entry->tts_calc, 60)); + res.push_back(casprintf_loc(translate("gettextFromC", "TTS: %umin (calc)"), div_up(entry->tts_calc, 60))); else - put_string(b, translate("gettextFromC", "TTS: >2h (calc)\n")); + res.push_back(translate("gettextFromC", "TTS: >2h (calc)")); } if (entry->rbt) - put_format_loc(b, translate("gettextFromC", "RBT: %umin\n"), DIV_UP(entry->rbt, 60)); + res.push_back(casprintf_loc(translate("gettextFromC", "RBT: %umin"), div_up(entry->rbt, 60))); if (prefs.decoinfo) { if (entry->current_gf > 0.0) - put_format(b, translate("gettextFromC", "GF %d%%\n"), (int)(100.0 * entry->current_gf)); + res.push_back(casprintf_loc(translate("gettextFromC", "GF %d%%"), (int)(100.0 * entry->current_gf))); if (entry->surface_gf > 0.0) - put_format(b, translate("gettextFromC", "Surface GF %.0f%%\n"), entry->surface_gf); + res.push_back(casprintf_loc(translate("gettextFromC", "Surface GF %.0f%%"), entry->surface_gf)); if (entry->ceiling) { depthvalue = get_depth_units(entry->ceiling, NULL, &depth_unit); - put_format_loc(b, translate("gettextFromC", "Calculated ceiling %.1f%s\n"), depthvalue, depth_unit); + res.push_back(casprintf_loc(translate("gettextFromC", "Calculated ceiling %.1f%s"), depthvalue, depth_unit)); if (prefs.calcalltissues) { int k; for (k = 0; k < 16; k++) { if (entry->ceilings[k]) { depthvalue = get_depth_units(entry->ceilings[k], NULL, &depth_unit); - put_format_loc(b, translate("gettextFromC", "Tissue %.0fmin: %.1f%s\n"), buehlmann_N2_t_halflife[k], depthvalue, depth_unit); + res.push_back(casprintf_loc(translate("gettextFromC", "Tissue %.0fmin: %.1f%s"), buehlmann_N2_t_halflife[k], depthvalue, depth_unit)); } } } } } if (entry->icd_warning) - put_format(b, "%s", translate("gettextFromC", "ICD in leading tissue\n")); + res.push_back(translate("gettextFromC", "ICD in leading tissue")); if (entry->heartbeat && prefs.hrgraph) - put_format_loc(b, translate("gettextFromC", "heart rate: %d\n"), entry->heartbeat); + res.push_back(casprintf_loc(translate("gettextFromC", "heart rate: %d"), entry->heartbeat)); if (entry->bearing >= 0) - put_format_loc(b, translate("gettextFromC", "bearing: %d\n"), entry->bearing); + res.push_back(casprintf_loc(translate("gettextFromC", "bearing: %d"), entry->bearing)); if (entry->running_sum) { depthvalue = get_depth_units(entry->running_sum / entry->sec, NULL, &depth_unit); - put_format_loc(b, translate("gettextFromC", "mean depth to here %.1f%s\n"), depthvalue, depth_unit); + res.push_back(casprintf_loc(translate("gettextFromC", "mean depth to here %.1f%s"), depthvalue, depth_unit)); } - strip_mb(b); + return res; } -extern "C" int get_plot_details_new(const struct dive *d, const struct plot_info *pi, int time, struct membuffer *mb) +std::pair> get_plot_details_new(const struct dive *d, const struct plot_info *pi, int time) { - int i; - /* The two first and the two last plot entries do not have useful data */ if (pi->nr <= 4) - return 0; - for (i = 2; i < pi->nr - 3; i++) { - if (pi->entry[i].sec >= time) - break; - } - plot_string(d, pi, i, mb); - return i; + return { 0, {} }; + + // binary search for sample index + auto it = std::lower_bound(pi->entry + 2, pi->entry + pi->nr - 3, time, + [] (const plot_data &d, int time) + { return d.sec < time; }); + int idx = it - pi->entry; + + auto strings = plot_string(d, pi, idx); + return std::make_pair(idx, strings); } -/* Compare two plot_data entries and writes the results into a string */ -extern "C" void compare_samples(const struct dive *d, const struct plot_info *pi, int idx1, int idx2, char *buf, int bufsize, bool sum) +/* Compare two plot_data entries and writes the results into a set of strings */ +std::vector compare_samples(const struct dive *d, const struct plot_info *pi, int idx1, int idx2, bool sum) { - struct plot_data *start, *stop, *data; + std::string space(" "); const char *depth_unit, *pressure_unit, *vertical_speed_unit; - char *buf2 = (char *)malloc(bufsize); - int avg_speed, max_asc_speed, max_desc_speed; - int delta_depth, avg_depth, max_depth, min_depth; - int pressurevalue; - int last_sec, delta_time; - double depthvalue, speedvalue; - if (bufsize > 0) - buf[0] = '\0'; - if (idx1 < 0 || idx2 < 0) { - free(buf2); - return; - } + std::vector res; + if (idx1 < 0 || idx2 < 0) + return res; if (pi->entry[idx1].sec > pi->entry[idx2].sec) { int tmp = idx2; idx2 = idx1; idx1 = tmp; } else if (pi->entry[idx1].sec == pi->entry[idx2].sec) { - free(buf2); - return; + return res; } - start = pi->entry + idx1; - stop = pi->entry + idx2; + struct plot_data *start = pi->entry + idx1; + struct plot_data *stop = pi->entry + idx2; - avg_speed = 0; - max_asc_speed = 0; - max_desc_speed = 0; + int avg_speed = 0; + int max_asc_speed = 0; + int max_desc_speed = 0; - delta_depth = abs(start->depth - stop->depth); - delta_time = abs(start->sec - stop->sec); - avg_depth = 0; - max_depth = 0; - min_depth = INT_MAX; + int delta_depth = abs(start->depth - stop->depth); + int delta_time = abs(start->sec - stop->sec); + int avg_depth = 0; + int max_depth = 0; + int min_depth = INT_MAX; - last_sec = start->sec; + int last_sec = start->sec; volume_t cylinder_volume = { .mliter = 0, }; - int *start_pressures = (int *)calloc((size_t)pi->nr_cylinders, sizeof(int)); - int *last_pressures = (int *)calloc((size_t)pi->nr_cylinders, sizeof(int)); - int *bar_used = (int *)calloc((size_t)pi->nr_cylinders, sizeof(int)); - int *volumes_used = (int *)calloc((size_t)pi->nr_cylinders, sizeof(int)); - bool *cylinder_is_used = (bool *)calloc((size_t)pi->nr_cylinders, sizeof(bool)); + std::vector start_pressures(pi->nr_cylinders, 0); + std::vector last_pressures(pi->nr_cylinders, 0); + std::vector bar_used(pi->nr_cylinders, 0); + std::vector volumes_used(pi->nr_cylinders, 0); + std::vector cylinder_is_used(pi->nr_cylinders, false); - data = start; + struct plot_data *data = start; for (int i = idx1; i < idx2; ++i) { data = pi->entry + i; if (sum) @@ -1625,47 +1615,38 @@ extern "C" void compare_samples(const struct dive *d, const struct plot_info *pi last_sec = data->sec; } - free(start_pressures); - free(last_pressures); - avg_depth /= stop->sec - start->sec; avg_speed /= stop->sec - start->sec; - snprintf_loc(buf, bufsize, translate("gettextFromC", "ΔT:%d:%02dmin"), delta_time / 60, delta_time % 60); - memcpy(buf2, buf, bufsize); + std::string l = casprintf_loc(translate("gettextFromC", "ΔT:%d:%02dmin"), delta_time / 60, delta_time % 60); depthvalue = get_depth_units(delta_depth, NULL, &depth_unit); - snprintf_loc(buf, bufsize, translate("gettextFromC", "%s ΔD:%.1f%s"), buf2, depthvalue, depth_unit); - memcpy(buf2, buf, bufsize); + l += space + casprintf_loc(translate("gettextFromC", "ΔD:%.1f%s"), depthvalue, depth_unit); depthvalue = get_depth_units(min_depth, NULL, &depth_unit); - snprintf_loc(buf, bufsize, translate("gettextFromC", "%s ↓D:%.1f%s"), buf2, depthvalue, depth_unit); - memcpy(buf2, buf, bufsize); + l += space + casprintf_loc(translate("gettextFromC", "↓D:%.1f%s"), depthvalue, depth_unit); depthvalue = get_depth_units(max_depth, NULL, &depth_unit); - snprintf_loc(buf, bufsize, translate("gettextFromC", "%s ↑D:%.1f%s"), buf2, depthvalue, depth_unit); - memcpy(buf2, buf, bufsize); + l += space + casprintf_loc(translate("gettextFromC", "↑D:%.1f%s"), depthvalue, depth_unit); depthvalue = get_depth_units(avg_depth, NULL, &depth_unit); - snprintf_loc(buf, bufsize, translate("gettextFromC", "%s øD:%.1f%s\n"), buf2, depthvalue, depth_unit); - memcpy(buf2, buf, bufsize); + l += space + casprintf_loc(translate("gettextFromC", "øD:%.1f%s"), depthvalue, depth_unit); + res.push_back(l); speedvalue = get_vertical_speed_units(abs(max_desc_speed), NULL, &vertical_speed_unit); - snprintf_loc(buf, bufsize, translate("gettextFromC", "%s ↓V:%.2f%s"), buf2, speedvalue, vertical_speed_unit); - memcpy(buf2, buf, bufsize); + l = casprintf_loc(translate("gettextFromC", "↓V:%.2f%s"), speedvalue, vertical_speed_unit); speedvalue = get_vertical_speed_units(abs(max_asc_speed), NULL, &vertical_speed_unit); - snprintf_loc(buf, bufsize, translate("gettextFromC", "%s ↑V:%.2f%s"), buf2, speedvalue, vertical_speed_unit); - memcpy(buf2, buf, bufsize); + l += space + casprintf_loc(translate("gettextFromC", "↑V:%.2f%s"), speedvalue, vertical_speed_unit); speedvalue = get_vertical_speed_units(abs(avg_speed), NULL, &vertical_speed_unit); - snprintf_loc(buf, bufsize, translate("gettextFromC", "%s øV:%.2f%s"), buf2, speedvalue, vertical_speed_unit); + l += space + casprintf_loc(translate("gettextFromC", "øV:%.2f%s"), speedvalue, vertical_speed_unit); int total_bar_used = 0; int total_volume_used = 0; bool cylindersizes_are_identical = true; bool sac_is_determinable = true; - for (int cylinder_index = 0; cylinder_index < pi->nr_cylinders; cylinder_index++) + for (int cylinder_index = 0; cylinder_index < pi->nr_cylinders; cylinder_index++) { if (cylinder_is_used[cylinder_index]) { total_bar_used += bar_used[cylinder_index]; total_volume_used += volumes_used[cylinder_index]; @@ -1681,20 +1662,16 @@ extern "C" void compare_samples(const struct dive *d, const struct plot_info *pi sac_is_determinable = false; } } - free(bar_used); - free(volumes_used); - free(cylinder_is_used); + } // No point printing 'bar used' if we know it's meaningless because cylinders of different size were used if (cylindersizes_are_identical && total_bar_used) { - pressurevalue = get_pressure_units(total_bar_used, &pressure_unit); - memcpy(buf2, buf, bufsize); - snprintf_loc(buf, bufsize, translate("gettextFromC", "%s ΔP:%d%s"), buf2, pressurevalue, pressure_unit); + int pressurevalue = get_pressure_units(total_bar_used, &pressure_unit); + l += space + casprintf_loc(translate("gettextFromC", "ΔP:%d%s"), pressurevalue, pressure_unit); } // We can't calculate the SAC if the volume for some of the cylinders used is unknown if (sac_is_determinable && total_volume_used) { - double volume_value; int volume_precision; const char *volume_unit; @@ -1703,10 +1680,10 @@ extern "C" void compare_samples(const struct dive *d, const struct plot_info *pi /* milliliters per minute */ int sac = lrint(total_volume_used / atm * 60 / delta_time); - memcpy(buf2, buf, bufsize); - volume_value = get_volume_units(sac, &volume_precision, &volume_unit); - snprintf_loc(buf, bufsize, translate("gettextFromC", "%s SAC:%.*f%s/min"), buf2, volume_precision, volume_value, volume_unit); + double volume_value = get_volume_units(sac, &volume_precision, &volume_unit); + l += space + casprintf_loc(translate("gettextFromC", "SAC:%.*f%s/min"), volume_precision, volume_value, volume_unit); } + res.push_back(l); - free(buf2); + return res; } diff --git a/core/profile.h b/core/profile.h index d3c7316d5..8812937d9 100644 --- a/core/profile.h +++ b/core/profile.h @@ -97,11 +97,9 @@ struct plot_info { #define AMB_PERCENTAGE 50.0 -extern void compare_samples(const struct dive *d, const struct plot_info *pi, int idx1, int idx2, char *buf, int bufsize, bool sum); extern void init_plot_info(struct plot_info *pi); /* when planner_dc is non-null, this is called in planner mode. */ extern void create_plot_info_new(const struct dive *dive, const struct divecomputer *dc, struct plot_info *pi, const struct deco_state *planner_ds); -extern int get_plot_details_new(const struct dive *d, const struct plot_info *pi, int time, struct membuffer *); extern void free_plot_info_data(struct plot_info *pi); /* @@ -145,5 +143,13 @@ static inline int get_plot_pressure(const struct plot_info *pi, int idx, int cyl #ifdef __cplusplus } + +// C++ only formatting functions +#include +#include +// Returns index of sample and array of strings describing the dive details at given time +std::pair> get_plot_details_new(const struct dive *d, const struct plot_info *pi, int time); +std::vector compare_samples(const struct dive *d, const struct plot_info *pi, int idx1, int idx2, bool sum); + #endif #endif // PROFILE_H diff --git a/profile-widget/divetooltipitem.cpp b/profile-widget/divetooltipitem.cpp index 84423dc59..403e252d7 100644 --- a/profile-widget/divetooltipitem.cpp +++ b/profile-widget/divetooltipitem.cpp @@ -222,8 +222,6 @@ void ToolTipItem::setTimeAxis(DiveCartesianAxis *axis) void ToolTipItem::refresh(const dive *d, const QPointF &pos, bool inPlanner) { - struct membufferpp mb; - if(refreshTime.elapsed() < 40) return; refreshTime.start(); @@ -233,7 +231,7 @@ void ToolTipItem::refresh(const dive *d, const QPointF &pos, bool inPlanner) lastTime = time; clear(); - int idx = get_plot_details_new(d, &pInfo, time, &mb); + auto [idx, lines] = get_plot_details_new(d, &pInfo, time); tissues.fill(); painter.setPen(QColor(0, 0, 0, 0)); @@ -253,7 +251,13 @@ void ToolTipItem::refresh(const dive *d, const QPointF &pos, bool inPlanner) painter.setPen(QColor(0, 0, 0, 127)); for (int i = 0; i < 16; i++) painter.drawLine(i, 60, i, 60 - entry->percentages[i] / 2); - entryToolTip.second->setPlainText(QString::fromUtf8(mb.buffer, mb.len)); + QString text; + for (const std::string &s: lines) { + if (!text.isEmpty()) + text += '\n'; + text += QString::fromStdString(s); + } + entryToolTip.second->setPlainText(text); } entryToolTip.first->setPixmap(tissues); diff --git a/profile-widget/ruleritem.cpp b/profile-widget/ruleritem.cpp index fdfabaf84..b431749c6 100644 --- a/profile-widget/ruleritem.cpp +++ b/profile-widget/ruleritem.cpp @@ -93,7 +93,6 @@ void RulerItem2::settingsChanged(bool value) void RulerItem2::recalculate() { - char buffer[500]; QPointF tmp; QFont font; QFontMetrics fm(font); @@ -112,8 +111,13 @@ void RulerItem2::recalculate() } QLineF line(startPoint, endPoint); setLine(line); - compare_samples(dive, pInfo, source->idx, dest->idx, buffer, 500, 1); - text = QString(buffer); + + QString text; + for (const std::string &s: compare_samples(dive, pInfo, source->idx, dest->idx, 1)) { + if (!text.isEmpty()) + text += '\n'; + text += QString::fromStdString(s); + } // draw text QGraphicsView *view = scene()->views().first();