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() ==