osrm-backend/include/engine/datafacade_factory.hpp
2022-12-20 18:00:11 +01:00

156 lines
5.3 KiB
C++

#ifndef OSRM_ENGINE_DATAFACADE_FACTORY_HPP
#define OSRM_ENGINE_DATAFACADE_FACTORY_HPP
#include "extractor/class_data.hpp"
#include "extractor/profile_properties.hpp"
#include "engine/algorithm.hpp"
#include "engine/api/base_parameters.hpp"
#include "engine/api/tile_parameters.hpp"
#include "util/integer_range.hpp"
#include "storage/shared_datatype.hpp"
#include <array>
#include <memory>
#include <unordered_map>
namespace osrm::engine
{
// This class selects the right facade for
template <template <typename A> class FacadeT, typename AlgorithmT> class DataFacadeFactory
{
static constexpr auto has_exclude_flags = routing_algorithms::HasExcludeFlags<AlgorithmT>{};
public:
using Facade = FacadeT<AlgorithmT>;
DataFacadeFactory() = default;
template <typename AllocatorT>
DataFacadeFactory(std::shared_ptr<AllocatorT> allocator)
: DataFacadeFactory(allocator, has_exclude_flags)
{
BOOST_ASSERT_MSG(facades.size() >= 1, "At least one datafacade is needed");
}
template <typename ParameterT> std::shared_ptr<const Facade> Get(const ParameterT &params) const
{
return Get(params, has_exclude_flags);
}
private:
// Algorithm with exclude flags
template <typename AllocatorT>
DataFacadeFactory(std::shared_ptr<AllocatorT> allocator, std::true_type)
{
const auto &index = allocator->GetIndex();
properties = index.template GetBlockPtr<extractor::ProfileProperties>("/common/properties");
const auto &metric_name = properties->GetWeightName();
std::vector<std::string> exclude_prefixes;
auto exclude_path = std::string("/") + routing_algorithms::identifier<AlgorithmT>() +
std::string("/metrics/") + metric_name + "/exclude/";
index.List(exclude_path, std::back_inserter(exclude_prefixes));
facades.resize(exclude_prefixes.size());
if (facades.empty())
{
throw util::exception(std::string("Could not find any metrics for ") +
routing_algorithms::name<AlgorithmT>() +
" in the data. Did you load the right dataset?");
}
for (const auto &exclude_prefix : exclude_prefixes)
{
auto index_begin = exclude_prefix.find_last_of('/');
BOOST_ASSERT_MSG(index_begin != std::string::npos,
"The exclude prefix needs to be a valid data path.");
std::size_t index =
std::stoi(exclude_prefix.substr(index_begin + 1, exclude_prefix.size()));
BOOST_ASSERT(index < facades.size());
facades[index] = std::make_shared<const Facade>(allocator, metric_name, index);
}
for (const auto index : util::irange<std::size_t>(0, properties->class_names.size()))
{
const std::string name = properties->GetClassName(index);
if (!name.empty())
{
name_to_class[name] = extractor::getClassData(index);
}
}
}
// Algorithm without exclude flags
template <typename AllocatorT>
DataFacadeFactory(std::shared_ptr<AllocatorT> allocator, std::false_type)
{
const auto &index = allocator->GetIndex();
properties = index.template GetBlockPtr<extractor::ProfileProperties>("/common/properties");
const auto &metric_name = properties->GetWeightName();
facades.push_back(std::make_shared<const Facade>(allocator, metric_name, 0));
}
std::shared_ptr<const Facade> Get(const api::TileParameters &, std::false_type) const
{
return facades[0];
}
// Default for non-exclude flags: return only facade
std::shared_ptr<const Facade> Get(const api::BaseParameters &params, std::false_type) const
{
if (!params.exclude.empty())
{
return {};
}
return facades[0];
}
// TileParameters don't drive from BaseParameters and generally don't have use for exclude flags
std::shared_ptr<const Facade> Get(const api::TileParameters &, std::true_type) const
{
return facades[0];
}
// Selection logic for finding the corresponding datafacade for the given parameters
std::shared_ptr<const Facade> Get(const api::BaseParameters &params, std::true_type) const
{
if (params.exclude.empty())
return facades[0];
extractor::ClassData mask = 0;
for (const auto &name : params.exclude)
{
auto class_mask_iter = name_to_class.find(name);
if (class_mask_iter == name_to_class.end())
{
return {};
}
else
{
mask |= class_mask_iter->second;
}
}
auto exclude_iter = std::find(
properties->excludable_classes.begin(), properties->excludable_classes.end(), mask);
if (exclude_iter != properties->excludable_classes.end())
{
auto exclude_index =
std::distance(properties->excludable_classes.begin(), exclude_iter);
return facades[exclude_index];
}
return {};
}
std::vector<std::shared_ptr<const Facade>> facades;
std::unordered_map<std::string, extractor::ClassData> name_to_class;
const extractor::ProfileProperties *properties = nullptr;
};
} // namespace osrm::engine
#endif