Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-04-27 08:49:02

0001 // Copyright 2024 Christophe Henry
0002 // henry UNDERSCORE christophe AT hotmail DOT com
0003 // This is an extended version of the state machine available in the boost::mpl library
0004 // Distributed under the same license as the original.
0005 // Copyright for the original version:
0006 // Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
0007 // under the Boost Software License, Version 1.0. (See accompanying
0008 // file LICENSE_1_0.txt or copy at
0009 // http://www.boost.org/LICENSE_1_0.txt)
0010 
0011 #ifndef BOOST_MSM_FRONT_PUML_COMMON_H
0012 #define BOOST_MSM_FRONT_PUML_COMMON_H
0013 
0014 #include <cstdint>
0015 #include <string>
0016 #include <string_view>
0017 #include <vector>
0018 #include <boost/any.hpp>
0019 #include <boost/fusion/mpl.hpp>
0020 #include <boost/fusion/include/as_vector.hpp>
0021 #include <boost/fusion/container/vector.hpp>
0022 #include <boost/fusion/include/insert_range.hpp>
0023 #include <boost/fusion/include/at_c.hpp>
0024 #include <boost/fusion/include/for_each.hpp>
0025 #include <boost/fusion/include/make_vector.hpp>
0026 
0027 #include <boost/mpl/size.hpp>
0028 
0029 #include <boost/msm/front/states.hpp>
0030 // functors
0031 #include <boost/msm/front/functor_row.hpp>
0032 #include <boost/msm/front/operator.hpp>
0033 
0034 namespace boost::msm::front::puml
0035 {
0036 namespace detail {
0037     template <class T1, class T2>
0038     struct pair_type
0039     {
0040         using first = T1;
0041         using second = T2;
0042     };
0043 }
0044 
0045     template<typename T>
0046     struct convert_to_msm_names
0047     {
0048         using type = T;
0049     };
0050 
0051 
0052     template <std::uint32_t hash, 
0053               class Flags = boost::fusion::vector0<>,
0054               class Entries = boost::fusion::vector0<>,
0055               class Exits = boost::fusion::vector0<>>
0056     struct State 
0057     {
0058         using generated_type = State<hash>;
0059         using flag_list = boost::fusion::vector0<>;
0060         using entries = Entries;
0061         using exits = Exits;
0062         using internal_flag_list = Flags;
0063 
0064         template <class Event, class FSM>
0065         void on_entry(Event& evt, FSM& fsm) 
0066         {
0067             boost::fusion::for_each(Entries{}, 
0068                 [&](auto action_guard_pair) 
0069                 {
0070                     if constexpr (
0071                         std::is_same_v<typename decltype(action_guard_pair)::second,boost::msm::front::none>)
0072                     {
0073                         typename decltype(action_guard_pair)::first{}(evt, fsm, *this, *this);
0074                     }
0075                     else
0076                     {
0077                         if (typename decltype(action_guard_pair)::second{}(evt, fsm, *this, *this))
0078                         {
0079                             typename decltype(action_guard_pair)::first{}(evt, fsm, *this, *this);
0080                         }
0081                     }
0082                 });
0083         }
0084         template <class Event, class FSM>
0085         void on_exit(Event& evt, FSM& fsm) 
0086         {
0087             boost::fusion::for_each(Exits{},
0088                 [&](auto action_guard_pair)
0089                 {
0090                     if constexpr (
0091                         std::is_same_v<typename decltype(action_guard_pair)::second, boost::msm::front::none>)
0092                     {
0093                         typename decltype(action_guard_pair)::first{}(evt, fsm, *this, *this);
0094                     }
0095                     else
0096                     {
0097                         if (typename decltype(action_guard_pair)::second{}(evt, fsm, *this, *this))
0098                         {
0099                             typename decltype(action_guard_pair)::first{}(evt, fsm, *this, *this);
0100                         }
0101                     }
0102                 });
0103         }
0104         // typedefs added for front::state compatibility
0105         typedef ::boost::mpl::vector<>  internal_transition_table;
0106         typedef ::boost::fusion::vector<>  internal_transition_table11;
0107         typedef ::boost::fusion::vector<>  transition_table;
0108         typedef ::boost::fusion::vector0<>       deferred_events;
0109 
0110     };
0111     template <std::uint32_t hash>
0112     struct Event
0113     {
0114 
0115     };
0116     template <std::uint32_t hash>
0117     struct Action
0118     {
0119 
0120     };
0121     template <std::uint32_t hash>
0122     struct Guard
0123     {
0124 
0125     };
0126     template <std::uint32_t hash>
0127     struct Flag
0128     {
0129 
0130     };
0131 
0132 
0133     namespace detail {
0134         // CRC32 Table (zlib polynomial)
0135         static constexpr std::uint32_t crc_table[256] =
0136         {
0137             0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
0138             0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
0139             0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
0140             0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
0141             0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
0142             0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
0143             0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
0144             0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
0145             0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
0146             0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
0147             0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
0148             0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
0149             0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
0150             0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
0151             0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
0152             0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
0153             0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
0154             0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
0155             0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
0156             0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
0157             0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
0158             0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
0159             0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
0160             0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
0161             0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
0162             0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
0163             0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
0164             0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
0165             0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
0166             0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
0167             0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
0168             0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
0169             0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
0170             0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
0171             0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
0172             0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
0173             0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
0174             0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
0175             0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
0176             0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
0177             0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
0178             0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
0179             0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
0180             0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
0181             0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
0182             0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
0183             0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
0184             0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
0185             0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
0186             0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
0187             0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
0188             0x2d02ef8dL
0189         };
0190         constexpr std::uint32_t crc32(std::string_view str)
0191         {
0192             std::uint32_t crc = 0xffffffff;
0193             for (auto c : str)
0194                 crc = (crc >> 8) ^ boost::msm::front::puml::detail::crc_table[(crc ^ c) & 0xff];
0195             return crc ^ 0xffffffff;
0196         }
0197 
0198         // removes training spaces or -
0199         constexpr std::string_view cleanup_token(const std::string_view& str)
0200         {
0201             auto first_not_whitespace = str.find_first_not_of("- \t");
0202             auto last_not_whitespace = str.find_last_not_of("- \t");
0203             if (first_not_whitespace != std::string::npos && last_not_whitespace != std::string::npos)
0204             {
0205                 //return std::string(str, first_not_whitespace, last_not_whitespace - first_not_whitespace + 1);
0206                 return str.substr(first_not_whitespace, last_not_whitespace - first_not_whitespace + 1);
0207             }
0208             else
0209             {
0210                 return std::string_view{};
0211             }
0212         }
0213 
0214         struct Transition
0215         {
0216             std::string_view source;
0217             std::string_view target;
0218             std::string_view event;
0219             std::string_view guard;
0220             std::string_view action;
0221         };
0222 
0223         // finds guards [Guard]
0224         // requires all blanks to have been removed
0225         constexpr boost::msm::front::puml::detail::Transition
0226             parse_guards(std::string_view part)
0227         {
0228             boost::msm::front::puml::detail::Transition res;
0229             auto start_pos = part.find("[");
0230             auto end_pos = part.find("]");
0231 
0232             if (start_pos != std::string::npos && end_pos != std::string::npos)
0233             {
0234                 ++start_pos;
0235                 res.guard = boost::msm::front::puml::detail::cleanup_token(part.substr(start_pos, end_pos - start_pos));
0236             }
0237             return res;
0238         }
0239 
0240 
0241         // requires all blanks to have been removed
0242         constexpr boost::msm::front::puml::detail::Transition parse_row_right(std::string_view part)
0243         {
0244             auto action_pos = part.find("/");
0245             auto guard_pos = part.find("[");
0246             auto evt_pos = part.find(":");
0247             auto internal_pos = part.find("-");
0248             bool is_internal_transition =
0249                 internal_pos != std::string::npos && internal_pos > evt_pos && internal_pos <= action_pos && internal_pos <= guard_pos;
0250             auto start_event_name_pos = (internal_pos == std::string::npos) ? evt_pos : internal_pos;
0251 
0252             boost::msm::front::puml::detail::Transition res;
0253 
0254             // target is until : or end of string if not provided
0255             if (evt_pos != std::string::npos && !is_internal_transition)
0256             {
0257                 res.target = boost::msm::front::puml::detail::cleanup_token(part.substr(0, evt_pos));
0258             }
0259             else if (!is_internal_transition)
0260             {
0261                 res.target = boost::msm::front::puml::detail::cleanup_token(part);
0262             }
0263             // event is between : and / or [, whatever comes first
0264             if (action_pos == std::string::npos && guard_pos == std::string::npos)
0265             {
0266                 res.event = boost::msm::front::puml::detail::cleanup_token(part.substr(start_event_name_pos + 1));
0267             }
0268             else
0269             {
0270                 auto length = std::min(action_pos, guard_pos) > 1 + start_event_name_pos ?
0271                     std::min(action_pos, guard_pos) - 1 - start_event_name_pos
0272                     : 0;
0273                 res.event = boost::msm::front::puml::detail::cleanup_token(part.substr(start_event_name_pos + 1, length));
0274             }
0275 
0276             // handle different guard / action cases
0277             if (action_pos != std::string::npos && guard_pos != std::string::npos)
0278             {
0279                 res.action = boost::msm::front::puml::detail::cleanup_token(part.substr(action_pos + 1, guard_pos - 1 - action_pos));
0280             }
0281             else if (action_pos != std::string::npos)
0282             {
0283                 // we have an action => target until /
0284                 res.action = boost::msm::front::puml::detail::cleanup_token(part.substr(action_pos + 1));
0285             }
0286             // handle guards
0287             res.guard = boost::msm::front::puml::detail::parse_guards(
0288                 boost::msm::front::puml::detail::cleanup_token(part)).guard;
0289             return res;
0290         }
0291 
0292         constexpr boost::msm::front::puml::detail::Transition parse_row(std::string_view row)
0293         {
0294             auto arrow_pos = row.find("->");
0295             auto puml_event_pos = row.find(":");
0296             auto left = row.substr(0, arrow_pos);
0297             auto right = row.substr(arrow_pos + 2);
0298 
0299             if (puml_event_pos != std::string::npos)
0300             {
0301                 return boost::msm::front::puml::detail::Transition{
0302                             boost::msm::front::puml::detail::cleanup_token(left),
0303                             boost::msm::front::puml::detail::parse_row_right(right).target,
0304                             boost::msm::front::puml::detail::parse_row_right(right).event,
0305                             boost::msm::front::puml::detail::parse_row_right(right).guard,
0306                             boost::msm::front::puml::detail::parse_row_right(right).action };
0307             }
0308             else if (arrow_pos != std::string::npos)
0309             {
0310                 // simple source -> target form
0311                 return boost::msm::front::puml::detail::Transition{
0312                     boost::msm::front::puml::detail::cleanup_token(left),
0313                     boost::msm::front::puml::detail::cleanup_token(right),
0314                     std::string_view{},
0315                     std::string_view{},
0316                     std::string_view{}
0317                 };
0318             }
0319             return boost::msm::front::puml::detail::Transition{};
0320         }
0321 
0322 
0323         constexpr int count_transitions(std::string_view s)
0324         {
0325             //s = reduce(s, "");
0326             int occurrences = 0;
0327             std::string::size_type pos = 0;
0328             auto target = "->";
0329             while ((pos = s.find(target, pos)) != std::string::npos)
0330             {
0331                 ++occurrences;
0332                 pos += 2;
0333             }
0334             return occurrences;
0335         };
0336         constexpr int count_inits(std::string_view s, std::size_t occurrences=0)
0337         {
0338             auto target = "[*]";
0339             auto star_pos = s.find(target);
0340             auto endl_after_pos = s.find("\n", star_pos);
0341             auto arrow_after_pos = s.find("->", star_pos);
0342             if (star_pos != std::string::npos && 
0343                 star_pos < arrow_after_pos && 
0344                 arrow_after_pos < endl_after_pos)
0345             {
0346                 return count_inits(s.substr(endl_after_pos), occurrences + 1);
0347             }
0348             return occurrences;
0349         };
0350         constexpr int count_actions(std::string_view s)
0351         {
0352             int occurrences = 0;
0353             if (!s.empty())
0354             {
0355                 occurrences = 1;
0356             }
0357             std::string::size_type pos = 0;
0358             auto target = ",";
0359             while ((pos = s.find(target, pos)) != std::string::npos)
0360             {
0361                 ++occurrences;
0362                 pos += 1;
0363             }
0364             return occurrences;
0365         };
0366 
0367         template <int t>
0368         constexpr
0369             auto parse_stt(std::string_view stt)
0370         {
0371             auto prev_pos = std::string::size_type(0);
0372             auto pos = std::string::size_type(0);
0373             auto trans_cpt = 0;
0374             do
0375             {
0376                 pos = stt.find("\n", prev_pos);
0377                 auto transition_symbol = stt.find("->", prev_pos);
0378                 auto init_symbol = stt.find("[*]", prev_pos);
0379                 if (init_symbol < pos || transition_symbol >= pos)
0380                 {
0381                     prev_pos = pos + 1;
0382                 }
0383                 else
0384                 {
0385                     if (trans_cpt == t)
0386                     {
0387                         return boost::msm::front::puml::detail::parse_row(stt.substr(prev_pos, pos - prev_pos));
0388                     }
0389                     prev_pos = pos + 1;
0390                     ++trans_cpt;
0391                 }
0392             } while (pos != std::string::npos);
0393             // should not happen
0394             return boost::msm::front::puml::detail::Transition{};
0395         }
0396 
0397         template <int a>
0398         constexpr auto parse_action(std::string_view actions)
0399         {
0400             //actions = reduce(actions, "");
0401             auto prev_pos = std::string::size_type(0);
0402             auto pos = std::string::size_type(0);
0403             auto action_cpt = 0;
0404             do
0405             {
0406                 pos = actions.find(",", prev_pos);
0407                 if (action_cpt == a)
0408                 {
0409                     return boost::msm::front::puml::detail::cleanup_token(actions.substr(prev_pos, pos - prev_pos));
0410                 }
0411                 ++action_cpt;
0412                 prev_pos = pos + 1;
0413             } while (pos != std::string::npos);
0414             // should not happen
0415             return std::string_view{};
0416         }
0417 
0418 
0419         template <int t>
0420         constexpr
0421             auto parse_inits(std::string_view stt)
0422         {
0423             //stt = reduce(stt, "");
0424 
0425             auto prev_pos = std::string::size_type(0);
0426             auto pos = std::string::size_type(0);
0427             auto trans_cpt = 0;
0428             do
0429             {
0430                 pos = stt.find("\n", prev_pos);
0431                 auto init_symbol = stt.find("[*]", prev_pos);
0432                 if (pos > init_symbol)
0433                 {
0434                     auto init_symbol2 = stt.find("->", init_symbol);
0435                     if (pos > init_symbol2)
0436                     {
0437                         if (trans_cpt == t)
0438                         {
0439                             return cleanup_token(stt.substr(init_symbol2 + 2, pos - init_symbol2 - 2));
0440                         }
0441                         ++trans_cpt;
0442                     }
0443                 }
0444                 prev_pos = pos + 1;
0445             } while (pos != std::string::npos);
0446             // should not happen
0447             return std::string_view{};
0448         }        
0449     } //namespace detail
0450 
0451     constexpr std::uint32_t by_name(std::string_view str)
0452     {
0453         return boost::msm::front::puml::detail::crc32(str) ^ 0xFFFFFFFF;
0454     }
0455 
0456     // specializations
0457     template<>
0458     struct convert_to_msm_names<State<by_name("")>>
0459     {
0460         using type = boost::msm::front::none;
0461     };
0462     template<>
0463     struct convert_to_msm_names<Event< by_name("")>>
0464     {
0465         using type = boost::msm::front::none;
0466     };
0467     template<>
0468     struct convert_to_msm_names<Action< by_name("")>>
0469     {
0470         using type = boost::msm::front::none;
0471     };
0472     template<>
0473     struct convert_to_msm_names<Guard< by_name("")>>
0474     {
0475         using type = boost::msm::front::none;
0476     };
0477     template<>
0478     struct convert_to_msm_names<Action< by_name("defer")>>
0479     {
0480         using type = boost::msm::front::Defer;
0481     };
0482     template<>
0483     struct convert_to_msm_names<Event< by_name("*")>>
0484     {
0485         using type = boost::any;
0486     };
0487 
0488     namespace detail
0489     {
0490         template <class Func>
0491         constexpr auto parse_guard_simple(Func guard_func)
0492         {
0493             constexpr auto and_pos = guard_func().find("&&");
0494             constexpr auto or_pos = guard_func().find("||");
0495             constexpr auto not_pos = guard_func().find("!");
0496             constexpr auto parens_begin_pos = guard_func().find("(");
0497             constexpr auto parens_end_pos = guard_func().find(")");
0498             constexpr auto last_and_pos = guard_func().find("&&", parens_end_pos);
0499             constexpr auto last_or_pos = guard_func().find("||", parens_end_pos);
0500 
0501             // check for operator of the lesser precedence after end parens
0502             if constexpr (parens_begin_pos != std::string::npos && parens_end_pos != std::string::npos &&
0503                 last_or_pos != std::string::npos && parens_end_pos < last_or_pos)
0504             {
0505                 return boost::msm::front::Or_<
0506                     decltype(boost::msm::front::puml::detail::parse_guard_simple(
0507                         [=]() {return boost::msm::front::puml::detail::cleanup_token(guard_func().substr(0, last_or_pos)); })),
0508                     decltype(boost::msm::front::puml::detail::parse_guard_simple(
0509                         [=]() {return boost::msm::front::puml::detail::cleanup_token(guard_func().substr(last_or_pos + 2)); })) > {};
0510             }
0511             else if constexpr (parens_begin_pos != std::string::npos && parens_end_pos != std::string::npos &&
0512                 last_and_pos != std::string::npos && parens_end_pos < last_and_pos)
0513             {
0514                 return boost::msm::front::And_<
0515                     decltype(boost::msm::front::puml::detail::parse_guard_simple(
0516                         [=]() {return boost::msm::front::puml::detail::cleanup_token(guard_func().substr(0, last_and_pos)); })),
0517                     decltype(boost::msm::front::puml::detail::parse_guard_simple(
0518                         [=]() {return boost::msm::front::puml::detail::cleanup_token(guard_func().substr(last_and_pos + 2)); })) > {};
0519             }
0520             else if  constexpr (parens_begin_pos != std::string::npos && parens_end_pos != std::string::npos &&
0521                 or_pos != std::string::npos && or_pos < and_pos && or_pos < parens_begin_pos)
0522             {
0523                 return boost::msm::front::Or_<
0524                     decltype(boost::msm::front::puml::detail::parse_guard_simple(
0525                         [=]() {return boost::msm::front::puml::detail::cleanup_token(guard_func().substr(0, or_pos)); })),
0526                     decltype(boost::msm::front::puml::detail::parse_guard_simple(
0527                         [=]() {return boost::msm::front::puml::detail::cleanup_token(guard_func().substr(or_pos + 2)); })) > {};
0528             }
0529             else if  constexpr (parens_begin_pos != std::string::npos && parens_end_pos != std::string::npos &&
0530                 and_pos != std::string::npos && and_pos < or_pos && and_pos < parens_begin_pos)
0531             {
0532                 return boost::msm::front::And_<
0533                     decltype(boost::msm::front::puml::detail::parse_guard_simple(
0534                         [=]() {return boost::msm::front::puml::detail::cleanup_token(guard_func().substr(0, and_pos)); })),
0535                     decltype(boost::msm::front::puml::detail::parse_guard_simple(
0536                         [=]() {return boost::msm::front::puml::detail::cleanup_token(guard_func().substr(and_pos + 2)); })) > {};
0537             }
0538             else if  constexpr (parens_begin_pos != std::string::npos && parens_end_pos != std::string::npos &&
0539                 not_pos != std::string::npos && not_pos < parens_begin_pos)
0540             {
0541                 return boost::msm::front::Not_<decltype(boost::msm::front::puml::detail::parse_guard_simple(
0542                     [=]() {return boost::msm::front::puml::detail::cleanup_token(guard_func().substr(not_pos + 1)); })) > {};
0543             }
0544             else if constexpr (parens_begin_pos != std::string::npos && parens_end_pos != std::string::npos)
0545             {
0546                 return boost::msm::front::puml::detail::parse_guard_simple(
0547                     [=]() {return boost::msm::front::puml::detail::cleanup_token(guard_func().substr(parens_begin_pos + 1, parens_end_pos - (parens_begin_pos + 1))); });
0548             }
0549             else if constexpr (and_pos == std::string::npos && or_pos == std::string::npos && not_pos == std::string::npos)
0550             {
0551                 return typename boost::msm::front::puml::convert_to_msm_names < Guard <by_name(guard_func())> >::type{};
0552             }
0553             // at least one operator, break at pos of the lesser precedence
0554             else if constexpr (or_pos != std::string::npos)
0555             {
0556                 return boost::msm::front::Or_<
0557                     decltype(boost::msm::front::puml::detail::parse_guard_simple(
0558                         [=]() {return boost::msm::front::puml::detail::cleanup_token(guard_func().substr(0, or_pos)); })),
0559                     decltype(boost::msm::front::puml::detail::parse_guard_simple(
0560                         [=]() {return boost::msm::front::puml::detail::cleanup_token(guard_func().substr(or_pos + 2)); })) > {};
0561             }
0562             else if constexpr (and_pos != std::string::npos)
0563             {
0564                 return boost::msm::front::And_<
0565                     decltype(boost::msm::front::puml::detail::parse_guard_simple(
0566                         [=]() {return boost::msm::front::puml::detail::cleanup_token(guard_func().substr(0, and_pos)); })),
0567                     decltype(boost::msm::front::puml::detail::parse_guard_simple(
0568                         [=]() {return boost::msm::front::puml::detail::cleanup_token(guard_func().substr(and_pos + 2)); })) > {};
0569             }
0570             else
0571             {
0572                 return boost::msm::front::Not_<decltype(boost::msm::front::puml::detail::parse_guard_simple(
0573                     [=]() {return boost::msm::front::puml::detail::cleanup_token(guard_func().substr(not_pos + 1)); })) > {};
0574             }
0575         }
0576         template <class Func>
0577         constexpr auto parse_guard_advanced(Func guard_func)
0578         {
0579             constexpr auto and_pos = guard_func().find("And(");
0580             constexpr auto or_pos = guard_func().find("Or(");
0581             constexpr auto not_pos = guard_func().find("Not(");
0582 
0583             if constexpr (and_pos == std::string::npos && or_pos == std::string::npos && not_pos == std::string::npos)
0584             {
0585                 return typename boost::msm::front::puml::convert_to_msm_names < Guard <by_name(guard_func())> >::type{};
0586             }
0587             // at least one operator, break at pos of the lesser precedence
0588             else if constexpr (or_pos != std::string::npos)
0589             {
0590                 constexpr auto comma_pos = guard_func().find(",", or_pos);
0591                 constexpr auto endparens_pos = guard_func().find(")", or_pos);
0592                 return boost::msm::front::Or_<
0593                     decltype(boost::msm::front::puml::detail::parse_guard_advanced(
0594                         [=]() {return boost::msm::front::puml::detail::cleanup_token(guard_func().substr(or_pos + 3, comma_pos - (or_pos + 3))); })),
0595                     decltype(boost::msm::front::puml::detail::parse_guard_advanced(
0596                         [=]() {return boost::msm::front::puml::detail::cleanup_token(guard_func().substr(comma_pos + 1, endparens_pos - (comma_pos + 1))); }))
0597                 > {};
0598             }
0599             else if constexpr (and_pos != std::string::npos)
0600             {
0601                 constexpr auto comma_pos = guard_func().find(",", and_pos);
0602                 constexpr auto endparens_pos = guard_func().find(")", and_pos);
0603                 return boost::msm::front::And_<
0604                     decltype(boost::msm::front::puml::detail::parse_guard_advanced(
0605                         [=]() {return boost::msm::front::puml::detail::cleanup_token(guard_func().substr(and_pos + 4, comma_pos - (and_pos + 4))); })),
0606                     decltype(boost::msm::front::puml::detail::parse_guard_advanced(
0607                         [=]() {return boost::msm::front::puml::detail::cleanup_token(guard_func().substr(comma_pos + 1, endparens_pos - (comma_pos + 1))); }))
0608                 > {};
0609             }
0610             else
0611             {
0612                 constexpr auto endparens_pos = guard_func().find(")", not_pos);
0613                 return boost::msm::front::Not_<
0614                     decltype(boost::msm::front::puml::detail::parse_guard_advanced(
0615                         [=]() {return boost::msm::front::puml::detail::cleanup_token(guard_func().substr(not_pos + 4, endparens_pos - (not_pos + 4))); }))
0616                 > {};
0617             }
0618         }
0619 
0620         template <class Func>
0621         constexpr auto parse_guard(Func guard_func)
0622         {
0623             if constexpr (guard_func().find("And(") != std::string::npos ||
0624                 guard_func().find("Or(") != std::string::npos ||
0625                 guard_func().find("Not(") != std::string::npos)
0626             {
0627                 return boost::msm::front::puml::detail::parse_guard_advanced(guard_func);
0628             }
0629             else
0630             {
0631                 return boost::msm::front::puml::detail::parse_guard_simple(guard_func);
0632             }
0633         }
0634 
0635         constexpr int count_terminates(std::string_view s, std::size_t occurrences = 0)
0636         {
0637             if (s.empty())
0638                 return occurrences;
0639             auto star_pos = s.find("[*]");
0640             auto arrow_pos = s.rfind("->", star_pos);
0641             auto endl_before_pos = s.rfind("\n", star_pos);
0642             if (star_pos != std::string::npos &&
0643                 arrow_pos != std::string::npos &&
0644                 arrow_pos > endl_before_pos )
0645             {
0646                 return count_terminates(s.substr(star_pos + 3), occurrences + 1);
0647             }
0648             else if(star_pos != std::string::npos)
0649             {
0650                 return count_terminates(s.substr(star_pos + 3), occurrences);
0651             }
0652             return occurrences;
0653         };
0654 
0655         template <class Func, class T>
0656         constexpr auto parse_terminate(Func stt, auto state_name, T vec = T{})
0657         {
0658             if constexpr (stt().empty())
0659             {
0660                 return vec;
0661             }
0662             else
0663             {
0664                 constexpr auto star_pos = stt().find("[*]");
0665                 constexpr auto arrow_pos = stt().rfind("->", star_pos);
0666                 constexpr auto endl_before_pos = stt().rfind("\n", star_pos);
0667                 constexpr auto state_pos = stt().rfind(state_name(), arrow_pos);
0668 
0669                 if constexpr (
0670                     star_pos != std::string::npos &&
0671                     arrow_pos != std::string::npos &&
0672                     arrow_pos > endl_before_pos &&
0673                     state_pos != std::string::npos &&
0674                     state_pos > endl_before_pos &&
0675                     cleanup_token(stt().substr(state_pos, arrow_pos - state_pos)) == state_name())
0676                 {
0677                     return
0678                         typename ::boost::mpl::push_back<
0679                         T,
0680                         boost::msm::TerminateFlag
0681                         >::type{};
0682                 }
0683                 else if constexpr (star_pos != std::string::npos)
0684                 {
0685                     return parse_terminate(
0686                         [=]() {return stt().substr(star_pos + 3); },
0687                         state_name,
0688                         vec);
0689                 }
0690                 else
0691                 {
0692                     return vec;
0693                 }
0694             }
0695 
0696         };
0697 
0698         template <class Func, class T = boost::fusion::vector0<>>
0699         constexpr auto parse_flags(Func stt, auto state_name, T vec = T{})
0700         {
0701             constexpr auto flag_pos = stt().find("flag");
0702 
0703             if constexpr (flag_pos != std::string::npos)
0704             {          
0705                 // we need to handle a flag
0706                 constexpr auto endl_after_flag_pos = stt().find("\n", flag_pos);
0707                 constexpr auto col_pos = stt().rfind(":",flag_pos);
0708                 constexpr auto endl_before_flag_pos = stt().rfind("\n", flag_pos);
0709 
0710                 if constexpr (endl_after_flag_pos != std::string::npos)
0711                 {
0712                     // the name start from end of prev line+1 to :
0713                     if constexpr (cleanup_token(stt().substr(endl_before_flag_pos+1,col_pos- (endl_before_flag_pos+1))) == state_name())
0714                     {
0715                         // flag name is from flag tag until endline
0716                         return parse_flags(
0717                             [=]() {return stt().substr(endl_after_flag_pos + 1); },
0718                             state_name,
0719                             typename ::boost::mpl::push_back<
0720                             T,
0721                             typename boost::msm::front::puml::convert_to_msm_names<
0722                             boost::msm::front::puml::Flag< by_name(cleanup_token(stt().substr(flag_pos + 4, endl_after_flag_pos - (flag_pos + 4))))>>::type
0723                             >::type{});
0724                     }
0725                     else
0726                     {
0727                         // check starting from next line
0728                         return parse_flags(
0729                             [=]() {return stt().substr(endl_after_flag_pos + 1); },
0730                             state_name,
0731                             vec);
0732                     }
0733                 }
0734                 else
0735                 {
0736                     // the flag line is the last line of the string so we will end recursion wether we found a flag or not
0737                     if constexpr (cleanup_token(stt().substr(endl_before_flag_pos + 1, col_pos - (endl_before_flag_pos + 1))) == state_name())
0738                     {
0739                         return typename ::boost::mpl::push_back<
0740                             T,
0741                             typename boost::msm::front::puml::convert_to_msm_names<
0742                             boost::msm::front::puml::Flag< by_name(cleanup_token(stt().substr(flag_pos + 4, endl_after_flag_pos - (flag_pos + 4))))>>::type
0743                             >::type{};
0744                     }
0745                     else
0746                     {
0747                         return vec;
0748                     }
0749                 }                
0750             }
0751             else 
0752             {
0753                 // no flag left, end recursion
0754                 return vec;
0755             }            
0756         }
0757 
0758         template <class Func, int actions_count, int anum, class T = boost::fusion::vector<>>
0759         constexpr auto create_action_sequence_helper(Func action_func, T vec = T{})
0760         {
0761             // stop condition
0762             if constexpr (anum >= actions_count)
0763             {
0764                 return vec;
0765             }
0766             else
0767             {
0768                 return boost::msm::front::puml::detail::create_action_sequence_helper<Func, actions_count, anum + 1>(
0769                     action_func,
0770                     typename ::boost::mpl::push_back<
0771                     T,
0772                     typename boost::msm::front::puml::convert_to_msm_names<
0773                     Action<by_name(boost::msm::front::puml::detail::parse_action<anum>(action_func()))>>::type >::type{});
0774             }
0775         }
0776         template <class Func>
0777         constexpr auto create_action_sequence(Func action_func)
0778         {
0779             return boost::msm::front::puml::detail::create_action_sequence_helper<
0780                 Func, boost::msm::front::puml::detail::count_actions(action_func()), 0>(action_func);
0781         }
0782 
0783 
0784         template <class Func, class T = boost::fusion::vector0<>>
0785         constexpr auto parse_state_actions(Func stt, auto state_name, auto tag_text, T vec = T{})
0786         {
0787             constexpr auto entry_pos = stt().find(std::string_view(tag_text()));
0788             constexpr auto tag_size = std::string_view(tag_text()).length();
0789 
0790             if constexpr (entry_pos != std::string::npos)
0791             {
0792                 // we need to handle an entry
0793                 constexpr auto endl_after_entry_pos = stt().find("\n", entry_pos);
0794                 constexpr auto bracket_beg_after_entry_pos = stt().find("[", entry_pos);
0795 
0796                 constexpr auto col_pos = stt().rfind(":", entry_pos);
0797                 constexpr auto endl_before_entry_pos = stt().rfind("\n", entry_pos);
0798                 auto make_action_sequence = [](auto actions)
0799                     {
0800                         if constexpr (boost::mpl::size<decltype(actions)>::value == 1)
0801                             return boost::fusion::at_c<0>(actions);
0802                         else if constexpr (boost::mpl::size<decltype(actions)>::value == 0)
0803                             return boost::msm::front::none{};
0804                         else
0805                             return boost::msm::front::ActionSequence_<decltype(actions)>{};
0806                     };
0807 
0808                 if constexpr (endl_after_entry_pos != std::string::npos)
0809                 {
0810                     // the name start from end of prev line+1 to :
0811                     if constexpr (by_name(cleanup_token(stt().substr(endl_before_entry_pos + 1, col_pos - (endl_before_entry_pos + 1)))) == by_name(state_name()))
0812                     {
0813                         if constexpr (bracket_beg_after_entry_pos != std::string::npos && bracket_beg_after_entry_pos < endl_after_entry_pos)
0814                         {
0815                             constexpr auto bracket_end_after_entry_pos = stt().find("]", entry_pos);
0816                             auto guard_l = [=]() {return stt().substr(bracket_beg_after_entry_pos +1, bracket_end_after_entry_pos - (bracket_beg_after_entry_pos +1)) ; };
0817                             auto action_l = [=]() {return stt().substr(entry_pos + tag_size, bracket_beg_after_entry_pos - (entry_pos + tag_size)); };
0818 
0819                             // action name is from entry tag until [
0820                             return parse_state_actions(
0821                                 [=]() {return stt().substr(endl_after_entry_pos + 1); },
0822                                 state_name,
0823                                 tag_text,
0824                                 typename ::boost::mpl::push_back<
0825                                     T,
0826                                     boost::msm::front::puml::detail::pair_type<
0827                                         decltype(make_action_sequence(boost::msm::front::puml::detail::create_action_sequence(action_l))),
0828                                         typename boost::msm::front::puml::convert_to_msm_names<
0829                                             decltype(boost::msm::front::puml::detail::parse_guard(guard_l))>::type
0830                                     >
0831                                 >::type{});
0832                         }
0833                         else
0834                         {
0835                             // action name is from entry tag until endline
0836                             auto action_l = [=]() {return stt().substr(entry_pos + tag_size, endl_after_entry_pos - (entry_pos + tag_size)); };
0837 
0838                             return parse_state_actions(
0839                                 [=]() {return stt().substr(endl_after_entry_pos + 1); },
0840                                 state_name,
0841                                 tag_text,
0842                                 typename ::boost::mpl::push_back<
0843                                     T,
0844                                     boost::msm::front::puml::detail::pair_type<
0845                                         decltype(make_action_sequence(boost::msm::front::puml::detail::create_action_sequence(action_l))),
0846                                         typename boost::msm::front::puml::convert_to_msm_names<
0847                                             boost::msm::front::puml::Guard<by_name("")>>::type
0848                                     >
0849                                 >::type{});
0850                         }
0851 
0852                     }
0853                     else
0854                     {
0855                         // check starting from next line
0856                         return parse_state_actions(
0857                             [=]() {return stt().substr(endl_after_entry_pos + 1); },
0858                             state_name,
0859                             tag_text,
0860                             vec);
0861                     }
0862                 }
0863                 // last line of string
0864                 else
0865                 {
0866                     // the entry line is the last line of the string so we will end recursion wether we found an entry or not
0867                     if constexpr (by_name(cleanup_token(stt().substr(endl_before_entry_pos + 1, col_pos - (endl_before_entry_pos + 1)))) == by_name(state_name()))
0868                     {
0869                         if constexpr (bracket_beg_after_entry_pos != std::string::npos && bracket_beg_after_entry_pos < endl_after_entry_pos)
0870                         {
0871                             constexpr auto bracket_end_after_entry_pos = stt().find("]", entry_pos);
0872                             auto guard_l = [stt]() {return stt().substr(bracket_beg_after_entry_pos +1, bracket_end_after_entry_pos - (bracket_beg_after_entry_pos +1)) ; };
0873 
0874 
0875                             // action name is from entry tag until [
0876                             auto action_l = [stt]() {return stt().substr(entry_pos + tag_size, bracket_beg_after_entry_pos - (entry_pos + tag_size)); };
0877 
0878                             return 
0879                                 typename ::boost::mpl::push_back<
0880                                     T,
0881                                     boost::msm::front::puml::detail::pair_type<
0882                                         decltype(make_action_sequence(boost::msm::front::puml::detail::create_action_sequence(action_l))),
0883                                         decltype(boost::msm::front::puml::detail::parse_guard(guard_l))
0884                                     >
0885                                 >::type{};
0886                         }
0887                         else
0888                         {
0889                             auto action_l = [stt]() {return stt().substr(entry_pos + tag_size, endl_after_entry_pos - (entry_pos + tag_size)); };
0890 
0891                             return 
0892                             typename ::boost::mpl::push_back<
0893                                 T,
0894                                 boost::msm::front::puml::detail::pair_type <
0895                                     decltype(make_action_sequence(boost::msm::front::puml::detail::create_action_sequence(action_l))),
0896                                     boost::msm::front::puml::Guard<by_name("")>
0897                                 >
0898                             >::type{};
0899                         }
0900 
0901                     }
0902                     else
0903                     {
0904                         return vec;
0905                     }
0906                 }
0907             }
0908             else
0909             {
0910                 // no entry left, end recursion
0911                 return vec;
0912             }
0913         }
0914 
0915         // recursively fills fusion vector with transition (making a tansition_table)
0916         template <class Func, int transitions, int tnum, class T = boost::fusion::vector<>>
0917         constexpr auto create_transition_table_helper(Func stt, T vec = T{})
0918         {
0919             // stop condition
0920             if constexpr (tnum >= transitions)
0921             {
0922                 return vec;
0923             }
0924             else
0925             {
0926                 auto guard_l = [stt]() {return boost::msm::front::puml::detail::parse_stt<tnum>(stt()).guard; };
0927                 auto action_l = [stt]() {return boost::msm::front::puml::detail::parse_stt<tnum>(stt()).action; };
0928                 auto source_l = [stt]() {return boost::msm::front::puml::detail::parse_stt<tnum>(stt()).source; };
0929                 auto target_l = [stt]() {return boost::msm::front::puml::detail::parse_stt<tnum>(stt()).target; };
0930                 auto stt_l = [stt]() {return std::string_view(stt()); };
0931                 auto entry_l = []() {return "entry"; };
0932                 auto exit_l = []() {return "exit"; };
0933 
0934                 auto make_action_sequence = [](auto actions)
0935                     {
0936                         if constexpr (boost::mpl::size<decltype(actions)>::value == 1)
0937                             return boost::fusion::at_c<0>(actions);
0938                         else if constexpr (boost::mpl::size<decltype(actions)>::value == 0)
0939                             return boost::msm::front::none{};
0940                         else
0941                             return boost::msm::front::ActionSequence_<decltype(actions)>{};
0942                     };
0943 
0944 
0945                 using one_row =
0946                     boost::msm::front::Row <
0947                     State < by_name(boost::msm::front::puml::detail::parse_stt<tnum>(stt()).source),
0948                             decltype(boost::msm::front::puml::detail::parse_terminate(
0949                                 stt_l, source_l, boost::msm::front::puml::detail::parse_flags(stt_l,source_l))),
0950                             decltype(parse_state_actions(stt_l,source_l, entry_l)),
0951                             decltype(parse_state_actions(stt_l,source_l, exit_l))
0952                     >,
0953                     typename boost::msm::front::puml::convert_to_msm_names<
0954                         Event< by_name(boost::msm::front::puml::detail::parse_stt<tnum>(stt()).event)>>::type,
0955                     typename boost::msm::front::puml::convert_to_msm_names<
0956                         State< by_name(boost::msm::front::puml::detail::parse_stt<tnum>(stt()).target),
0957                                decltype(boost::msm::front::puml::detail::parse_terminate(
0958                                    stt_l, target_l, boost::msm::front::puml::detail::parse_flags(stt_l,target_l))),
0959                                decltype(parse_state_actions(stt_l, target_l, entry_l)),
0960                                decltype(parse_state_actions(stt_l, target_l, exit_l))
0961                     >>::type,
0962                     decltype(make_action_sequence(boost::msm::front::puml::detail::create_action_sequence(action_l))),
0963                     decltype(boost::msm::front::puml::detail::parse_guard(guard_l))
0964                     >;
0965 
0966                 return boost::msm::front::puml::detail::create_transition_table_helper<Func, transitions, tnum + 1>(
0967                     stt, typename ::boost::mpl::push_back< T, one_row>::type{});
0968             }
0969         }
0970 
0971 
0972         template <class Func, int regions, int rnum, class T = boost::fusion::vector<>>
0973         constexpr auto create_inits_helper(Func stt, T vec = T{})
0974         {
0975             // stop condition
0976             if constexpr (rnum >= regions)
0977             {
0978                 return vec;
0979             }
0980             else
0981             {
0982                 return boost::msm::front::puml::detail::create_inits_helper<Func, regions, rnum + 1>(
0983                     stt, typename ::boost::mpl::push_back< T, State<by_name(boost::msm::front::puml::detail::parse_inits<rnum>(stt()))> >::type{});
0984             }
0985         }
0986 
0987 
0988     }//namespace detail
0989 
0990 
0991 
0992     template <class Func>
0993     constexpr auto create_transition_table(Func stt_func)
0994     {
0995         return boost::msm::front::puml::detail::create_transition_table_helper<
0996             Func,
0997             boost::msm::front::puml::detail::count_transitions(
0998                 stt_func()) - 
0999                 boost::msm::front::puml::detail::count_inits(stt_func()) - 
1000                 boost::msm::front::puml::detail::count_terminates(stt_func())
1001             , 0>(stt_func);
1002     }
1003 
1004     template <class Func>
1005     constexpr auto create_initial_states(Func stt_func)
1006     {
1007         return boost::msm::front::puml::detail::create_inits_helper<
1008             Func,
1009             boost::msm::front::puml::detail::count_inits(stt_func()), 0>(stt_func);
1010     }
1011 
1012     template <class Func>
1013     constexpr auto create_fsm_table(Func stt_func)
1014     {
1015         return boost::msm::front::puml::detail::pair_type <
1016            decltype(
1017            boost::msm::front::puml::detail::create_transition_table_helper<
1018                 Func,
1019                 boost::msm::front::puml::detail::count_transitions(
1020                     stt_func()) -
1021                     boost::msm::front::puml::detail::count_inits(stt_func()) - 
1022                     boost::msm::front::puml::detail::count_terminates(stt_func())
1023                , 0>(stt_func)),
1024            decltype(
1025            boost::msm::front::puml::detail::create_inits_helper<
1026                 Func,
1027                 boost::msm::front::puml::detail::count_inits(stt_func()), 0>(stt_func))>{};
1028     }
1029 
1030 }//boost::msm::front::puml
1031 
1032 // helper macro to hide declarations
1033 #define BOOST_MSM_PUML_DECLARE_TABLE(stt)                       \
1034 using Stt = decltype(create_fsm_table([]() {return stt;}));     \
1035 using transition_table = typename Stt::first;                   \
1036 using initial_state = typename Stt::second;
1037 
1038 
1039 #endif // BOOST_MSM_FRONT_PUML_COMMON_H