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,
MTPReplyMarkup());
auto failHandler = std::make_shared<Fn<void(const RPCError&, QByteArray)>>();
auto performRequest = [=] {
auto performRequest = [=](const auto &repeatRequest) -> void {
auto &histories = history->owner().histories();
const auto requestType = Data::Histories::RequestType::Send;
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
@ -149,28 +148,25 @@ void SendExistingMedia(
api->applyUpdates(result, randomId);
finish();
}).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();
}).afterRequest(history->sendRequestId
).send();
return history->sendRequestId;
});
};
*failHandler = [=](const RPCError &error, QByteArray usedFileReference) {
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();
performRequest(performRequest);
api->finishForwarding(message.action);
}

View File

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

View File

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

View File

@ -853,56 +853,20 @@ void EditScans::ChooseScan(
Fn<void(ReadScanError)> errorCallback) {
Expects(parent != nullptr);
const auto processFiles = std::make_shared<Fn<void(QStringList&&)>>();
const auto filter = FileDialog::AllFilesFilter()
+ qsl(";;Image files (*")
+ cImgExtensions().join(qsl(" *"))
+ qsl(")");
const auto guardedCallback = crl::guard(parent, doneCallback);
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) {
crl::on_main([=] {
guardedError(error);
});
};
const auto processImage = [=](
QByteArray &&content,
QStringList &&remainingFiles) {
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) {
const auto processFiles = [=](
QStringList &&files,
const auto &handleImage) -> void {
while (!files.isEmpty()) {
auto file = files.front();
files.removeAt(0);
@ -919,11 +883,49 @@ void EditScans::ChooseScan(
return f.readAll();
}();
if (!content.isEmpty()) {
processImage(std::move(content), std::move(files));
handleImage(
std::move(content),
std::move(files),
handleImage);
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)
|| (type == FileType::Translation);
(allowMany ? FileDialog::GetOpenPaths : FileDialog::GetOpenPath)(

View File

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