text: #ifndef CONTIGUOUS_INTERNALMEM_DATAFACADE_HPP
  #define CONTIGUOUS_INTERNALMEM_DATAFACADE_HPP
  
  #include "engine/datafacade/algorithm_datafacade.hpp"
  #include "engine/datafacade/contiguous_block_allocator.hpp"
  #include "engine/datafacade/datafacade_base.hpp"
  
  #include "engine/algorithm.hpp"
  #include "engine/approach.hpp"
  #include "engine/geospatial_query.hpp"
  
  #include "storage/shared_datatype.hpp"
  #include "storage/shared_memory_ownership.hpp"
  #include "storage/view_factory.hpp"
  
  #include "util/exception.hpp"
  #include "util/exception_utils.hpp"
  #include "util/log.hpp"
  
  #include <boost/assert.hpp>
  
  #include <algorithm>
  #include <cstddef>
  #include <iterator>
  #include <limits>
  #include <memory>
  #include <string>
  #include <utility>
  #include <vector>
  
  namespace osrm
  {
  namespace engine
  {
  namespace datafacade
  {
  
  template <typename AlgorithmT> class ContiguousInternalMemoryAlgorithmDataFacade;
  
  template <>
  class ContiguousInternalMemoryAlgorithmDataFacade<CH> : public datafacade::AlgorithmDataFacade<CH>
  {
    private:
      using QueryGraph = util::FilteredGraphView<contractor::QueryGraphView>;
      using GraphNode = QueryGraph::NodeArrayEntry;
      using GraphEdge = QueryGraph::EdgeArrayEntry;
  
      QueryGraph m_query_graph;
  
      // allocator that keeps the allocation data
      std::shared_ptr<ContiguousBlockAllocator> allocator;
  
    public:
      ContiguousInternalMemoryAlgorithmDataFacade(
          std::shared_ptr<ContiguousBlockAllocator> allocator_,
          const std::string &metric_name,
          std::size_t exclude_index)
          : allocator(std::move(allocator_))
      {
          InitializeInternalPointers(allocator->GetIndex(), metric_name, exclude_index);
      }
  
      void InitializeInternalPointers(const storage::SharedDataIndex &index,
                                      const std::string &metric_name,
                                      const std::size_t exclude_index)
      {
          m_query_graph =
              make_filtered_graph_view(index, "/ch/metrics/" + metric_name, exclude_index);
      }
  
      // search graph access
      unsigned GetNumberOfNodes() const override final { return m_query_graph.GetNumberOfNodes(); }
  
      unsigned GetNumberOfEdges() const override final { return m_query_graph.GetNumberOfEdges(); }
  
      unsigned GetOutDegree(const NodeID n) const override final
      {
          return m_query_graph.GetOutDegree(n);
      }
  
      NodeID GetTarget(const EdgeID e) const override final { return m_query_graph.GetTarget(e); }
  
      const EdgeData &GetEdgeData(const EdgeID e) const override final
      {
          return m_query_graph.GetEdgeData(e);
      }
  
      EdgeRange GetAdjacentEdgeRange(const NodeID node) const override final
      {
          return m_query_graph.GetAdjacentEdgeRange(node);
      }
  
      // searches for a specific edge
      EdgeID FindEdge(const NodeID from, const NodeID to) const override final
      {
          return m_query_graph.FindEdge(from, to);
      }
  
      EdgeID FindEdgeInEitherDirection(const NodeID from, const NodeID to) const override final
      {
          return m_query_graph.FindEdgeInEitherDirection(from, to);
      }
  
      EdgeID
      FindEdgeIndicateIfReverse(const NodeID from, const NodeID to, bool &result) const override final
      {
          return m_query_graph.FindEdgeIndicateIfReverse(from, to, result);
      }
  
      EdgeID FindSmallestEdge(const NodeID from,
                              const NodeID to,
                              std::function<bool(EdgeData)> filter) const override final
      {
          return m_query_graph.FindSmallestEdge(from, to, filter);
      }
  };
  
  /**
   * This base class implements the Datafacade interface for accessing
   * data that's stored in a single large block of memory (RAM).
   *
   * In this case "internal memory" refers to RAM - as opposed to "external memory",
   * which usually refers to disk.
   */
  class ContiguousInternalMemoryDataFacadeBase : public BaseDataFacade
  {
    private:
      using super = BaseDataFacade;
      using IndexBlock = util::RangeTable<16, storage::Ownership::View>::BlockT;
      using RTreeLeaf = super::RTreeLeaf;
      using SharedRTree = util::StaticRTree<RTreeLeaf, storage::Ownership::View>;
      using SharedGeospatialQuery = GeospatialQuery<SharedRTree, BaseDataFacade>;
      using RTreeNode = SharedRTree::TreeNode;
  
      extractor::ClassData exclude_mask;
      extractor::ProfileProperties *m_profile_properties;
      extractor::Datasources *m_datasources;
  
      std::uint32_t m_check_sum;
      util::vector_view<util::Coordinate> m_coordinate_list;
      extractor::PackedOSMIDsView m_osmnodeid_list;
      util::vector_view<std::uint32_t> m_lane_description_offsets;
      util::vector_view<extractor::TurnLaneType::Mask> m_lane_description_masks;
      util::vector_view<TurnPenalty> m_turn_weight_penalties;
      util::vector_view<TurnPenalty> m_turn_duration_penalties;
      extractor::SegmentDataView segment_data;
      extractor::EdgeBasedNodeDataView edge_based_node_data;
      guidance::TurnDataView turn_data;
  
      util::vector_view<char> m_datasource_name_data;
      util::vector_view<std::size_t> m_datasource_name_offsets;
      util::vector_view<std::size_t> m_datasource_name_lengths;
      util::vector_view<util::guidance::LaneTupleIdPair> m_lane_tupel_id_pairs;
  
      util::vector_view<extractor::StorageManeuverOverride> m_maneuver_overrides;
      util::vector_view<NodeID> m_maneuver_override_node_sequences;
  
      SharedRTree m_static_rtree;
      std::unique_ptr<SharedGeospatialQuery> m_geospatial_query;
      boost::filesystem::path file_index_path;
  
      extractor::IntersectionBearingsView intersection_bearings_view;
  
      extractor::NameTableView m_name_table;
      // the look-up table for entry classes. An entry class lists the possibility of entry for all
      // available turns. Such a class id is stored with every edge.
      util::vector_view<util::guidance::EntryClass> m_entry_class_table;
  
      // allocator that keeps the allocation data
      std::shared_ptr<ContiguousBlockAllocator> allocator;
  
      void InitializeInternalPointers(const storage::SharedDataIndex &index,
                                      const std::string &metric_name,
                                      const std::size_t exclude_index)
      {
          // TODO: For multi-metric support we need to have separate exclude classes per metric
          (void)metric_name;
  
          m_profile_properties =
              index.GetBlockPtr<extractor::ProfileProperties>("/common/properties");
  
          exclude_mask = m_profile_properties->excludable_classes[exclude_index];
  
          m_check_sum = *index.GetBlockPtr<std::uint32_t>("/common/connectivity_checksum");
  
          std::tie(m_coordinate_list, m_osmnodeid_list) =
              make_nbn_data_view(index, "/common/nbn_data");
  
          m_static_rtree = make_search_tree_view(index, "/common/rtree");
          m_geospatial_query.reset(
              new SharedGeospatialQuery(m_static_rtree, m_coordinate_list, *this));
  
          edge_based_node_data = make_ebn_data_view(index, "/common/ebg_node_data");
  
          turn_data = make_turn_data_view(index, "/common/turn_data");
  
          m_name_table = make_name_table_view(index, "/common/names");
  
          std::tie(m_lane_description_offsets, m_lane_description_masks) =
              make_turn_lane_description_views(index, "/common/turn_lanes");
          m_lane_tupel_id_pairs = make_lane_data_view(index, "/common/turn_lanes");
  
          m_turn_weight_penalties = make_turn_weight_view(index, "/common/turn_penalty");
          m_turn_duration_penalties = make_turn_duration_view(index, "/common/turn_penalty");
  
          segment_data = make_segment_data_view(index, "/common/segment_data");
  
          m_datasources = index.GetBlockPtr<extractor::Datasources>("/common/data_sources_names");
  
          intersection_bearings_view =
              make_intersection_bearings_view(index, "/common/intersection_bearings");
  
          m_entry_class_table = make_entry_classes_view(index, "/common/entry_classes");
  
          std::tie(m_maneuver_overrides, m_maneuver_override_node_sequences) =
              make_maneuver_overrides_views(index, "/common/maneuver_overrides");
      }
  
    public:
      // allows switching between process_memory/shared_memory datafacade, based on the type of
      // allocator
      ContiguousInternalMemoryDataFacadeBase(std::shared_ptr<ContiguousBlockAllocator> allocator_,
                                             const std::string &metric_name,
                                             const std::size_t exclude_index)
          : allocator(std::move(allocator_))
      {
          InitializeInternalPointers(allocator->GetIndex(), metric_name, exclude_index);
      }
  
      // node and edge information access
      util::Coordinate GetCoordinateOfNode(const NodeID id) const override final
      {
          return m_coordinate_list[id];
      }
  
      OSMNodeID GetOSMNodeIDOfNode(const NodeID id) const override final
      {
          return m_osmnodeid_list[id];
      }
  
      NodeForwardRange GetUncompressedForwardGeometry(const EdgeID id) const override final
      {
          return segment_data.GetForwardGeometry(id);
      }
  
      NodeReverseRange GetUncompressedReverseGeometry(const EdgeID id) const override final
      {
          return segment_data.GetReverseGeometry(id);
      }
  
      DurationForwardRange GetUncompressedForwardDurations(const EdgeID id) const override final
      {
          return segment_data.GetForwardDurations(id);
      }
  
      DurationReverseRange GetUncompressedReverseDurations(const EdgeID id) const override final
      {
          return segment_data.GetReverseDurations(id);
      }
  
      WeightForwardRange GetUncompressedForwardWeights(const EdgeID id) const override final
      {
          return segment_data.GetForwardWeights(id);
      }
  
      WeightReverseRange GetUncompressedReverseWeights(const EdgeID id) const override final
      {
          return segment_data.GetReverseWeights(id);
      }
  
      // Returns the data source ids that were used to supply the edge
      // weights.
      DatasourceForwardRange GetUncompressedForwardDatasources(const EdgeID id) const override final
      {
          return segment_data.GetForwardDatasources(id);
      }
  
      // Returns the data source ids that were used to supply the edge
      // weights.
      DatasourceReverseRange GetUncompressedReverseDatasources(const EdgeID id) const override final
      {
          return segment_data.GetReverseDatasources(id);
      }
  
      TurnPenalty GetWeightPenaltyForEdgeID(const EdgeID id) const override final
      {
          BOOST_ASSERT(m_turn_weight_penalties.size() > id);
          return m_turn_weight_penalties[id];
      }
  
      TurnPenalty GetDurationPenaltyForEdgeID(const EdgeID id) const override final
      {
          BOOST_ASSERT(m_turn_duration_penalties.size() > id);
          return m_turn_duration_penalties[id];
      }
  
      osrm::guidance::TurnInstruction
      GetTurnInstructionForEdgeID(const EdgeID id) const override final
      {
          return turn_data.GetTurnInstruction(id);
      }
  
      std::vector<RTreeLeaf> GetEdgesInBox(const util::Coordinate south_west,
                                           const util::Coordinate north_east) const override final
      {
          BOOST_ASSERT(m_geospatial_query.get());
          const util::RectangleInt2D bbox{
              south_west.lon, north_east.lon, south_west.lat, north_east.lat};
          return m_geospatial_query->Search(bbox);
      }
  
      std::vector<PhantomNodeWithDistance>
      NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
                                 const float max_distance,
                                 const Approach approach) const override final
      {
          BOOST_ASSERT(m_geospatial_query.get());
  
          return m_geospatial_query->NearestPhantomNodesInRange(
              input_coordinate, max_distance, approach);
      }
  
      std::vector<PhantomNodeWithDistance>
      NearestPhantomNodesInRange(const util::Coordinate input_coordinate,
                                 const float max_distance,
                                 const int bearing,
                                 const int bearing_range,
                                 const Approach approach) const override final
      {
          BOOST_ASSERT(m_geospatial_query.get());
  
          return m_geospatial_query->NearestPhantomNodesInRange(
              input_coordinate, max_distance, bearing, bearing_range, approach);
      }
  
      std::vector<PhantomNodeWithDistance>
      NearestPhantomNodes(const util::Coordinate input_coordinate,
                          const unsigned max_results,
                          const Approach approach) const override final
      {
          BOOST_ASSERT(m_geospatial_query.get());
  
          return m_geospatial_query->NearestPhantomNodes(input_coordinate, max_results, approach);
      }
  
      std::vector<PhantomNodeWithDistance>
      NearestPhantomNodes(const util::Coordinate input_coordinate,
                          const unsigned max_results,
                          const double max_distance,
                          const Approach approach) const override final
      {
          BOOST_ASSERT(m_geospatial_query.get());
  
          return m_geospatial_query->NearestPhantomNodes(
              input_coordinate, max_results, max_distance, approach);
      }
  
      std::vector<PhantomNodeWithDistance>
      NearestPhantomNodes(const util::Coordinate input_coordinate,
                          const unsigned max_results,
                          const int bearing,
                          const int bearing_range,
                          const Approach approach) const override final
      {
          BOOST_ASSERT(m_geospatial_query.get());
  
          return m_geospatial_query->NearestPhantomNodes(
              input_coordinate, max_results, bearing, bearing_range, approach);
      }
  
      std::vector<PhantomNodeWithDistance>
      NearestPhantomNodes(const util::Coordinate input_coordinate,
                          const unsigned max_results,
                          const double max_distance,
                          const int bearing,
                          const int bearing_range,
                          const Approach approach) const override final
      {
          BOOST_ASSERT(m_geospatial_query.get());
  
          return m_geospatial_query->NearestPhantomNodes(
              input_coordinate, max_results, max_distance, bearing, bearing_range, approach);
      }
  
      std::pair<PhantomNode, PhantomNode>
      NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
                                                        const Approach approach) const override final
      {
          BOOST_ASSERT(m_geospatial_query.get());
  
          return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
              input_coordinate, approach);
      }
  
      std::pair<PhantomNode, PhantomNode>
      NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
                                                        const double max_distance,
                                                        const Approach approach) const override final
      {
          BOOST_ASSERT(m_geospatial_query.get());
  
          return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
              input_coordinate, max_distance, approach);
      }
  
      std::pair<PhantomNode, PhantomNode>
      NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
                                                        const double max_distance,
                                                        const int bearing,
                                                        const int bearing_range,
                                                        const Approach approach) const override final
      {
          BOOST_ASSERT(m_geospatial_query.get());
  
          return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
              input_coordinate, max_distance, bearing, bearing_range, approach);
      }
  
      std::pair<PhantomNode, PhantomNode>
      NearestPhantomNodeWithAlternativeFromBigComponent(const util::Coordinate input_coordinate,
                                                        const int bearing,
                                                        const int bearing_range,
                                                        const Approach approach) const override final
      {
          BOOST_ASSERT(m_geospatial_query.get());
  
          return m_geospatial_query->NearestPhantomNodeWithAlternativeFromBigComponent(
              input_coordinate, bearing, bearing_range, approach);
      }
  
      std::uint32_t GetCheckSum() const override final { return m_check_sum; }
  
      GeometryID GetGeometryIndex(const NodeID id) const override final
      {
          return edge_based_node_data.GetGeometryID(id);
      }
  
      ComponentID GetComponentID(const NodeID id) const override final
      {
          return edge_based_node_data.GetComponentID(id);
      }
  
      extractor::TravelMode GetTravelMode(const NodeID id) const override final
      {
          return edge_based_node_data.GetTravelMode(id);
      }
  
      extractor::ClassData GetClassData(const NodeID id) const override final
      {
          return edge_based_node_data.GetClassData(id);
      }
  
      bool ExcludeNode(const NodeID id) const override final
      {
          return (edge_based_node_data.GetClassData(id) & exclude_mask) > 0;
      }
  
      std::vector<std::string> GetClasses(const extractor::ClassData class_data) const override final
      {
          auto indexes = extractor::getClassIndexes(class_data);
          std::vector<std::string> classes(indexes.size());
          std::transform(indexes.begin(), indexes.end(), classes.begin(), [this](const auto index) {
              return m_profile_properties->GetClassName(index);
          });
  
          return classes;
      }
  
      NameID GetNameIndex(const NodeID id) const override final
      {
          return edge_based_node_data.GetNameID(id);
      }
  
      StringView GetNameForID(const NameID id) const override final
      {
          return m_name_table.GetNameForID(id);
      }
  
      StringView GetRefForID(const NameID id) const override final
      {
          return m_name_table.GetRefForID(id);
      }
  
      StringView GetPronunciationForID(const NameID id) const override final
      {
          return m_name_table.GetPronunciationForID(id);
      }
  
      StringView GetDestinationsForID(const NameID id) const override final
      {
          return m_name_table.GetDestinationsForID(id);
      }
  
      StringView GetExitsForID(const NameID id) const override final
      {
          return m_name_table.GetExitsForID(id);
      }
  
      StringView GetDatasourceName(const DatasourceID id) const override final
      {
          return m_datasources->GetSourceName(id);
      }
  
      bool GetContinueStraightDefault() const override final
      {
          return m_profile_properties->continue_straight_at_waypoint;
      }
  
      double GetMapMatchingMaxSpeed() const override final
      {
          return m_profile_properties->max_speed_for_map_matching;
      }
  
      const char *GetWeightName() const override final { return m_profile_properties->weight_name; }
  
      unsigned GetWeightPrecision() const override final
      {
          return m_profile_properties->weight_precision;
      }
  
      double GetWeightMultiplier() const override final
      {
          return m_profile_properties->GetWeightMultiplier();
      }
  
      util::guidance::BearingClass GetBearingClass(const NodeID node) const override final
      {
          return intersection_bearings_view.GetBearingClass(node);
      }
  
      guidance::TurnBearing PreTurnBearing(const EdgeID eid) const override final
      {
          return turn_data.GetPreTurnBearing(eid);
      }
      guidance::TurnBearing PostTurnBearing(const EdgeID eid) const override final
      {
          return turn_data.GetPostTurnBearing(eid);
      }
  
      util::guidance::EntryClass GetEntryClass(const EdgeID turn_id) const override final
      {
          auto entry_class_id = turn_data.GetEntryClassID(turn_id);
          return m_entry_class_table.at(entry_class_id);
      }
  
      bool HasLaneData(const EdgeID id) const override final { return turn_data.HasLaneData(id); }
  
      util::guidance::LaneTupleIdPair GetLaneData(const EdgeID id) const override final
      {
          BOOST_ASSERT(HasLaneData(id));
          return m_lane_tupel_id_pairs.at(turn_data.GetLaneDataID(id));
      }
  
      extractor::TurnLaneDescription
      GetTurnDescription(const LaneDescriptionID lane_description_id) const override final
      {
          if (lane_description_id == INVALID_LANE_DESCRIPTIONID)
              return {};
          else
              return extractor::TurnLaneDescription(
                  m_lane_description_masks.begin() + m_lane_description_offsets[lane_description_id],
                  m_lane_description_masks.begin() +
                      m_lane_description_offsets[lane_description_id + 1]);
      }
  
      bool IsLeftHandDriving(const NodeID id) const override final
      {
          // TODO: can be moved to a data block indexed by GeometryID
          return edge_based_node_data.IsLeftHandDriving(id);
      }
  
      bool IsSegregated(const NodeID id) const override final
      {
          return edge_based_node_data.IsSegregated(id);
      }
  
      std::vector<extractor::ManeuverOverride>
      GetOverridesThatStartAt(const NodeID edge_based_node_id) const override final
      {
          std::vector<extractor::ManeuverOverride> results;
  
          // heterogeneous comparison:
          struct Comp
          {
              bool operator()(const extractor::StorageManeuverOverride &s, NodeID i) const
              {
                  return s.start_node < i;
              }
              bool operator()(NodeID i, const extractor::StorageManeuverOverride &s) const
              {
                  return i < s.start_node;
              }
          };
  
          auto found_range = std::equal_range(
              m_maneuver_overrides.begin(), m_maneuver_overrides.end(), edge_based_node_id, Comp{});
  
          std::for_each(found_range.first, found_range.second, [&](const auto & override) {
              std::vector<NodeID> sequence(
                  m_maneuver_override_node_sequences.begin() + override.node_sequence_offset_begin,
                  m_maneuver_override_node_sequences.begin() + override.node_sequence_offset_end);
              results.push_back(extractor::ManeuverOverride{std::move(sequence),
                                                            override.instruction_node,
                                                            override.override_type,
                                                            override.direction});
          });
          return results;
      }
  };
  
  template <typename AlgorithmT> class ContiguousInternalMemoryDataFacade;
  
  template <>
  class ContiguousInternalMemoryDataFacade<CH>
      : public ContiguousInternalMemoryDataFacadeBase,
        public ContiguousInternalMemoryAlgorithmDataFacade<CH>
  {
    public:
      ContiguousInternalMemoryDataFacade(std::shared_ptr<ContiguousBlockAllocator> allocator,
                                         const std::string &metric_name,
                                         const std::size_t exclude_index)
          : ContiguousInternalMemoryDataFacadeBase(allocator, metric_name, exclude_index),
            ContiguousInternalMemoryAlgorithmDataFacade<CH>(allocator, metric_name, exclude_index)
      {
      }
  };
  
  template <> class ContiguousInternalMemoryAlgorithmDataFacade<MLD> : public AlgorithmDataFacade<MLD>
  {
      // MLD data
      partitioner::MultiLevelPartitionView mld_partition;
      partitioner::CellStorageView mld_cell_storage;
      customizer::CellMetricView mld_cell_metric;
      using QueryGraph = customizer::MultiLevelEdgeBasedGraphView;
      using GraphNode = QueryGraph::NodeArrayEntry;
      using GraphEdge = QueryGraph::EdgeArrayEntry;
  
      QueryGraph query_graph;
  
      void InitializeInternalPointers(const storage::SharedDataIndex &index,
                                      const std::string &metric_name,
                                      const std::size_t exclude_index)
      {
          mld_partition = make_partition_view(index, "/mld/multilevelpartition");
          mld_cell_metric =
              make_filtered_cell_metric_view(index, "/mld/metrics/" + metric_name, exclude_index);
          mld_cell_storage = make_cell_storage_view(index, "/mld/cellstorage");
          query_graph = make_multi_level_graph_view(index, "/mld/multilevelgraph");
      }
  
      // allocator that keeps the allocation data
      std::shared_ptr<ContiguousBlockAllocator> allocator;
  
    public:
      ContiguousInternalMemoryAlgorithmDataFacade(
          std::shared_ptr<ContiguousBlockAllocator> allocator_,
          const std::string &metric_name,
          const std::size_t exclude_index)
          : allocator(std::move(allocator_))
      {
          InitializeInternalPointers(allocator->GetIndex(), metric_name, exclude_index);
      }
  
      const partitioner::MultiLevelPartitionView &GetMultiLevelPartition() const override
      {
          return mld_partition;
      }
  
      const partitioner::CellStorageView &GetCellStorage() const override { return mld_cell_storage; }
  
      const customizer::CellMetricView &GetCellMetric() const override { return mld_cell_metric; }
  
      // search graph access
      unsigned GetNumberOfNodes() const override final { return query_graph.GetNumberOfNodes(); }
  
      unsigned GetMaxBorderNodeID() const override final { return query_graph.GetMaxBorderNodeID(); }
  
      unsigned GetNumberOfEdges() const override final { return query_graph.GetNumberOfEdges(); }
  
      unsigned GetOutDegree(const NodeID n) const override final
      {
          return query_graph.GetOutDegree(n);
      }
  
      EdgeRange GetAdjacentEdgeRange(const NodeID node) const override final
      {
          return query_graph.GetAdjacentEdgeRange(node);
      }
  
      EdgeWeight GetNodeWeight(const NodeID node) const override final
      {
          return query_graph.GetNodeWeight(node);
      }
  
      EdgeDuration GetNodeDuration(const NodeID node) const override final
      {
          return query_graph.GetNodeDuration(node);
      }
  
      EdgeDistance GetNodeDistance(const NodeID node) const override final
      {
          return query_graph.GetNodeDistance(node);
      }
  
      bool IsForwardEdge(const NodeID node) const override final
      {
          return query_graph.IsForwardEdge(node);
      }
  
      bool IsBackwardEdge(const NodeID node) const override final
      {
          return query_graph.IsBackwardEdge(node);
      }
  
      NodeID GetTarget(const EdgeID e) const override final { return query_graph.GetTarget(e); }
  
      const EdgeData &GetEdgeData(const EdgeID e) const override final
      {
          return query_graph.GetEdgeData(e);
      }
  
      EdgeRange GetBorderEdgeRange(const LevelID level, const NodeID node) const override final
      {
          return query_graph.GetBorderEdgeRange(level, node);
      }
  
      // searches for a specific edge
      EdgeID FindEdge(const NodeID from, const NodeID to) const override final
      {
          return query_graph.FindEdge(from, to);
      }
  };
  
  template <>
  class ContiguousInternalMemoryDataFacade<MLD> final
      : public ContiguousInternalMemoryDataFacadeBase,
        public ContiguousInternalMemoryAlgorithmDataFacade<MLD>
  {
    private:
    public:
      ContiguousInternalMemoryDataFacade(std::shared_ptr<ContiguousBlockAllocator> allocator,
                                         const std::string &metric_name,
                                         const std::size_t exclude_index)
          : ContiguousInternalMemoryDataFacadeBase(allocator, metric_name, exclude_index),
            ContiguousInternalMemoryAlgorithmDataFacade<MLD>(allocator, metric_name, exclude_index)
      {
      }
  };
  }
  }
  }
  
  #endif // CONTIGUOUS_INTERNALMEM_DATAFACADE_HPP
  