50 LOG_DBG(
"Skipping empty call from '{}' to '{}'", m.
from(), m.
to());
63 const auto &f =
dynamic_cast<const model::method &
>(to.value());
64 const std::string_view style = f.
is_static() ?
"__" :
"";
66 if (m.
type() == message_t::kCoAwait)
67 message = fmt::format(
"{}<< co_await >>\\n{}{}", style,
68 f.message_name(render_mode), style);
71 "{}{}{}", style, f.message_name(render_mode), style);
73 else if (to.value().
type_name() ==
"objc_method") {
75 const std::string_view style = f.
is_static() ?
"__" :
"";
77 fmt::format(
"{}{}{}", style, f.message_name(render_mode), style);
79 else if (
config().combine_free_functions_into_file_participants()) {
80 if (to.value().
type_name() ==
"function") {
84 if (f.is_cuda_kernel())
86 else if (f.is_cuda_device())
88 else if (f.is_coroutine())
91 else if (to.value().
type_name() ==
"function_template") {
95 if (f.is_cuda_kernel())
97 else if (f.is_cuda_device())
99 else if (f.is_coroutine())
113 ostr << from_alias <<
" "
118 if (
config().generate_links) {
146 std::string message_stereotype;
147 if (m.
type() == message_t::kCoReturn) {
148 message_stereotype =
"<< co_return >>";
150 else if (m.
type() == message_t::kCoYield) {
151 message_stereotype =
"<< co_yield >>";
154 std::string message_label;
158 if (to.has_value() && from.has_value() && !from.value().
is_void()) {
163 ostr << from_alias <<
" "
167 if (
config().generate_return_types())
169 else if (
config().generate_return_values())
172 else if (from.has_value() && !from.value().is_void() &&
173 (from.value().type_name() ==
"method" ||
174 from.value().type_name() ==
"objc_method" ||
175 config().combine_free_functions_into_file_participants())) {
178 ostr <<
"[<--" <<
" " << from_alias;
179 if (
config().generate_return_types())
181 else if (
config().generate_return_values())
185 if (!message_stereotype.empty()) {
186 if (message_label.empty())
187 message_label = fmt::format(
"//{}//", message_stereotype);
189 message_label = fmt::format(
190 "//{}//\\n//{}//", message_stereotype, message_label);
193 if (!message_label.empty())
194 message_label = fmt::format(
"//{}//", message_label);
197 if (!message_label.empty())
198 ostr <<
" : " << message_label;
204 eid_t activity_id, std::ostream &ostr, std::vector<eid_t> &visited)
const
206 const auto &a =
model().get_activity(activity_id);
210 if (
config().fold_repeated_activities() && !inserted &&
211 !a.messages().empty()) {
225 for (
const auto &m : a.messages()) {
226 if (m.in_static_declaration_context()) {
233 if (m.type() == message_t::kCall || m.type() == message_t::kCoAwait) {
237 if (!to.has_value()) {
238 LOG_DBG(
"Skipping activity {} due to missing target paricipant "
244 visited.push_back(m.from());
246 LOG_DBG(
"Generating message [{}] --> [{}]", m.from(), m.to());
252 ostr <<
"activate " << to_alias <<
'\n';
254 if (
model().sequences().find(m.to()) !=
model().sequences().end()) {
255 if (std::find(visited.begin(), visited.end(), m.to()) ==
259 LOG_DBG(
"Generating activity {} (called from {})", m.to(),
266 LOG_DBG(
"Skipping activity {} --> {} - missing sequence {}",
267 m.from(), m.to(), m.to());
269 ostr <<
"deactivate " << to_alias <<
'\n';
273 else if (m.type() == message_t::kReturn) {
276 auto return_message = m;
277 if (!visited.empty()) {
278 return_message.set_to(visited.back());
282 else if (m.type() == message_t::kCoReturn) {
285 auto return_message = m;
286 if (!visited.empty()) {
287 return_message.set_to(visited.back());
291 else if (m.type() == message_t::kCoYield) {
294 auto return_message = m;
295 if (!visited.empty()) {
296 return_message.set_to(visited.back());
300 else if (m.type() == message_t::kIf) {
304 if (
const auto &text = m.condition_text(); text.has_value())
305 ostr <<
" " << text.value();
308 else if (m.type() == message_t::kElseIf) {
311 if (
const auto &text = m.condition_text(); text.has_value())
312 ostr <<
" " << text.value();
315 else if (m.type() == message_t::kElse) {
319 else if (m.type() == message_t::kIfEnd) {
322 else if (m.type() == message_t::kWhile) {
326 if (
const auto &text = m.condition_text(); text.has_value())
327 ostr <<
" " << text.value();
330 else if (m.type() == message_t::kWhileEnd) {
333 else if (m.type() == message_t::kFor) {
337 if (
const auto &text = m.condition_text(); text.has_value())
338 ostr <<
" " << text.value();
341 else if (m.type() == message_t::kForEnd) {
344 else if (m.type() == message_t::kDo) {
348 if (
const auto &text = m.condition_text(); text.has_value())
349 ostr <<
" " << text.value();
352 else if (m.type() == message_t::kDoEnd) {
355 else if (m.type() == message_t::kTry) {
358 ostr <<
"group try\n";
360 else if (m.type() == message_t::kCatch) {
364 else if (m.type() == message_t::kTryEnd) {
368 else if (m.type() == message_t::kSwitch) {
371 ostr <<
"group switch\n";
373 else if (m.type() == message_t::kCase) {
377 else if (m.type() == message_t::kSwitchEnd) {
380 else if (m.type() == message_t::kConditional) {
384 if (
const auto &text = m.condition_text(); text.has_value())
385 ostr <<
" " << text.value();
388 else if (m.type() == message_t::kConditionalElse) {
392 else if (m.type() == message_t::kConditionalEnd) {
406 bool comment_generated_from_note_decorators{
false};
407 for (
const auto &decorator : m.
decorators()) {
408 auto note = std::dynamic_pointer_cast<decorators::note>(decorator);
409 if (note && note->applies_to_diagram(
config().name)) {
410 comment_generated_from_note_decorators =
true;
415 note->text,
config().message_comment_width())
418 ostr <<
"end note" <<
'\n';
422 if (comment_generated_from_note_decorators)
425 if (!
config().generate_message_comments())
429 if (
const auto &comment = m.
comment(); comment &&
435 config().message_comment_width())
438 ostr <<
"end note" <<
'\n';
443 std::ostream &ostr,
const std::string &name)
const
445 auto p =
model().get(name);
447 if (!p.has_value()) {
448 LOG_WARN(
"Cannot find participant {} from `participants_order` "
458 std::ostream &ostr,
eid_t id,
bool force)
const
460 eid_t participant_id{};
463 for (
const auto pid :
model().active_participants()) {
465 participant_id = pid;
473 if (participant_id == 0)
479 const auto &participant =
482 if (participant.type_name() ==
"method") {
483 const auto class_id =
492 const auto &class_participant =
497 auto participant_name =
config().simplify_template_type(
500 config().using_namespace().relative(participant_name);
504 ostr <<
"participant \"" << participant_name <<
"\" as "
505 << class_participant.alias();
507 if (
config().generate_links) {
509 ostr, class_participant);
516 else if (participant.type_name() ==
"objc_method") {
517 const auto class_id =
526 const auto &class_participant =
531 auto participant_name =
config().simplify_template_type(
534 config().using_namespace().relative(participant_name);
538 ostr <<
"participant \"" << participant_name <<
"\" as "
539 << class_participant.alias() <<
" <<ObjC Interface>>";
541 if (
config().generate_links) {
543 ostr, class_participant);
550 else if ((participant.type_name() ==
"function" ||
551 participant.type_name() ==
"function_template") &&
552 config().combine_free_functions_into_file_participants()) {
555 const auto &file_path =
561 assert(!file_path.empty());
569 std::filesystem::path{file_path},
config().root_directory())
572 ostr <<
"participant \"" << participant_name <<
"\" as "
573 << fmt::format(
"C_{:022}", file_id.value());
582 auto participant_name =
583 config().using_namespace().relative(
config().simplify_template_type(
587 ostr <<
"participant \"" << participant_name <<
"\" as "
588 << participant.alias();
590 if (
const auto *function_ptr =
593 if (function_ptr->is_cuda_kernel())
594 ostr <<
" << CUDA Kernel >>";
595 else if (function_ptr->is_cuda_device())
596 ostr <<
" << CUDA Device >>";
597 else if (function_ptr->is_coroutine())
598 ostr << fmt::format(
"<< Coroutine >>");
601 if (
config().generate_links) {
622 if ((participant.
type_name() ==
"function" ||
623 participant.
type_name() ==
"function_template") &&
624 config().combine_free_functions_into_file_participants()) {
627 return fmt::format(
"C_{:022}", file_id.value());
630 return participant.
alias();
637 if (
config().participants_order.has_value) {
638 for (
const auto &p :
config().participants_order()) {
639 LOG_DBG(
"Pregenerating participant {}", p);
656 std::vector<eid_t> visited_participants;
658 for (
const auto from_id : start_from) {
659 if (
model().participants().count(from_id) == 0)
664 if (!from.has_value()) {
665 LOG_WARN(
"Failed to find participant {} for 'from' "
681 if (from.value().type_name() ==
"method" ||
682 from.value().type_name() ==
"objc_method" ||
683 config().combine_free_functions_into_file_participants()) {
684 ostr <<
"[->" <<
" " << from_alias <<
" : "
689 ostr <<
"activate " << from_alias <<
'\n';
693 ostr <<
"deactivate " << from_alias <<
'\n';
699 std::vector<eid_t> start_from;
700 for (
const auto &sf :
config().from()) {
701 if (sf.location_type == location_t::function) {
703 for (
const auto &[k, v] :
model().sequences()) {
704 if (
model().participants().count(v.from()) == 0)
707 const auto &caller = *
model().participants().at(v.from());
708 std::string vfrom = caller.full_name(
false);
709 if (sf.location == vfrom) {
710 LOG_DBG(
"Found sequence diagram start point: {}", k);
711 start_from.push_back(k);
717 model().handle_invalid_from_condition(sf);
727 std::vector<model::message_chain_t> result;
729 for (
const auto &to_location :
config().to()) {
730 auto to_activity_ids =
model().get_to_activity_ids(to_location);
732 if (to_activity_ids.empty()) {
733 model().handle_invalid_to_condition(to_location);
736 for (
const auto &to_activity_id : to_activity_ids) {
737 std::vector<model::message_chain_t> message_chains_unique =
738 model().get_all_from_to_message_chains(
eid_t{}, to_activity_id);
740 result.insert(result.end(), message_chains_unique.begin(),
741 message_chains_unique.end());
755 std::vector<model::message_chain_t> message_chains =
758 bool first_separator_skipped{
false};
759 for (
const auto &mc : message_chains) {
760 if (!first_separator_skipped)
761 first_separator_skipped =
true;
765 const auto from_activity_id = mc.front().from();
767 if (
model().participants().count(from_activity_id) == 0)
773 if (from.value().type_name() ==
"method" ||
774 from.value().type_name() ==
"objc_method" ||
775 config().combine_free_functions_into_file_participants()) {
783 for (
const auto &m : mc) {
791 for (
const auto &ft :
config().from_to()) {
794 assert(ft.size() == 2);
796 const auto &from_location = ft.front();
797 const auto &to_location = ft.back();
799 const auto from_activity_ids =
800 model().get_from_activity_ids(from_location);
802 const auto to_activity_ids =
model().get_to_activity_ids(to_location);
804 if (from_activity_ids.empty()) {
805 model().handle_invalid_from_condition(from_location);
808 if (from_activity_ids.empty() || to_activity_ids.empty()) {
809 model().handle_invalid_to_condition(to_location);
812 bool first_separator_skipped{
false};
814 for (
const auto from_activity_id : from_activity_ids) {
815 if (
model().participants().count(from_activity_id) == 0)
818 for (
const auto to_activity_id : to_activity_ids) {
819 if (
model().participants().count(to_activity_id) == 0)
822 auto message_chains_unique =
823 model().get_all_from_to_message_chains(
824 from_activity_id, to_activity_id);
826 for (
const auto &mc : message_chains_unique) {
827 if (!first_separator_skipped)
828 first_separator_skipped =
true;
835 if (from.value().type_name() ==
"method" ||
836 from.value().type_name() ==
"objc_method" ||
838 .combine_free_functions_into_file_participants()) {
847 for (
const auto &m : mc) {
859 if (
config().generate_method_arguments() ==