Fix a memory leak using a recursive lambda.

This commit is contained in:
John Preston 2020-07-06 15:51:58 +04:00
parent 900f7e1304
commit 52e780b065
5 changed files with 70 additions and 73 deletions

View file

@ -129,8 +129,7 @@ void SendExistingMedia(
caption, caption,
MTPReplyMarkup()); MTPReplyMarkup());
auto failHandler = std::make_shared<Fn<void(const RPCError&, QByteArray)>>(); auto performRequest = [=](const auto &repeatRequest) -> void {
auto performRequest = [=] {
auto &histories = history->owner().histories(); auto &histories = history->owner().histories();
const auto requestType = Data::Histories::RequestType::Send; const auto requestType = Data::Histories::RequestType::Send;
histories.sendRequest(history, requestType, [=](Fn<void()> finish) { histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
@ -149,28 +148,25 @@ void SendExistingMedia(
api->applyUpdates(result, randomId); api->applyUpdates(result, randomId);
finish(); finish();
}).fail([=](const RPCError &error) { }).fail([=](const RPCError &error) {
(*failHandler)(error, usedFileReference); if (error.code() == 400
&& error.type().startsWith(qstr("FILE_REFERENCE_"))) {
api->refreshFileReference(origin, [=](const auto &result) {
if (media->fileReference() != usedFileReference) {
repeatRequest(repeatRequest);
} else {
api->sendMessageFail(error, peer, randomId, newId);
}
});
} else {
api->sendMessageFail(error, peer, randomId, newId);
}
finish(); finish();
}).afterRequest(history->sendRequestId }).afterRequest(history->sendRequestId
).send(); ).send();
return history->sendRequestId; return history->sendRequestId;
}); });
}; };
*failHandler = [=](const RPCError &error, QByteArray usedFileReference) { performRequest(performRequest);
if (error.code() == 400
&& error.type().startsWith(qstr("FILE_REFERENCE_"))) {
api->refreshFileReference(origin, [=](const auto &result) {
if (media->fileReference() != usedFileReference) {
performRequest();
} else {
api->sendMessageFail(error, peer, randomId, newId);
}
});
} else {
api->sendMessageFail(error, peer, randomId, newId);
}
};
performRequest();
api->finishForwarding(message.action); api->finishForwarding(message.action);
} }

View file

