diff --git a/include/warthog/search/uds_traits.h b/include/warthog/search/uds_traits.h index bfaac52..9d65c8b 100644 --- a/include/warthog/search/uds_traits.h +++ b/include/warthog/search/uds_traits.h @@ -14,6 +14,7 @@ #include "search_metrics.h" #include +#include namespace warthog::search { @@ -133,7 +134,7 @@ enum class reopen_policy // decide whether to renopen nodes already expanded (when their g-value // can be improved). we handle the positive case via specialisation. -template +template inline bool reopen() { @@ -147,6 +148,108 @@ reopen() return true; } +struct uds_default_traits +{ + // using node = std::tuple<>; + // using observer = std::tuple<>; + static constexpr admissibility_criteria ac = admissibility_criteria::any; + static constexpr feasibility_criteria fc + = feasibility_criteria::until_exhaustion; + static constexpr reopen_policy rp = reopen_policy::no; +}; + +template< + typename N = search_node, typename L = std::tuple<>, + admissibility_criteria AC = admissibility_criteria::any, + feasibility_criteria FC = feasibility_criteria::until_exhaustion, + reopen_policy RP = reopen_policy::no> +struct uds_traits +{ + using node = N; + using observer = L; + static constexpr admissibility_criteria ac = AC; + static constexpr feasibility_criteria fc = FC; + static constexpr reopen_policy rp = RP; +}; + +namespace details +{ + +template +struct uds_trait_node +{ + using type = search_node; +}; +template + requires requires { typename Traits::node; } +struct uds_trait_node +{ + using type = typename Traits::node; +}; + +template +struct uds_trait_observer +{ + using type = search_node; +}; +template + requires requires { typename Traits::observer; } +struct uds_trait_observer +{ + using type = typename Traits::observer; +}; + +} // namespace details + +template +using uds_trait_node = typename details::uds_trait_node::type; + +template +using uds_trait_observer = typename details::uds_trait_observer::type; + +template +inline consteval admissibility_criteria +uds_trait_ac() noexcept +{ + if constexpr(requires { + { + Traits::ac + } -> util::same_as_rmref; + }) + { + return Traits::ac; + } + else { return admissibility_criteria::any; } +} + +template +inline consteval feasibility_criteria +uds_trait_fc() noexcept +{ + if constexpr(requires { + { + Traits::fc + } -> util::same_as_rmref; + }) + { + return Traits::fc; + } + else { return feasibility_criteria::until_exhaustion; } +} + +template +inline consteval reopen_policy +uds_trait_rp() noexcept +{ + if constexpr(requires { + { Traits::rp } -> util::same_as_rmref; + }) + { + return Traits::rp; + } + else { return reopen_policy::no; } +} + } // namespace warthog::search #endif // WARTHOG_SEARCH_UDS_TRAITS_H diff --git a/include/warthog/search/unidirectional_search.h b/include/warthog/search/unidirectional_search.h index 2a04e05..8382bf9 100644 --- a/include/warthog/search/unidirectional_search.h +++ b/include/warthog/search/unidirectional_search.h @@ -41,20 +41,30 @@ namespace warthog::search // (default: search for any solution, until OPEN is exhausted) template< typename H, typename E, typename Q = util::pqueue_min, - typename L = std::tuple<>, - admissibility_criteria AC = admissibility_criteria::any, - feasibility_criteria FC = feasibility_criteria::until_exhaustion, - reopen_policy RP = reopen_policy::no> -class unidirectional_search + typename Traits = uds_default_traits> +class unidirectional_search_full { public: - unidirectional_search( + using traits = Traits; + using search_node = uds_trait_node; + using L = uds_trait_observer; + + static constexpr admissibility_criteria AC = uds_trait_ac(); + static constexpr feasibility_criteria FC = uds_trait_fc(); + static constexpr reopen_policy RP = uds_trait_rp(); + + unidirectional_search_full( H* heuristic, E* expander, Q* queue, L listeners = L{}) : heuristic_(heuristic), expander_(expander), open_(queue), listeners_(listeners) { } + unidirectional_search_full(const unidirectional_search_full& other) + = delete; + ~unidirectional_search_full() = default; - ~unidirectional_search() { } + unidirectional_search_full& + operator=(const unidirectional_search_full& other) + = delete; void get_pathcost(problem_instance* pi, search_parameters* par, solution* sol) @@ -138,14 +148,6 @@ class unidirectional_search Q* open_; [[no_unique_address]] L listeners_; - // no copy ctor - unidirectional_search(const unidirectional_search& other) { } - unidirectional_search& - operator=(const unidirectional_search& other) - { - return *this; - } - /** * Initialise a new 'search_node' for the ongoing search given the parent * node (@param current). @@ -315,6 +317,25 @@ class unidirectional_search } }; +// Keep for backward compatibility. +// Done as class instead of using to support user-defined deduction +template< + typename H, typename E, typename Q = util::pqueue_min, + typename L = std::tuple<>, + admissibility_criteria AC = admissibility_criteria::any, + feasibility_criteria FC = feasibility_criteria::until_exhaustion, + reopen_policy RP = reopen_policy::no> +class unidirectional_search + : public unidirectional_search_full< + H, E, Q, uds_traits> +{ +public: + using unidirectional_search_full = unidirectional_search_full< + H, E, Q, uds_traits>; + + using unidirectional_search_full::unidirectional_search_full; +}; + template< typename H, typename E, typename Q = util::pqueue_min, typename L = std::tuple<>> diff --git a/include/warthog/util/template.h b/include/warthog/util/template.h index ce94e3d..47213c2 100644 --- a/include/warthog/util/template.h +++ b/include/warthog/util/template.h @@ -108,6 +108,13 @@ choose_integer_sequence(auto value, TemplateFunc&& tfunc) value, std::forward(tfunc)); } +template +concept same_as_rmref + = std::same_as, std::remove_reference_t>; +template +concept same_as_rmcvref + = std::same_as, std::remove_cvref_t>; + } // namespace warthog::util #endif // WARTHOG_UTIL_CAST_H