Compare commits

...

6 commits

Author SHA1 Message Date
Morten Borup Petersen
f8feef25ea
Merge 407beefad6 into 4f7d567571 2024-11-17 08:40:40 +13:00
Berthold Stoeger
4f7d567571 planner: use value semantics for computeVariations()
When computing the variations in a background thread, the
code has to work on a copy of the dive plan and the deco
state. Instead of passing a copy via a unique_ptr<>, simply
use value semantics when calling computeVariations().

This does an unnecessary copy of the deco state, when
computeVariations is not run in the background, but so what.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2024-11-17 08:40:24 +13:00
Berthold Stoeger
9f55f167b2 planner: fix calculations of variations
In 8704a8b the code in cloneDiveplan() was replaced by a simple
assignment statement.

Alas, the original code was more complex: it copied only up
to a certain point (it stopped at automatically generated
steps).

The new behavior made the calculations of variations fail,
because a call to plan() adds deco stops.

Therefore, copy the plan _before_ calling plan().

Fixes #4368

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2024-11-17 08:40:24 +13:00
Dirk Hohndel
beb352d47c Ubuntu: update supported versions
Drop 23.10 / Mantic
Add  24.10 / Oracular

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2024-11-11 14:22:28 +13:00
Dirk Hohndel
e7900c514c export-html: prevent invalid json
A dive without events could lead to json with extra closing brackets that
prevents browsers from rendering the dive log.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2024-11-05 19:17:12 +01:00
dependabot[bot]
8e9010a000 build(deps): bump com.github.mik3y:usb-serial-for-android
Bumps [com.github.mik3y:usb-serial-for-android](https://github.com/mik3y/usb-serial-for-android) from v3.8.0 to 3.8.1.
- [Release notes](https://github.com/mik3y/usb-serial-for-android/releases)
- [Changelog](https://github.com/mik3y/usb-serial-for-android/blob/master/CHANGELOG.txt)
- [Commits](https://github.com/mik3y/usb-serial-for-android/compare/v3.8.0...v3.8.1)

---
updated-dependencies:
- dependency-name: com.github.mik3y:usb-serial-for-android
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-04 15:59:52 +13:00
5 changed files with 31 additions and 48 deletions

View file

@ -28,7 +28,7 @@ apply plugin: 'com.android.application'
dependencies { dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar']) implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.github.mik3y:usb-serial-for-android:v3.8.0' implementation 'com.github.mik3y:usb-serial-for-android:3.8.1'
implementation 'com.android.support:support-v4:28.0.0' implementation 'com.android.support:support-v4:28.0.0'
} }

View file

@ -92,7 +92,8 @@ static void write_dive_status(struct membuffer *b, const struct dive &dive)
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\":["; const char *separator = "";
put_string(b, "\"events\":[");
for (const auto &ev: dive.dcs[0].events) { for (const auto &ev: dive.dcs[0].events) {
put_string(b, separator); put_string(b, separator);
separator = ", "; separator = ", ";

View file

@ -105,7 +105,7 @@ debuild -S -d
# create builds for the newer Ubuntu releases that Launchpad supports # create builds for the newer Ubuntu releases that Launchpad supports
# #
rel=focal rel=focal
others="jammy mantic noble" others="jammy noble oracular"
for next in $others for next in $others
do do
sed -i "s/${rel}/${next}/g" debian/changelog sed -i "s/${rel}/${next}/g" debian/changelog

View file

@ -1118,38 +1118,25 @@ void DivePlannerPointsModel::updateDiveProfile()
if (diveplan.is_empty()) if (diveplan.is_empty())
return; return;
// For calculating variations, we need a copy of the plan. We have to copy _before_
// calling plan(), because that adds deco stops.
bool computeVariations = isPlanner() && shouldComputeVariations();
struct diveplan plan_copy;
if (computeVariations)
plan_copy = diveplan;
deco_state_cache cache; deco_state_cache cache;
struct deco_state plan_deco_state; struct deco_state plan_deco_state;
plan(&plan_deco_state, diveplan, d, dcNr, decotimestep, cache, isPlanner(), false); plan(&plan_deco_state, diveplan, d, dcNr, decotimestep, cache, isPlanner(), false);
updateMaxDepth(); updateMaxDepth();
if (isPlanner() && shouldComputeVariations()) { if (computeVariations) {
auto plan_copy = std::make_unique<struct diveplan>();
lock_planner();
*plan_copy = diveplan;
unlock_planner();
#ifdef VARIATIONS_IN_BACKGROUND #ifdef VARIATIONS_IN_BACKGROUND
// Since we're calling computeVariations asynchronously and plan_deco_state is allocated QtConcurrent::run([this, plan = std::move(plan_copy), deco = plan_deco_state] ()
// on the stack, it must be copied and freed by the worker-thread. { this->computeVariations(std::move(plan), deco); });
auto deco_copy = std::make_unique<deco_state>(plan_deco_state);
// Ideally, we would pass the unique_ptrs to the lambda for QtConcurrent::run().
// This, in principle, can be done as such:
// [ptr = std::move(ptr)] () mutable { f(std::move(ptr)) };
// However, this make the lambda uncopyable and QtConcurrent::run() sadly
// uses copy semantics.
// So let's be pragmatic and do a release/reaquire pair.
// Somewhat disappointing, but what do you want to do?
// Note 1: this is now not exception safe, but Qt doesn't support
// exceptions anyway.
// Note 2: We also can't use the function / argument syntax of QtConcurrent::run(),
// because it likewise uses copy-semantics. How annoying.
QtConcurrent::run([this, plan = plan_copy.release(), deco = deco_copy.release()] ()
{ this->computeVariationsFreeDeco(std::unique_ptr<struct diveplan>(plan),
std::unique_ptr<deco_state>(deco)); });
#else #else
computeVariations(std::move(plan_copy), &plan_deco_state); computeVariations(std::move(plan_copy), plan_deco_state);
#endif #endif
final_deco_state = plan_deco_state; final_deco_state = plan_deco_state;
} }
@ -1194,12 +1181,6 @@ int DivePlannerPointsModel::analyzeVariations(const std::vector<decostop> &min,
return (leftsum + rightsum) / 2; return (leftsum + rightsum) / 2;
} }
void DivePlannerPointsModel::computeVariationsFreeDeco(std::unique_ptr<struct diveplan> original_plan, std::unique_ptr<struct deco_state> previous_ds)
{
computeVariations(std::move(original_plan), previous_ds.get());
// Note: previous ds automatically free()d by virtue of being a unique_ptr.
}
// Return reference to second to last element. // Return reference to second to last element.
// Caller is responsible for checking that there are at least two elements. // Caller is responsible for checking that there are at least two elements.
template <typename T> template <typename T>
@ -1208,17 +1189,16 @@ auto &second_to_last(T &v)
return *std::prev(std::prev(v.end())); return *std::prev(std::prev(v.end()));
} }
void DivePlannerPointsModel::computeVariations(std::unique_ptr<struct diveplan> original_plan, const struct deco_state *previous_ds) void DivePlannerPointsModel::computeVariations(struct diveplan original_plan, struct deco_state ds)
{ {
// nothing to do unless there's an original plan // nothing to do unless there's an original plan
if (!original_plan) if (original_plan.dp.empty())
return; return;
auto dive = std::make_unique<struct dive>(); auto dive = std::make_unique<struct dive>();
copy_dive(d, dive.get()); copy_dive(d, dive.get());
deco_state_cache cache, save; deco_state_cache cache, save;
struct diveplan plan_copy; struct diveplan plan_copy;
struct deco_state ds = *previous_ds;
int my_instance = ++instanceCounter; int my_instance = ++instanceCounter;
save.cache(&ds); save.cache(&ds);
@ -1236,7 +1216,7 @@ void DivePlannerPointsModel::computeVariations(std::unique_ptr<struct diveplan>
depth_units = tr("ft"); depth_units = tr("ft");
} }
plan_copy = *original_plan; plan_copy = original_plan;
if (plan_copy.dp.size() < 2) if (plan_copy.dp.size() < 2)
return; return;
if (my_instance != instanceCounter) if (my_instance != instanceCounter)
@ -1244,7 +1224,7 @@ void DivePlannerPointsModel::computeVariations(std::unique_ptr<struct diveplan>
auto original = plan(&ds, plan_copy, dive.get(), dcNr, 1, cache, true, false); auto original = plan(&ds, plan_copy, dive.get(), dcNr, 1, cache, true, false);
save.restore(&ds, false); save.restore(&ds, false);
plan_copy = *original_plan; plan_copy = original_plan;
second_to_last(plan_copy.dp).depth.mm += delta_depth.mm; second_to_last(plan_copy.dp).depth.mm += delta_depth.mm;
plan_copy.dp.back().depth.mm += delta_depth.mm; plan_copy.dp.back().depth.mm += delta_depth.mm;
if (my_instance != instanceCounter) if (my_instance != instanceCounter)
@ -1252,6 +1232,7 @@ void DivePlannerPointsModel::computeVariations(std::unique_ptr<struct diveplan>
auto deeper = plan(&ds, plan_copy, dive.get(), dcNr, 1, cache, true, false); auto deeper = plan(&ds, plan_copy, dive.get(), dcNr, 1, cache, true, false);
save.restore(&ds, false); save.restore(&ds, false);
plan_copy = original_plan;
second_to_last(plan_copy.dp).depth.mm -= delta_depth.mm; second_to_last(plan_copy.dp).depth.mm -= delta_depth.mm;
plan_copy.dp.back().depth.mm -= delta_depth.mm; plan_copy.dp.back().depth.mm -= delta_depth.mm;
if (my_instance != instanceCounter) if (my_instance != instanceCounter)
@ -1259,13 +1240,14 @@ void DivePlannerPointsModel::computeVariations(std::unique_ptr<struct diveplan>
auto shallower = plan(&ds, plan_copy, dive.get(), dcNr, 1, cache, true, false); auto shallower = plan(&ds, plan_copy, dive.get(), dcNr, 1, cache, true, false);
save.restore(&ds, false); save.restore(&ds, false);
plan_copy = *original_plan; plan_copy = original_plan;
plan_copy.dp.back().time += delta_time.seconds; plan_copy.dp.back().time += delta_time.seconds;
if (my_instance != instanceCounter) if (my_instance != instanceCounter)
return; return;
auto longer = plan(&ds, plan_copy, dive.get(), dcNr, 1, cache, true, false); auto longer = plan(&ds, plan_copy, dive.get(), dcNr, 1, cache, true, false);
save.restore(&ds, false); save.restore(&ds, false);
plan_copy = original_plan;
plan_copy.dp.back().time -= delta_time.seconds; plan_copy.dp.back().time -= delta_time.seconds;
if (my_instance != instanceCounter) if (my_instance != instanceCounter)
return; return;
@ -1308,15 +1290,16 @@ void DivePlannerPointsModel::createPlan(bool saveAsNew)
removeDeco(); removeDeco();
createTemporaryPlan(); createTemporaryPlan();
// For calculating variations, we need a copy of the plan. We have to copy _before_
// calling plan(), because that adds deco stops.
struct diveplan plan_copy;
if (shouldComputeVariations())
plan_copy = diveplan;
plan(&ds_after_previous_dives, diveplan, d, dcNr, decotimestep, cache, isPlanner(), true); plan(&ds_after_previous_dives, diveplan, d, dcNr, decotimestep, cache, isPlanner(), true);
if (shouldComputeVariations()) { if (shouldComputeVariations())
auto plan_copy = std::make_unique<struct diveplan>(); computeVariations(std::move(plan_copy), ds_after_previous_dives);
lock_planner();
*plan_copy = diveplan;
unlock_planner();
computeVariations(std::move(plan_copy), &ds_after_previous_dives);
}
// Fixup planner notes. // Fixup planner notes.
if (current_dive && d->id == current_dive->id) { if (current_dive && d->id == current_dive->id) {

View file

@ -131,8 +131,7 @@ private:
void createTemporaryPlan(); void createTemporaryPlan();
struct diveplan diveplan; struct diveplan diveplan;
void computeVariationsDone(QString text); void computeVariationsDone(QString text);
void computeVariations(std::unique_ptr<struct diveplan> plan, const struct deco_state *ds); void computeVariations(struct diveplan plan, struct deco_state ds); // Note: works on copies of plan and ds
void computeVariationsFreeDeco(std::unique_ptr<struct diveplan> plan, std::unique_ptr<struct deco_state> ds);
int analyzeVariations(const std::vector<decostop> &min, const std::vector<decostop> &mid, const std::vector<decostop> &max, const char *unit); int analyzeVariations(const std::vector<decostop> &min, const std::vector<decostop> &mid, const std::vector<decostop> &max, const char *unit);
struct dive *d; struct dive *d;
int dcNr; int dcNr;