@ -604,7 +604,7 @@ bool CanScheduleUntilOnline(not_null<PeerData*> peer) {
void ScheduleBox( void ScheduleBox(
not_null<Ui::GenericBox*> box, not_null<Ui::GenericBox*> box,
SendMenuType type, SendMenuType type,
FnMut<void(Api::SendOptions)> done, Fn<void(Api::SendOptions)> done,
TimeId time) { TimeId time) {
box->setTitle((type == SendMenuType::Reminder) box->setTitle((type == SendMenuType::Reminder)
? tr::lng_remind_title() ? tr::lng_remind_title()
@ -697,8 +697,6 @@ void ScheduleBox(
}), (*calendar)->lifetime()); }), (*calendar)->lifetime());
}); });
const auto shared = std::make_shared<FnMut<void(Api::SendOptions)>>(
std::move(done));
const auto collect = [=] { const auto collect = [=] {
const auto timeValue = timeInput->valueCurrent().split(':'); const auto timeValue = timeInput->valueCurrent().split(':');
if (timeValue.size() != 2) { if (timeValue.size() != 2) {
@ -731,9 +729,9 @@ void ScheduleBox(
return; return;
} }
auto copy = shared; auto copy = done;
box->closeBox(); box->closeBox();
(*copy)(result); copy(result);
}; };
timeInput->submitRequests( timeInput->submitRequests(
) | rpl::start_with_next([=] { ) | rpl::start_with_next([=] {

View file

@ -22,7 +22,7 @@ namespace HistoryView {
void ScheduleBox( void ScheduleBox(
not_null<Ui::GenericBox*> box, not_null<Ui::GenericBox*> box,
SendMenuType type, SendMenuType type,
FnMut<void(Api::SendOptions)> done, Fn<void(Api::SendOptions)> done,
TimeId time); TimeId time);
template <typename Guard, typename Submit> template <typename Guard, typename Submit>

View file

@ -853,56 +853,20 @@ void EditScans::ChooseScan(
Fn<void(ReadScanError)> errorCallback) { Fn<void(ReadScanError)> errorCallback) {
Expects(parent != nullptr); Expects(parent != nullptr);
const auto processFiles = std::make_shared<Fn<void(QStringList&&)>>();
const auto filter = FileDialog::AllFilesFilter() const auto filter = FileDialog::AllFilesFilter()
+ qsl(";;Image files (*") + qsl(";;Image files (*")
+ cImgExtensions().join(qsl(" *")) + cImgExtensions().join(qsl(" *"))
+ qsl(")"); + qsl(")");
const auto guardedCallback = crl::guard(parent, doneCallback); const auto guardedCallback = crl::guard(parent, doneCallback);
const auto guardedError = crl::guard(parent, errorCallback); const auto guardedError = crl::guard(parent, errorCallback);
const auto onMainCallback = [=](
QByteArray &&content,
QStringList &&remainingFiles) {
crl::on_main([
=,
bytes = std::move(content),
remainingFiles = std::move(remainingFiles)
]() mutable {
guardedCallback(std::move(bytes));
(*processFiles)(std::move(remainingFiles));
});
};
const auto onMainError = [=](ReadScanError error) { const auto onMainError = [=](ReadScanError error) {
crl::on_main([=] { crl::on_main([=] {
guardedError(error); guardedError(error);
}); });
}; };
const auto processImage = [=]( const auto processFiles = [=](
QByteArray &&content, QStringList &&files,
QStringList &&remainingFiles) { const auto &handleImage) -> void {
crl::async([
=,
bytes = std::move(content),
remainingFiles = std::move(remainingFiles)
]() mutable {
auto result = ProcessImage(std::move(bytes));
if (const auto error = base::get_if<ReadScanError>(&result)) {
onMainError(*error);
} else {
auto content = base::get_if<QByteArray>(&result);
Assert(content != nullptr);
onMainCallback(std::move(*content), std::move(remainingFiles));
}
});
};
const auto processOpened = [=](FileDialog::OpenResult &&result) {
if (result.paths.size() > 0) {
(*processFiles)(std::move(result.paths));
} else if (!result.remoteContent.isEmpty()) {
processImage(std::move(result.remoteContent), {});
}
};
*processFiles = [=](QStringList &&files) {
while (!files.isEmpty()) { while (!files.isEmpty()) {
auto file = files.front(); auto file = files.front();
files.removeAt(0); files.removeAt(0);
@ -919,11 +883,49 @@ void EditScans::ChooseScan(
return f.readAll(); return f.readAll();
}(); }();
if (!content.isEmpty()) { if (!content.isEmpty()) {
processImage(std::move(content), std::move(files)); handleImage(
std::move(content),
std::move(files),
handleImage);
return; return;
} }
} }
}; };
const auto processImage = [=](
QByteArray &&content,
QStringList &&remainingFiles,
const auto &repeatProcessImage) -> void {
crl::async([
=,
bytes = std::move(content),
remainingFiles = std::move(remainingFiles)
]() mutable {
auto result = ProcessImage(std::move(bytes));
if (const auto error = base::get_if<ReadScanError>(&result)) {
onMainError(*error);
} else {
auto content = base::get_if<QByteArray>(&result);
Assert(content != nullptr);
crl::on_main([
=,
bytes = std::move(*content),
remainingFiles = std::move(remainingFiles)
]() mutable {
guardedCallback(std::move(bytes));
processFiles(
std::move(remainingFiles),
repeatProcessImage);
});
}
});
};
const auto processOpened = [=](FileDialog::OpenResult &&result) {
if (result.paths.size() > 0) {
processFiles(std::move(result.paths), processImage);
} else if (!result.remoteContent.isEmpty()) {
processImage(std::move(result.remoteContent), {}, processImage);
}
};
const auto allowMany = (type == FileType::Scan) const auto allowMany = (type == FileType::Scan)
|| (type == FileType::Translation); || (type == FileType::Translation);
(allowMany ? FileDialog::GetOpenPaths : FileDialog::GetOpenPath)( (allowMany ? FileDialog::GetOpenPaths : FileDialog::GetOpenPath)(

View file

@ -209,10 +209,11 @@ void SetupInterfaceScale(
} }
return (result == ScaleValues.size()) ? (result - 1) : result; return (result == ScaleValues.size()) ? (result - 1) : result;
}; };
const auto inSetScale = Ui::CreateChild<bool>(container.get()); const auto inSetScale = container->lifetime().make_state<bool>();
const auto setScale = std::make_shared<Fn<void(int)>>(); const auto setScale = [=](int scale, const auto &repeatSetScale) -> void {
*setScale = [=](int scale) { if (*inSetScale) {
if (*inSetScale) return; return;
}
*inSetScale = true; *inSetScale = true;
const auto guard = gsl::finally([=] { *inSetScale = false; }); const auto guard = gsl::finally([=] { *inSetScale = false; });
@ -228,7 +229,7 @@ void SetupInterfaceScale(
base::call_delayed( base::call_delayed(
st::defaultSettingsSlider.duration, st::defaultSettingsSlider.duration,
button, button,
[=] { (*setScale)(cConfigScale()); }); [=] { repeatSetScale(cConfigScale(), repeatSetScale); });
}); });
Ui::show(Box<ConfirmBox>( Ui::show(Box<ConfirmBox>(
tr::lng_settings_need_restart(tr::now), tr::lng_settings_need_restart(tr::now),
@ -256,16 +257,16 @@ void SetupInterfaceScale(
) | rpl::map([=](int section) { ) | rpl::map([=](int section) {
return scaleByIndex(section); return scaleByIndex(section);
}) | rpl::start_with_next([=](int scale) { }) | rpl::start_with_next([=](int scale) {
(*setScale)((scale == cScreenScale()) setScale(
? style::kScaleAuto (scale == cScreenScale()) ? style::kScaleAuto : scale,
: scale); setScale);
}, slider->lifetime()); }, slider->lifetime());
button->toggledValue( button->toggledValue(
) | rpl::map([](bool checked) { ) | rpl::map([](bool checked) {
return checked ? style::kScaleAuto : cEvalScale(cConfigScale()); return checked ? style::kScaleAuto : cEvalScale(cConfigScale());
}) | rpl::start_with_next([=](int scale) { }) | rpl::start_with_next([=](int scale) {
(*setScale)(scale); setScale(scale, setScale);
}, button->lifetime()); }, button->lifetime());
} }