Loading...
Searching...
No Matches
search_configurator.hpp
Go to the documentation of this file.
// SPDX-FileCopyrightText: 2006-2025 Knut Reinert & Freie Universität Berlin
// SPDX-FileCopyrightText: 2016-2025 Knut Reinert & MPI für molekulare Genetik
// SPDX-License-Identifier: BSD-3-Clause
#pragma once
#include <seqan3/core/detail/template_inspection.hpp>
#include <seqan3/search/configuration/hit.hpp>
#include <seqan3/search/configuration/max_error.hpp>
#include <seqan3/search/configuration/output.hpp>
#include <seqan3/search/configuration/result_type.hpp>
#include <seqan3/search/detail/policy_max_error.hpp>
#include <seqan3/search/detail/policy_search_result_builder.hpp>
#include <seqan3/search/detail/search_scheme_algorithm.hpp>
#include <seqan3/search/detail/unidirectional_search_algorithm.hpp>
#include <seqan3/search/search_result.hpp>
#include <seqan3/utility/detail/multi_invocable.hpp>
#include <seqan3/utility/type_traits/lazy_conditional.hpp>
namespace seqan3::detail
{
class search_configurator
{
private:
template <typename search_configuration_t, typename index_t, typename query_index_t>
struct select_search_result
{
private:
using index_cursor_type = typename index_t::cursor_type;
using index_size_type = typename index_t::size_type;
using traits_type = search_traits<search_configuration_t>;
using query_id_t = std::conditional_t<traits_type::output_query_id, size_t, empty_type>;
using index_cursor_t = std::conditional_t<traits_type::output_index_cursor, index_cursor_type, empty_type>;
using reference_id_t = std::conditional_t<traits_type::output_reference_id, index_size_type, empty_type>;
using reference_begin_position_t =
std::conditional_t<traits_type::output_reference_begin_position, index_size_type, empty_type>;
public:
using type = search_result<query_id_t, index_cursor_t, reference_id_t, reference_begin_position_t>;
};
template <typename configuration_t, typename index_t, typename... policies_t>
struct select_search_algorithm
{
using type = lazy_conditional_t<template_specialisation_of<typename index_t::cursor_type, bi_fm_index_cursor>,
lazy<search_scheme_algorithm, configuration_t, index_t, policies_t...>,
lazy<unidirectional_search_algorithm, configuration_t, index_t, policies_t...>>;
};
public:
template <typename configuration_t>
static auto add_default_hit_configuration(configuration_t const & cfg)
{
if constexpr (!detail::search_traits<configuration_t>::has_hit_configuration)
return cfg | search_cfg::hit_all{};
else
return cfg;
}
template <typename configuration_t>
static auto add_default_output_configuration(configuration_t const & cfg)
{
if constexpr (!seqan3::detail::search_traits<configuration_t>::has_output_configuration)
return cfg | search_cfg::output_query_id{} | search_cfg::output_reference_id{}
| search_cfg::output_reference_begin_position{};
else
return cfg;
}
template <typename configuration_t>
static auto add_defaults(configuration_t const & cfg)
{
static_assert(detail::is_type_specialisation_of_v<configuration_t, configuration>,
"cfg must be a specialisation of seqan3::configuration.");
auto cfg1 = add_default_hit_configuration(cfg);
auto cfg2 = add_default_output_configuration(cfg1);
return cfg2;
}
template <typename query_t, typename configuration_t, typename index_t>
static auto configure_algorithm(configuration_t const & cfg, index_t const & index)
{
using query_index_t = std::tuple_element_t<0, query_t>;
using search_result_t = typename select_search_result<configuration_t, index_t, query_index_t>::type;
using callback_t = std::function<void(search_result_t)>;
using type_erased_algorithm_t = std::function<void(query_t, callback_t)>;
auto complete_config = cfg | search_cfg::detail::result_type<search_result_t>{};
return std::pair{configure_hit_strategy<type_erased_algorithm_t>(complete_config, index), complete_config};
}
template <typename algorithm_t, typename configuration_t, typename index_t>
static algorithm_t configure_hit_strategy(configuration_t const &, index_t const &);
template <typename algorithm_t, typename configuration_t, typename index_t>
static algorithm_t select_and_return_algorithm(configuration_t const & config, index_t const & index)
{
using selected_algorithm_t =
typename select_search_algorithm<configuration_t,
index_t,
policy_max_error,
policy_search_result_builder<configuration_t>>::type;
return selected_algorithm_t{config, index};
}
};
template <typename algorithm_t, typename configuration_t, typename index_t>
algorithm_t search_configurator::configure_hit_strategy(configuration_t const & cfg, index_t const & index)
{
// Delegate to the next config with the modified configuration.
auto next_config_step = [&](auto new_cfg) -> algorithm_t
{
return select_and_return_algorithm<algorithm_t>(new_cfg, index);
};
// Check if dynamic config present, otherwise continue.
if constexpr (configuration_t::template exists<search_cfg::hit>())
{
auto hit_variant = get<search_cfg::hit>(cfg).hit_variant;
if (std::holds_alternative<empty_type>(hit_variant))
throw std::invalid_argument{"The dynamic hit strategy was not initialised! "
"Please refer to the configuration documentation of the search algorithm for "
"more details."};
// Remove dynamic config first.
auto cfg_without_hit = cfg.template remove<search_cfg::hit>();
// Apply the correct static configuration element.
if (std::holds_alternative<search_cfg::hit_all_best>(hit_variant))
{
return next_config_step(cfg_without_hit | search_cfg::hit_all_best{});
}
else if (std::holds_alternative<search_cfg::hit_single_best>(hit_variant))
{
return next_config_step(cfg_without_hit | search_cfg::hit_single_best{});
}
else if (std::holds_alternative<search_cfg::hit_strata>(hit_variant))
{
return next_config_step(cfg_without_hit | std::get<search_cfg::hit_strata>(hit_variant));
}
else
return next_config_step(cfg_without_hit | search_cfg::hit_all{});
}
else // Already statically configured.
{
static_assert(detail::search_traits<configuration_t>::has_hit_configuration,
"The hit strategy for the search algorithm was not configured. "
"Please refer to the configuration documentation of the search algorithm for more details.");
return next_config_step(cfg);
}
}
} // namespace seqan3::detail
hit.hpp
Provides the configuration to define the hit strategies "hit_strata", "hit_all", "hit_all_best",...
std::holds_alternative
T holds_alternative(T... args)
lazy_conditional.hpp
Provides lazy template instantiation traits.
max_error.hpp
Provides the configuration for maximum number of errors for all error types.
multi_invocable.hpp
Provides a type that combines multiple invocables.
seqan3::get
constexpr auto const & get(configuration< configs_t... > const &config) noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition configuration.hpp:412
policy_max_error.hpp
Provides the seqan3::detail::policy_max_error.
policy_search_result_builder.hpp
Provides the seqan3::detail::policy_search_result_builder.
result_type.hpp
Provides seqan3::search_cfg::detail::result_type.
output.hpp
Provides the configuration for the content of the search result.
search_result.hpp
Provides seqan3::search_result.
search_scheme_algorithm.hpp
Provides the algorithm to search in an index using search schemes.
template_inspection.hpp
Provides type traits for working with templates.
unidirectional_search_algorithm.hpp
Provides an approximate string matching algorithm based on simple backtracking. This should only be u...
Hide me