18#include "quetzal/coalescence/graph/k_ary_tree.hpp"
19#include <boost/graph/depth_first_search.hpp>
39template <
typename P1>
using single_function_argument_t =
typename single_function_argument_impl<P1>::type;
58bool check_if_balanced(std::string_view input,
const char &open =
'(',
const char &close =
')')
61 for (
const auto &ch : input)
80 static std::string edit(
const std::string s)
98 static bool check(std::string_view s)
109 static bool check(std::string_view s)
116using namespace std::string_literals;
121static inline std::vector<std::string> forbidden_labels = {
" "s,
","s,
";"s,
"("s,
")"s,
"["s,
"]"s};
130static inline constexpr char blank =
'_';
135template <
unsigned int N>
struct remove_comments_of_depth
142template <>
struct remove_comments_of_depth<0> : detail::identity
151template <>
struct remove_comments_of_depth<1>
153 static std::string edit(
const std::string s)
157 return std::regex_replace(s, std::regex(R
"(\[[^()]*\])"), "");
166template <>
struct remove_comments_of_depth<2>
168 static std::string edit(
const std::string s)
172 for (
const auto &ch : s)
178 if (ch ==
'[' && counter == 2)
180 if (ch ==
']' && counter == 1)
182 if (!(counter >= 2 || (counter == 1 && ch ==
']')))
183 buffer.append(std::string(1, ch));
197 static inline std::string root_branch_length()
202 static inline std::string treat_comments(std::string &s)
216 static inline std::string root_branch_length()
221 static inline std::string treat_comments(
const std::string s)
223 return remove_comments_of_depth<2>::edit(s);
235 static inline std::string root_branch_length()
240 static inline std::string treat_comments(std::string &s)
243 return remove_comments_of_depth<2>::edit(s);
250template <
class F,
class... Args>
251concept Formattable = std::invocable<F, Args...> && std::convertible_to<std::invoke_result_t<F, Args...>, std::string>;
258template <
class T, std::predicate<T> P1, std::predicate<T> P2, Formattable<T> F1, Formattable<T> F2,
280 static inline constexpr char _end =
';';
290 mutable int _depth = 0;
323 void _pre_order(
const node_type &node)
const
325 if (std::invoke(_has_children, node))
332 void _in_order()
const
340 if (std::invoke(_has_children, node))
344 if (std::invoke(_has_parent, node))
346 auto const label = std::invoke(_label, node);
348 std::string
const branch(std::invoke(_branch_length, node));
350 _formula.append(
":").append(branch);
355 _formula += std::invoke(_label, node);
356 _formula += policy_type::root_branch_length();
366 generator(P1 has_parent, P2 has_children, F1 label, F2 branch_length, Policy pol = {})
367 :
policy_type(std::move(pol)), _has_parent(std::move(has_parent)), _has_children(std::move(has_children)),
368 _label(std::move(label)), _branch_length(std::move(branch_length))
379 return [
this](
const node_type &node) { this->_pre_order(node); };
387 return [
this]() { this->_in_order(); };
398 return [
this](
const node_type &node) { this->_post_order(node); };
408 std::string forbidden =
" ,;()[\\]";
409 bool is_forbidden = std::regex_search(s, std::regex(
"[" + forbidden +
"]"));
426 _formula.push_back(this->_end);
428 _formula = policy_type::treat_comments(_formula);
432 throw std::runtime_error(std::string(
"Failed: formula parenthesis are not balanced:") + _formula);
437 throw std::runtime_error(std::string(
"Failed: formula square brackets are not balanced:") + _formula);
440 return std::move(_formula);
449template <
class P1,
class P2,
class F1,
class F2,
class Policy = PAUP>
450generator(P1, P2, F1, F2, Policy pol = {}) -> generator<detail::single_function_argument_t<P1>, P1, P2, F1, F2, Policy>;