From 45bfe937aaef1424bba4e1bff581dcbcceda6613 Mon Sep 17 00:00:00 2001 From: Mugr Rex Date: Thu, 20 Apr 2023 16:04:04 +0200 Subject: [PATCH 1/9] Final merge commit --- CHANGELOG.md | 1 + .../intersection/node_based_graph_walker.hpp | 46 +++++++++---------- .../maneuver_override_relation_parser.hpp | 4 +- include/extractor/profile_properties.hpp | 4 +- include/guidance/intersection_handler.hpp | 5 +- include/guidance/sliproad_handler.hpp | 9 ++-- include/guidance/turn_handler.hpp | 7 ++- include/nodejs/node_osrm_support.hpp | 8 ++-- include/util/coordinate_calculation.hpp | 8 ++-- include/util/geojson_debug_policies.hpp | 11 ++--- include/util/geojson_debug_policy_toolkit.hpp | 5 +- include/util/query_heap.hpp | 14 +++--- include/util/timezones.hpp | 4 +- .../intersection/node_based_graph_walker.cpp | 6 +-- .../maneuver_override_relation_parser.cpp | 8 ++-- src/guidance/intersection_handler.cpp | 9 ++-- src/guidance/sliproad_handler.cpp | 18 ++++---- src/guidance/turn_handler.cpp | 12 ++--- src/util/coordinate_calculation.cpp | 11 +++-- src/util/geojson_debug_policies.cpp | 8 ++-- src/util/timezones.cpp | 6 +-- 21 files changed, 100 insertions(+), 104 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 83e1fab4e83..7a4430434ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - NodeJS: - CHANGED: Use node-api instead of NAN. [#6452](https://github.com/Project-OSRM/osrm-backend/pull/6452) - Misc: + - FIXED: Partial fix migration from boost::optional to std::optional [#6551](https://github.com/Project-OSRM/osrm-backend/issues/6551), see also [#6592](https://github.com/Project-OSRM/osrm-backend/issues/6592) - CHANGED: keep libosrm* in the docker image for downstream linking [#6602](https://github.com/Project-OSRM/osrm-backend/pull/6602) - CHANGED: Move vector in CSVFilesParser instead copying it. [#6470](https://github.com/Project-OSRM/osrm-backend/pull/6470) - REMOVED: Get rid of unused functions in util/json_util.hpp. [#6446](https://github.com/Project-OSRM/osrm-backend/pull/6446) diff --git a/include/extractor/intersection/node_based_graph_walker.hpp b/include/extractor/intersection/node_based_graph_walker.hpp index 869e934bcf9..f3915ee9f1e 100644 --- a/include/extractor/intersection/node_based_graph_walker.hpp +++ b/include/extractor/intersection/node_based_graph_walker.hpp @@ -11,8 +11,8 @@ #include "util/typedefs.hpp" #include -#include #include +#include #include namespace osrm::extractor::intersection @@ -42,10 +42,10 @@ class NodeBasedGraphWalker * selector not provinding any further edge to traverse) */ template - boost::optional> TraverseRoad(NodeID starting_at_node_id, - EdgeID following_edge_id, - accumulator_type &accumulator, - const selector_type &selector) const; + std::optional> TraverseRoad(NodeID starting_at_node_id, + EdgeID following_edge_id, + accumulator_type &accumulator, + const selector_type &selector) const; private: const util::NodeBasedDynamicGraph &node_based_graph; @@ -111,11 +111,11 @@ struct SelectRoadByNameOnlyChoiceAndStraightness * traversal. If no such edge is found, return {} is allowed. Usually you want to choose some * form of obious turn to follow. */ - boost::optional operator()(const NodeID nid, - const EdgeID via_edge_id, - const IntersectionView &intersection, - const util::NodeBasedDynamicGraph &node_based_graph, - const EdgeBasedNodeDataContainer &node_data_container) const; + std::optional operator()(const NodeID nid, + const EdgeID via_edge_id, + const IntersectionView &intersection, + const util::NodeBasedDynamicGraph &node_based_graph, + const EdgeBasedNodeDataContainer &node_data_container) const; private: const NameID desired_name_id; @@ -138,11 +138,11 @@ struct SelectStraightmostRoadByNameAndOnlyChoice * traversal. If no such edge is found, return {} is allowed. Usually you want to choose some * form of obious turn to follow. */ - boost::optional operator()(const NodeID nid, - const EdgeID via_edge_id, - const IntersectionView &intersection, - const util::NodeBasedDynamicGraph &node_based_graph, - const EdgeBasedNodeDataContainer &node_data_container) const; + std::optional operator()(const NodeID nid, + const EdgeID via_edge_id, + const IntersectionView &intersection, + const util::NodeBasedDynamicGraph &node_based_graph, + const EdgeBasedNodeDataContainer &node_data_container) const; private: const NameID desired_name_id; @@ -187,7 +187,7 @@ struct IntersectionFinderAccumulator }; template -boost::optional> +std::optional> NodeBasedGraphWalker::TraverseRoad(NodeID current_node_id, EdgeID current_edge_id, accumulator_type &accumulator, @@ -254,19 +254,19 @@ NodeBasedGraphWalker::TraverseRoad(NodeID current_node_id, struct SkipTrafficSignalBarrierRoadSelector { - boost::optional operator()(const NodeID, - const EdgeID, - const IntersectionView &intersection, - const util::NodeBasedDynamicGraph &, - const EdgeBasedNodeDataContainer &) const + std::optional operator()(const NodeID, + const EdgeID, + const IntersectionView &intersection, + const util::NodeBasedDynamicGraph &, + const EdgeBasedNodeDataContainer &) const { if (intersection.isTrafficSignalOrBarrier()) { - return boost::make_optional(intersection[1].eid); + return std::make_optional(intersection[1].eid); } else { - return boost::none; + return std::nullopt; } } }; diff --git a/include/extractor/maneuver_override_relation_parser.hpp b/include/extractor/maneuver_override_relation_parser.hpp index df4b93a3d0a..c6084ad70ec 100644 --- a/include/extractor/maneuver_override_relation_parser.hpp +++ b/include/extractor/maneuver_override_relation_parser.hpp @@ -3,7 +3,7 @@ #include "maneuver_override.hpp" -#include +#include #include #include @@ -55,7 +55,7 @@ class ManeuverOverrideRelationParser { public: ManeuverOverrideRelationParser(); - boost::optional TryParse(const osmium::Relation &relation) const; + std::optional TryParse(const osmium::Relation &relation) const; }; } // namespace osrm::extractor diff --git a/include/extractor/profile_properties.hpp b/include/extractor/profile_properties.hpp index 817e7b763ab..371155b17fc 100644 --- a/include/extractor/profile_properties.hpp +++ b/include/extractor/profile_properties.hpp @@ -7,11 +7,11 @@ #include #include -#include #include #include #include +#include namespace osrm::extractor { @@ -80,7 +80,7 @@ struct ProfileProperties } // Check if this classes are excludable - boost::optional ClassesAreExcludable(ClassData classes) const + std::optional ClassesAreExcludable(ClassData classes) const { auto iter = std::find(excludable_classes.begin(), excludable_classes.end(), classes); if (iter != excludable_classes.end()) diff --git a/include/guidance/intersection_handler.hpp b/include/guidance/intersection_handler.hpp index dcd62d4cbbe..2c922510bfd 100644 --- a/include/guidance/intersection_handler.hpp +++ b/include/guidance/intersection_handler.hpp @@ -15,11 +15,10 @@ #include #include +#include #include #include -#include - namespace osrm::guidance { @@ -129,7 +128,7 @@ class IntersectionHandler // ^ via // // For this scenario returns intersection at `b` and `b`. - boost::optional + std::optional getNextIntersection(const NodeID at, const EdgeID via) const; bool isSameName(const EdgeID source_edge_id, const EdgeID target_edge_id) const; diff --git a/include/guidance/sliproad_handler.hpp b/include/guidance/sliproad_handler.hpp index a75f70a520c..533ac4dcfb2 100644 --- a/include/guidance/sliproad_handler.hpp +++ b/include/guidance/sliproad_handler.hpp @@ -9,10 +9,9 @@ #include "util/node_based_graph.hpp" +#include #include -#include - namespace osrm::guidance { @@ -43,9 +42,9 @@ class SliproadHandler final : public IntersectionHandler Intersection intersection) const override final; private: - boost::optional getObviousIndexWithSliproads(const EdgeID from, - const Intersection &intersection, - const NodeID at) const; + std::optional getObviousIndexWithSliproads(const EdgeID from, + const Intersection &intersection, + const NodeID at) const; // Next intersection from `start` onto `onto` is too far away for a Siproad scenario bool nextIntersectionIsTooFarAway(const NodeID start, const EdgeID onto) const; diff --git a/include/guidance/turn_handler.hpp b/include/guidance/turn_handler.hpp index d3e25c79a19..6a52109925f 100644 --- a/include/guidance/turn_handler.hpp +++ b/include/guidance/turn_handler.hpp @@ -11,9 +11,8 @@ #include "util/attributes.hpp" #include "util/node_based_graph.hpp" -#include - #include +#include #include #include @@ -72,7 +71,7 @@ class TurnHandler final : public IntersectionHandler bool hasObvious(const EdgeID &via_edge, const Fork &fork) const; - boost::optional findForkCandidatesByGeometry(Intersection &intersection) const; + std::optional findForkCandidatesByGeometry(Intersection &intersection) const; bool isCompatibleByRoadClass(const Intersection &intersection, const Fork fork) const; @@ -96,7 +95,7 @@ class TurnHandler final : public IntersectionHandler handleDistinctConflict(const EdgeID via_edge, ConnectedRoad &left, ConnectedRoad &right) const; // Classification - boost::optional findFork(const EdgeID via_edge, Intersection &intersection) const; + std::optional findFork(const EdgeID via_edge, Intersection &intersection) const; OSRM_ATTR_WARN_UNUSED Intersection assignLeftTurns(const EdgeID via_edge, diff --git a/include/nodejs/node_osrm_support.hpp b/include/nodejs/node_osrm_support.hpp index 5296dc4ed3b..4074d984e18 100644 --- a/include/nodejs/node_osrm_support.hpp +++ b/include/nodejs/node_osrm_support.hpp @@ -21,11 +21,11 @@ #include #include -#include #include #include #include +#include #include #include #include @@ -345,11 +345,11 @@ inline engine_config_ptr argumentsToEngineConfig(const Napi::CallbackInfo &args) return engine_config; } -inline boost::optional> +inline std::optional> parseCoordinateArray(const Napi::Array &coordinates_array) { Napi::HandleScope scope(coordinates_array.Env()); - boost::optional> resulting_coordinates; + std::optional> resulting_coordinates; std::vector temp_coordinates; for (uint32_t i = 0; i < coordinates_array.Length(); ++i) @@ -968,7 +968,7 @@ inline bool parseCommonParameters(const Napi::Object &obj, ParamType ¶ms) inline PluginParameters argumentsToPluginParameters( const Napi::CallbackInfo &args, - const boost::optional &output_format = {}) + const std::optional &output_format = {}) { if (args.Length() < 3 || !args[1].IsObject()) { diff --git a/include/util/coordinate_calculation.hpp b/include/util/coordinate_calculation.hpp index 4ebbafa5c52..53c803a1900 100644 --- a/include/util/coordinate_calculation.hpp +++ b/include/util/coordinate_calculation.hpp @@ -4,11 +4,11 @@ #include "util/coordinate.hpp" #include -#include #include #include #include +#include #include #include @@ -102,9 +102,9 @@ double bearing(const Coordinate first_coordinate, const Coordinate second_coordi double computeAngle(const Coordinate first, const Coordinate second, const Coordinate third); // find the center of a circle through three coordinates -boost::optional circleCenter(const Coordinate first_coordinate, - const Coordinate second_coordinate, - const Coordinate third_coordinate); +std::optional circleCenter(const Coordinate first_coordinate, + const Coordinate second_coordinate, + const Coordinate third_coordinate); // find the radius of a circle through three coordinates double circleRadius(const Coordinate first_coordinate, diff --git a/include/util/geojson_debug_policies.hpp b/include/util/geojson_debug_policies.hpp index 3a209db0ac2..0f25badd0f4 100644 --- a/include/util/geojson_debug_policies.hpp +++ b/include/util/geojson_debug_policies.hpp @@ -1,6 +1,7 @@ #ifndef OSRM_GEOJSON_DEBUG_POLICIES #define OSRM_GEOJSON_DEBUG_POLICIES +#include #include #include "extractor/query_node.hpp" @@ -9,8 +10,6 @@ #include "util/node_based_graph.hpp" #include "util/typedefs.hpp" -#include - namespace osrm::util { @@ -20,7 +19,7 @@ struct NodeIdVectorToLineString // converts a vector of node ids into a linestring geojson feature util::json::Object operator()(const std::vector &node_ids, - const boost::optional &properties = {}) const; + const std::optional &properties = {}) const; const std::vector &node_coordinates; }; @@ -29,7 +28,7 @@ struct CoordinateVectorToLineString { // converts a vector of node ids into a linestring geojson feature util::json::Object operator()(const std::vector &coordinates, - const boost::optional &properties = {}) const; + const std::optional &properties = {}) const; }; struct NodeIdVectorToMultiPoint @@ -38,7 +37,7 @@ struct NodeIdVectorToMultiPoint // converts a vector of node ids into a linestring geojson feature util::json::Object operator()(const std::vector &node_ids, - const boost::optional &properties = {}) const; + const std::optional &properties = {}) const; const std::vector &node_coordinates; }; @@ -47,7 +46,7 @@ struct CoordinateVectorToMultiPoint { // converts a vector of node ids into a linestring geojson feature util::json::Object operator()(const std::vector &coordinates, - const boost::optional &properties = {}) const; + const std::optional &properties = {}) const; }; } // namespace osrm::util diff --git a/include/util/geojson_debug_policy_toolkit.hpp b/include/util/geojson_debug_policy_toolkit.hpp index 62c1019ef1f..fcddc21a1a2 100644 --- a/include/util/geojson_debug_policy_toolkit.hpp +++ b/include/util/geojson_debug_policy_toolkit.hpp @@ -7,8 +7,7 @@ #include #include - -#include +#include namespace osrm::util { @@ -84,7 +83,7 @@ struct NodeIdToCoordinate inline util::json::Object makeFeature(std::string type, util::json::Array coordinates, - const boost::optional &properties = {}) + const std::optional &properties = {}) { util::json::Object result; result.values["type"] = "Feature"; diff --git a/include/util/query_heap.hpp b/include/util/query_heap.hpp index 463323efe87..f481a78f065 100644 --- a/include/util/query_heap.hpp +++ b/include/util/query_heap.hpp @@ -3,11 +3,11 @@ #include #include -#include #include #include #include +#include #include #include @@ -289,26 +289,26 @@ class QueryHeap return inserted_nodes[index].node == node; } - boost::optional GetHeapNodeIfWasInserted(const NodeID node) + HeapNode *GetHeapNodeIfWasInserted(const NodeID node) { const auto index = node_index.peek_index(node); if (index >= static_cast(inserted_nodes.size()) || inserted_nodes[index].node != node) { - return {}; + return nullptr; } - return inserted_nodes[index]; + return &inserted_nodes[index]; } - boost::optional GetHeapNodeIfWasInserted(const NodeID node) const + const HeapNode *GetHeapNodeIfWasInserted(const NodeID node) const { const auto index = node_index.peek_index(node); if (index >= static_cast(inserted_nodes.size()) || inserted_nodes[index].node != node) { - return {}; + return nullptr; } - return inserted_nodes[index]; + return &inserted_nodes[index]; } NodeID Min() const diff --git a/include/util/timezones.hpp b/include/util/timezones.hpp index ff6b0bc988d..8105aaae47c 100644 --- a/include/util/timezones.hpp +++ b/include/util/timezones.hpp @@ -6,11 +6,11 @@ #include #include #include -#include #include #include +#include namespace osrm::updater { @@ -34,7 +34,7 @@ class Timezoner Timezoner(const char geojson[], std::time_t utc_time_now); Timezoner(const boost::filesystem::path &tz_shapes_filename, std::time_t utc_time_now); - boost::optional operator()(const point_t &point) const; + std::optional operator()(const point_t &point) const; private: void LoadLocalTimesRTree(rapidjson::Document &geojson, std::time_t utc_time); diff --git a/src/extractor/intersection/node_based_graph_walker.cpp b/src/extractor/intersection/node_based_graph_walker.cpp index 72dd8ff2342..46208fb2ba4 100644 --- a/src/extractor/intersection/node_based_graph_walker.cpp +++ b/src/extractor/intersection/node_based_graph_walker.cpp @@ -66,7 +66,7 @@ SelectRoadByNameOnlyChoiceAndStraightness::SelectRoadByNameOnlyChoiceAndStraight { } -boost::optional SelectRoadByNameOnlyChoiceAndStraightness::operator()( +std::optional SelectRoadByNameOnlyChoiceAndStraightness::operator()( const NodeID /*nid*/, const EdgeID /*via_edge_id*/, const IntersectionView &intersection, @@ -116,7 +116,7 @@ SelectStraightmostRoadByNameAndOnlyChoice::SelectStraightmostRoadByNameAndOnlyCh { } -boost::optional SelectStraightmostRoadByNameAndOnlyChoice::operator()( +std::optional SelectStraightmostRoadByNameAndOnlyChoice::operator()( const NodeID /*nid*/, const EdgeID /*via_edge_id*/, const IntersectionView &intersection, @@ -234,7 +234,7 @@ boost::optional SelectStraightmostRoadByNameAndOnlyChoice::operator()( return {}; } - return is_only_choice_with_same_name ? boost::optional(min_element->eid) : boost::none; + return is_only_choice_with_same_name ? std::optional(min_element->eid) : std::nullopt; } // --------------------------------------------------------------------------------- diff --git a/src/extractor/maneuver_override_relation_parser.cpp b/src/extractor/maneuver_override_relation_parser.cpp index 737edf670d2..a0fcb2d1a24 100644 --- a/src/extractor/maneuver_override_relation_parser.cpp +++ b/src/extractor/maneuver_override_relation_parser.cpp @@ -1,9 +1,9 @@ #include "extractor/maneuver_override_relation_parser.hpp" #include "extractor/maneuver_override.hpp" -#include #include +#include #include #include #include @@ -21,7 +21,7 @@ ManeuverOverrideRelationParser::ManeuverOverrideRelationParser() {} * into an InputManeuverOverride object, if the relation is considered * valid (i.e. has the minimum tags we expect). */ -boost::optional +std::optional ManeuverOverrideRelationParser::TryParse(const osmium::Relation &relation) const { @@ -35,7 +35,7 @@ ManeuverOverrideRelationParser::TryParse(const osmium::Relation &relation) const if (osmium::tags::match_none_of(tag_list, filter)) // if it's not a maneuver, continue; { - return boost::none; + return std::nullopt; } // we pretend every restriction is a conditional restriction. If we do not find any restriction, @@ -130,7 +130,7 @@ ManeuverOverrideRelationParser::TryParse(const osmium::Relation &relation) const } else { - return boost::none; + return std::nullopt; } return maneuver_override; } diff --git a/src/guidance/intersection_handler.cpp b/src/guidance/intersection_handler.cpp index 6cbd016a01f..197f280149c 100644 --- a/src/guidance/intersection_handler.cpp +++ b/src/guidance/intersection_handler.cpp @@ -426,7 +426,7 @@ void IntersectionHandler::assignTrivialTurns(const EdgeID via_eid, } } -boost::optional +std::optional IntersectionHandler::getNextIntersection(const NodeID at, const EdgeID via) const { // We use the intersection generator to jump over traffic signals, barriers. The intersection @@ -449,7 +449,7 @@ IntersectionHandler::getNextIntersection(const NodeID at, const EdgeID via) cons if (intersection_parameters.node == SPECIAL_NODEID || intersection_parameters.edge == SPECIAL_EDGEID) { - return boost::none; + return {}; } auto intersection = extractor::intersection::getConnectedRoads(node_based_graph, @@ -464,11 +464,10 @@ IntersectionHandler::getNextIntersection(const NodeID at, const EdgeID via) cons if (intersection.size() <= 2 || intersection.isTrafficSignalOrBarrier()) { - return boost::none; + return {}; } - return boost::make_optional( - IntersectionViewAndNode{std::move(intersection), intersection_node}); + return std::make_optional(IntersectionViewAndNode{std::move(intersection), intersection_node}); } bool IntersectionHandler::isSameName(const EdgeID source_edge_id, const EdgeID target_edge_id) const diff --git a/src/guidance/sliproad_handler.cpp b/src/guidance/sliproad_handler.cpp index 702bdf59a38..0d0d6695e59 100644 --- a/src/guidance/sliproad_handler.cpp +++ b/src/guidance/sliproad_handler.cpp @@ -627,7 +627,7 @@ Intersection SliproadHandler::operator()(const NodeID /*nid*/, // Implementation details -boost::optional SliproadHandler::getObviousIndexWithSliproads( +std::optional SliproadHandler::getObviousIndexWithSliproads( const EdgeID from, const Intersection &intersection, const NodeID at) const { BOOST_ASSERT(from != SPECIAL_EDGEID); @@ -638,14 +638,14 @@ boost::optional SliproadHandler::getObviousIndexWithSliproads( if (index != 0) { - return boost::make_optional(index); + return std::make_optional(index); } // Otherwise check if the road is forking into two and one of them is a Sliproad; // then the non-Sliproad is the obvious one. if (intersection.size() != 3) { - return boost::none; + return {}; } const auto forking = intersection[1].instruction.type == TurnType::Fork && @@ -653,7 +653,7 @@ boost::optional SliproadHandler::getObviousIndexWithSliproads( if (!forking) { - return boost::none; + return {}; } const auto first = getNextIntersection(at, intersection.getRightmostRoad().eid); @@ -661,27 +661,27 @@ boost::optional SliproadHandler::getObviousIndexWithSliproads( if (!first || !second) { - return boost::none; + return {}; } if (first->intersection.isDeadEnd() || second->intersection.isDeadEnd()) { - return boost::none; + return {}; } // In case of loops at the end of the road, we will arrive back at the intersection // itself. If that is the case, the road is obviously not a sliproad. if (canBeTargetOfSliproad(first->intersection) && at != second->node) { - return boost::make_optional(std::size_t{2}); + return std::make_optional(std::size_t{2}); } if (canBeTargetOfSliproad(second->intersection) && at != first->node) { - return boost::make_optional(std::size_t{1}); + return std::make_optional(std::size_t{1}); } - return boost::none; + return {}; } bool SliproadHandler::nextIntersectionIsTooFarAway(const NodeID start, const EdgeID onto) const diff --git a/src/guidance/turn_handler.cpp b/src/guidance/turn_handler.cpp index b13cbf1c927..10038ba21b3 100644 --- a/src/guidance/turn_handler.cpp +++ b/src/guidance/turn_handler.cpp @@ -6,10 +6,10 @@ #include #include +#include #include #include -#include using osrm::util::angularDeviation; @@ -585,7 +585,7 @@ Intersection TurnHandler::assignRightTurns(const EdgeID via_edge, } // finds a fork candidate by just looking at the geometry and angle of an intersection -boost::optional +std::optional TurnHandler::findForkCandidatesByGeometry(Intersection &intersection) const { if (intersection.size() >= 3) @@ -642,7 +642,7 @@ TurnHandler::findForkCandidatesByGeometry(Intersection &intersection) const } } } - return boost::none; + return {}; } // check if the fork candidates (all roads between left and right) and the @@ -678,8 +678,8 @@ bool TurnHandler::isCompatibleByRoadClass(const Intersection &intersection, cons // Checks whether a three-way-intersection coming from `via_edge` is a fork // with `intersection` as described as in #IntersectionExplanation@intersection_handler.hpp -boost::optional TurnHandler::findFork(const EdgeID via_edge, - Intersection &intersection) const +std::optional TurnHandler::findFork(const EdgeID via_edge, + Intersection &intersection) const { auto fork = findForkCandidatesByGeometry(intersection); if (fork) @@ -720,7 +720,7 @@ boost::optional TurnHandler::findFork(const EdgeID via_edge, } } - return boost::none; + return {}; } void TurnHandler::handleDistinctConflict(const EdgeID via_edge, diff --git a/src/util/coordinate_calculation.cpp b/src/util/coordinate_calculation.cpp index 3bc17266448..4686a9827d0 100644 --- a/src/util/coordinate_calculation.cpp +++ b/src/util/coordinate_calculation.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include namespace osrm::util::coordinate_calculation @@ -173,14 +174,14 @@ double computeAngle(const Coordinate first, const Coordinate second, const Coord return angle; } -boost::optional +std::optional circleCenter(const Coordinate C1, const Coordinate C2, const Coordinate C3) { // free after http://paulbourke.net/geometry/circlesphere/ // require three distinct points if (C1 == C2 || C2 == C3 || C1 == C3) { - return boost::none; + return {}; } // define line through c1, c2 and c2,c3 @@ -195,7 +196,7 @@ circleCenter(const Coordinate C1, const Coordinate C2, const Coordinate C3) (std::abs(C2C1_lat) < std::numeric_limits::epsilon() && std::abs(C3C2_lat) < std::numeric_limits::epsilon())) { - return boost::none; + return {}; } else if (std::abs(C2C1_lon) < std::numeric_limits::epsilon()) { @@ -233,7 +234,7 @@ circleCenter(const Coordinate C1, const Coordinate C2, const Coordinate C3) // can this ever happen? if (std::abs(C2C1_slope - C3C2_slope) < std::numeric_limits::epsilon()) - return boost::none; + return {}; const double C1_y = static_cast(toFloating(C1.lat)); const double C1_x = static_cast(toFloating(C1.lon)); @@ -247,7 +248,7 @@ circleCenter(const Coordinate C1, const Coordinate C2, const Coordinate C3) (2 * (C3C2_slope - C2C1_slope)); const double lat = (0.5 * (C1_x + C2_x) - lon) / C2C1_slope + 0.5 * (C1_y + C2_y); if (lon < -180.0 || lon > 180.0 || lat < -90.0 || lat > 90.0) - return boost::none; + return {}; else return Coordinate(FloatLongitude{lon}, FloatLatitude{lat}); } diff --git a/src/util/geojson_debug_policies.cpp b/src/util/geojson_debug_policies.cpp index afdba87ab5c..9fd2ad60dba 100644 --- a/src/util/geojson_debug_policies.cpp +++ b/src/util/geojson_debug_policies.cpp @@ -17,7 +17,7 @@ NodeIdVectorToLineString::NodeIdVectorToLineString( // converts a vector of node ids into a linestring geojson feature util::json::Object NodeIdVectorToLineString::operator()(const std::vector &node_ids, - const boost::optional &properties) const + const std::optional &properties) const { util::json::Array coordinates; std::transform(node_ids.begin(), @@ -37,7 +37,7 @@ NodeIdVectorToMultiPoint::NodeIdVectorToMultiPoint( util::json::Object NodeIdVectorToMultiPoint::operator()(const std::vector &node_ids, - const boost::optional &properties) const + const std::optional &properties) const { util::json::Array coordinates; std::transform(node_ids.begin(), @@ -51,7 +51,7 @@ NodeIdVectorToMultiPoint::operator()(const std::vector &node_ids, //---------------------------------------------------------------- util::json::Object CoordinateVectorToMultiPoint::operator()(const std::vector &input_coordinates, - const boost::optional &properties) const + const std::optional &properties) const { auto coordinates = makeJsonArray(input_coordinates); return makeFeature("MultiPoint", std::move(coordinates), properties); @@ -60,7 +60,7 @@ CoordinateVectorToMultiPoint::operator()(const std::vector &in //---------------------------------------------------------------- util::json::Object CoordinateVectorToLineString::operator()(const std::vector &input_coordinates, - const boost::optional &properties) const + const std::optional &properties) const { auto coordinates = makeJsonArray(input_coordinates); return makeFeature("LineString", std::move(coordinates), properties); diff --git a/src/util/timezones.cpp b/src/util/timezones.cpp index 179e2d11ae3..f11b1860a4e 100644 --- a/src/util/timezones.cpp +++ b/src/util/timezones.cpp @@ -5,13 +5,13 @@ #include #include -#include #include #include #include #include +#include #include #include #include @@ -157,7 +157,7 @@ void Timezoner::LoadLocalTimesRTree(rapidjson::Document &geojson, std::time_t ut rtree = rtree_t(polygons); } -boost::optional Timezoner::operator()(const point_t &point) const +std::optional Timezoner::operator()(const point_t &point) const { std::vector result; rtree.query(boost::geometry::index::intersects(point), std::back_inserter(result)); @@ -167,6 +167,6 @@ boost::optional Timezoner::operator()(const point_t &point) const if (boost::geometry::within(point, local_times[index].first)) return local_times[index].second; } - return boost::none; + return {}; } } // namespace osrm::updater From 23fb96c4f208c2ef0c813d9fa7c656eef886aa68 Mon Sep 17 00:00:00 2001 From: Mugr Rex Date: Fri, 21 Apr 2023 13:16:14 +0200 Subject: [PATCH 2/9] Fixed error in /nodejs --- include/nodejs/node_osrm_support.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/nodejs/node_osrm_support.hpp b/include/nodejs/node_osrm_support.hpp index 4074d984e18..28f84263c7d 100644 --- a/include/nodejs/node_osrm_support.hpp +++ b/include/nodejs/node_osrm_support.hpp @@ -400,7 +400,7 @@ parseCoordinateArray(const Napi::Array &coordinates_array) osrm::util::FloatLatitude{std::move(lat)}); } - resulting_coordinates = boost::make_optional(std::move(temp_coordinates)); + resulting_coordinates = std::make_optional(std::move(temp_coordinates)); return resulting_coordinates; } From 5b23b11129feadc5761bba419282282543f158a5 Mon Sep 17 00:00:00 2001 From: Mugr Rex Date: Mon, 24 Apr 2023 19:10:04 +0200 Subject: [PATCH 3/9] Readded updater Must have been lost while concating everything into one commit --- include/updater/csv_file_parser.hpp | 2 +- include/updater/source.hpp | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/include/updater/csv_file_parser.hpp b/include/updater/csv_file_parser.hpp index e21565f1a73..d51ada1561d 100644 --- a/include/updater/csv_file_parser.hpp +++ b/include/updater/csv_file_parser.hpp @@ -39,7 +39,7 @@ template struct CSVFilesParser { } - // Operator returns a lambda function that maps input Key to boost::optional. + // Operator returns a lambda function that maps input Key to std::optional. auto operator()(const std::vector &csv_filenames) const { try diff --git a/include/updater/source.hpp b/include/updater/source.hpp index 0b3dec11b74..e97df9bd0c7 100644 --- a/include/updater/source.hpp +++ b/include/updater/source.hpp @@ -3,8 +3,7 @@ #include "util/typedefs.hpp" -#include - +#include #include namespace osrm::updater @@ -12,9 +11,9 @@ namespace osrm::updater template struct LookupTable { - boost::optional operator()(const Key &key) const + std::optional operator()(const Key &key) const { - using Result = boost::optional; + using Result = std::optional; const auto it = std::lower_bound( lookup.begin(), lookup.end(), key, [](const auto &lhs, const auto &rhs) { return rhs < lhs.first; @@ -49,7 +48,7 @@ struct SpeedSource final { SpeedSource() : speed(0.), rate() {} double speed; - boost::optional rate; + std::optional rate; std::uint8_t source; }; From 1107a14a2cf1e00cf4896dcb4fbaef202b2d1678 Mon Sep 17 00:00:00 2001 From: Mugr Rex Date: Mon, 24 Apr 2023 19:16:27 +0200 Subject: [PATCH 4/9] Removed nodejs Seems like my local build is ok, but in CI the references to engine are still there so I am reverting code in /nodejs to master --- include/nodejs/node_osrm_support.hpp | 10 +- src/nodejs/json_v8_renderer.hpp | 68 + src/nodejs/node_osrm.hpp | 32 + src/nodejs/node_osrm_support.hpp | 1706 ++++++++++++++++++++++++++ 4 files changed, 1811 insertions(+), 5 deletions(-) create mode 100644 src/nodejs/json_v8_renderer.hpp create mode 100644 src/nodejs/node_osrm.hpp create mode 100644 src/nodejs/node_osrm_support.hpp diff --git a/include/nodejs/node_osrm_support.hpp b/include/nodejs/node_osrm_support.hpp index 28f84263c7d..5296dc4ed3b 100644 --- a/include/nodejs/node_osrm_support.hpp +++ b/include/nodejs/node_osrm_support.hpp @@ -21,11 +21,11 @@ #include #include +#include #include #include #include -#include #include #include #include @@ -345,11 +345,11 @@ inline engine_config_ptr argumentsToEngineConfig(const Napi::CallbackInfo &args) return engine_config; } -inline std::optional> +inline boost::optional> parseCoordinateArray(const Napi::Array &coordinates_array) { Napi::HandleScope scope(coordinates_array.Env()); - std::optional> resulting_coordinates; + boost::optional> resulting_coordinates; std::vector temp_coordinates; for (uint32_t i = 0; i < coordinates_array.Length(); ++i) @@ -400,7 +400,7 @@ parseCoordinateArray(const Napi::Array &coordinates_array) osrm::util::FloatLatitude{std::move(lat)}); } - resulting_coordinates = std::make_optional(std::move(temp_coordinates)); + resulting_coordinates = boost::make_optional(std::move(temp_coordinates)); return resulting_coordinates; } @@ -968,7 +968,7 @@ inline bool parseCommonParameters(const Napi::Object &obj, ParamType ¶ms) inline PluginParameters argumentsToPluginParameters( const Napi::CallbackInfo &args, - const std::optional &output_format = {}) + const boost::optional &output_format = {}) { if (args.Length() < 3 || !args[1].IsObject()) { diff --git a/src/nodejs/json_v8_renderer.hpp b/src/nodejs/json_v8_renderer.hpp new file mode 100644 index 00000000000..4b8bbd193d8 --- /dev/null +++ b/src/nodejs/json_v8_renderer.hpp @@ -0,0 +1,68 @@ +#ifndef OSRM_BINDINGS_NODE_JSON_V8_RENDERER_HPP +#define OSRM_BINDINGS_NODE_JSON_V8_RENDERER_HPP + +#include "osrm/json_container.hpp" +#include + +#include + +namespace node_osrm +{ + +struct V8Renderer +{ + explicit V8Renderer(const Napi::Env &env, Napi::Value &out) : env(env), out(out) {} + + void operator()(const osrm::json::String &string) const + { + out = Napi::String::New(env, string.value); + } + + void operator()(const osrm::json::Number &number) const + { + out = Napi::Number::New(env, number.value); + } + + void operator()(const osrm::json::Object &object) const + { + Napi::Object obj = Napi::Object::New(env); + for (const auto &keyValue : object.values) + { + Napi::Value child; + mapbox::util::apply_visitor(V8Renderer(env, child), keyValue.second); + obj.Set(keyValue.first, child); + } + out = obj; + } + + void operator()(const osrm::json::Array &array) const + { + Napi::Array a = Napi::Array::New(env, array.values.size()); + for (auto i = 0u; i < array.values.size(); ++i) + { + Napi::Value child; + mapbox::util::apply_visitor(V8Renderer(env, child), array.values[i]); + a.Set(i, child); + } + out = a; + } + + void operator()(const osrm::json::True &) const { out = Napi::Boolean::New(env, true); } + + void operator()(const osrm::json::False &) const { out = Napi::Boolean::New(env, false); } + + void operator()(const osrm::json::Null &) const { out = env.Null(); } + + private: + const Napi::Env &env; + Napi::Value &out; +}; + +inline void renderToV8(const Napi::Env &env, Napi::Value &out, const osrm::json::Object &object) +{ + V8Renderer renderer(env, out); + renderer(object); +} +} // namespace node_osrm + +#endif // JSON_V8_RENDERER_HPP diff --git a/src/nodejs/node_osrm.hpp b/src/nodejs/node_osrm.hpp new file mode 100644 index 00000000000..f85fb536235 --- /dev/null +++ b/src/nodejs/node_osrm.hpp @@ -0,0 +1,32 @@ +#ifndef OSRM_BINDINGS_NODE_HPP +#define OSRM_BINDINGS_NODE_HPP + +#include "osrm/osrm_fwd.hpp" + +#include + +#include + +namespace node_osrm +{ + +class Engine final : public Napi::ObjectWrap +{ + public: + static Napi::Object Init(Napi::Env env, Napi::Object exports); + Engine(const Napi::CallbackInfo &info); + + std::shared_ptr this_; + + private: + Napi::Value route(const Napi::CallbackInfo &info); + Napi::Value nearest(const Napi::CallbackInfo &info); + Napi::Value table(const Napi::CallbackInfo &info); + Napi::Value tile(const Napi::CallbackInfo &info); + Napi::Value match(const Napi::CallbackInfo &info); + Napi::Value trip(const Napi::CallbackInfo &info); +}; + +} // namespace node_osrm + +#endif diff --git a/src/nodejs/node_osrm_support.hpp b/src/nodejs/node_osrm_support.hpp new file mode 100644 index 00000000000..5296dc4ed3b --- /dev/null +++ b/src/nodejs/node_osrm_support.hpp @@ -0,0 +1,1706 @@ +#ifndef OSRM_BINDINGS_NODE_SUPPORT_HPP +#define OSRM_BINDINGS_NODE_SUPPORT_HPP + +#include "nodejs/json_v8_renderer.hpp" +#include "engine/api/flatbuffers/fbresult_generated.h" +#include "osrm/approach.hpp" +#include "osrm/bearing.hpp" +#include "osrm/coordinate.hpp" +#include "osrm/engine_config.hpp" +#include "osrm/json_container.hpp" +#include "osrm/match_parameters.hpp" +#include "osrm/nearest_parameters.hpp" +#include "osrm/osrm.hpp" +#include "osrm/route_parameters.hpp" +#include "osrm/status.hpp" +#include "osrm/storage_config.hpp" +#include "osrm/table_parameters.hpp" +#include "osrm/tile_parameters.hpp" +#include "osrm/trip_parameters.hpp" +#include "util/json_renderer.hpp" +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace node_osrm +{ + +using engine_config_ptr = std::unique_ptr; +using route_parameters_ptr = std::unique_ptr; +using trip_parameters_ptr = std::unique_ptr; +using tile_parameters_ptr = std::unique_ptr; +using match_parameters_ptr = std::unique_ptr; +using nearest_parameters_ptr = std::unique_ptr; +using table_parameters_ptr = std::unique_ptr; + +struct PluginParameters +{ + bool renderToBuffer = false; +}; + +using ObjectOrString = typename mapbox::util::variant; + +template inline Napi::Value render(const Napi::Env &env, const ResultT &result); + +template <> Napi::Value inline render(const Napi::Env &env, const std::string &result) +{ + return Napi::Buffer::Copy(env, result.data(), result.size()); +} + +template <> Napi::Value inline render(const Napi::Env &env, const ObjectOrString &result) +{ + if (result.is()) + { + // Convert osrm::json object tree into matching v8 object tree + Napi::Value value; + renderToV8(env, value, result.get()); + return value; + } + else + { + // Return the string object as a node Buffer + return Napi::Buffer::Copy( + env, result.get().data(), result.get().size()); + } +} + +inline bool IsUnsignedInteger(const Napi::Value &value) +{ + if (!value.IsNumber()) + { + return false; + } + const auto doubleValue = value.ToNumber().DoubleValue(); + return doubleValue >= 0.0 && std::floor(doubleValue) == doubleValue; +} + +inline void ParseResult(const osrm::Status &result_status, osrm::json::Object &result) +{ + const auto code_iter = result.values.find("code"); + const auto end_iter = result.values.end(); + + BOOST_ASSERT(code_iter != end_iter); + + if (result_status == osrm::Status::Error) + { + throw std::logic_error(code_iter->second.get().value.c_str()); + } + + result.values.erase(code_iter); + const auto message_iter = result.values.find("message"); + if (message_iter != end_iter) + { + result.values.erase(message_iter); + } +} + +inline void ParseResult(const osrm::Status & /*result_status*/, const std::string & /*unused*/) {} +inline void ParseResult(const osrm::Status &result_status, + const flatbuffers::FlatBufferBuilder &fbs_builder) +{ + auto fbs_result = osrm::engine::api::fbresult::GetFBResult(fbs_builder.GetBufferPointer()); + + if (result_status == osrm::Status::Error) + { + BOOST_ASSERT(fbs_result->code()); + throw std::logic_error(fbs_result->code()->message()->c_str()); + } +} + +inline void ThrowError(const Napi::Env &env, const char *message) +{ + Napi::Error::New(env, message).ThrowAsJavaScriptException(); +} + +inline void ThrowTypeError(const Napi::Env &env, const char *message) +{ + Napi::TypeError::New(env, message).ThrowAsJavaScriptException(); +} + +inline engine_config_ptr argumentsToEngineConfig(const Napi::CallbackInfo &args) +{ + Napi::HandleScope scope(args.Env()); + auto engine_config = std::make_unique(); + + if (args.Length() == 0) + { + return engine_config; + } + else if (args.Length() > 1) + { + ThrowError(args.Env(), "Only accepts one parameter"); + return engine_config_ptr(); + } + + BOOST_ASSERT(args.Length() == 1); + + if (args[0].IsString()) + { + engine_config->storage_config = osrm::StorageConfig(args[0].ToString().Utf8Value()); + engine_config->use_shared_memory = false; + return engine_config; + } + else if (!args[0].IsObject()) + { + ThrowError(args.Env(), "Parameter must be a path or options object"); + return engine_config_ptr(); + } + + BOOST_ASSERT(args[0].IsObject()); + auto params = args[0].As(); + + auto path = params.Get("path"); + if (path.IsEmpty()) + return engine_config_ptr(); + + auto memory_file = params.Get("memory_file"); + if (memory_file.IsEmpty()) + return engine_config_ptr(); + + auto shared_memory = params.Get("shared_memory"); + if (shared_memory.IsEmpty()) + return engine_config_ptr(); + + auto mmap_memory = params.Get("mmap_memory"); + if (mmap_memory.IsEmpty()) + return engine_config_ptr(); + + if (!memory_file.IsUndefined()) + { + if (path.IsUndefined()) + { + ThrowError(args.Env(), "memory_file option requires a path to a file."); + return engine_config_ptr(); + } + + engine_config->memory_file = memory_file.ToString().Utf8Value(); + } + + auto dataset_name = params.Get("dataset_name"); + if (dataset_name.IsEmpty()) + return engine_config_ptr(); + if (!dataset_name.IsUndefined()) + { + if (dataset_name.IsString()) + { + engine_config->dataset_name = dataset_name.ToString().Utf8Value(); + } + else + { + ThrowError(args.Env(), "dataset_name needs to be a string"); + return engine_config_ptr(); + } + } + + if (!path.IsUndefined()) + { + engine_config->storage_config = osrm::StorageConfig(path.ToString().Utf8Value()); + + engine_config->use_shared_memory = false; + } + if (!shared_memory.IsUndefined()) + { + if (shared_memory.IsBoolean()) + { + engine_config->use_shared_memory = shared_memory.ToBoolean().Value(); + } + else + { + ThrowError(args.Env(), "Shared_memory option must be a boolean"); + return engine_config_ptr(); + } + } + if (!mmap_memory.IsUndefined()) + { + if (mmap_memory.IsBoolean()) + { + engine_config->use_mmap = mmap_memory.ToBoolean().Value(); + } + else + { + ThrowError(args.Env(), "mmap_memory option must be a boolean"); + return engine_config_ptr(); + } + } + + if (path.IsUndefined() && !engine_config->use_shared_memory) + { + ThrowError(args.Env(), + "Shared_memory must be enabled if no path is " + "specified"); + return engine_config_ptr(); + } + + auto algorithm = params.Get("algorithm"); + if (algorithm.IsEmpty()) + return engine_config_ptr(); + + if (algorithm.IsString()) + { + auto algorithm_str = algorithm.ToString().Utf8Value(); + if (algorithm_str == "CH") + { + engine_config->algorithm = osrm::EngineConfig::Algorithm::CH; + } + else if (algorithm_str == "CoreCH") + { + engine_config->algorithm = osrm::EngineConfig::Algorithm::CH; + } + else if (algorithm_str == "MLD") + { + engine_config->algorithm = osrm::EngineConfig::Algorithm::MLD; + } + else + { + ThrowError(args.Env(), "algorithm option must be one of 'CH', 'CoreCH', or 'MLD'."); + return engine_config_ptr(); + } + } + else if (!algorithm.IsUndefined()) + { + ThrowError(args.Env(), + "algorithm option must be a string and one of 'CH', 'CoreCH', or 'MLD'."); + return engine_config_ptr(); + } + + // Set EngineConfig system-wide limits on construction, if requested + + auto max_locations_trip = params.Get("max_locations_trip"); + auto max_locations_viaroute = params.Get("max_locations_viaroute"); + auto max_locations_distance_table = params.Get("max_locations_distance_table"); + auto max_locations_map_matching = params.Get("max_locations_map_matching"); + auto max_results_nearest = params.Get("max_results_nearest"); + auto max_alternatives = params.Get("max_alternatives"); + auto max_radius_map_matching = params.Get("max_radius_map_matching"); + auto default_radius = params.Get("default_radius"); + + if (!max_locations_trip.IsUndefined() && !max_locations_trip.IsNumber()) + { + ThrowError(args.Env(), "max_locations_trip must be an integral number"); + return engine_config_ptr(); + } + if (!max_locations_viaroute.IsUndefined() && !max_locations_viaroute.IsNumber()) + { + ThrowError(args.Env(), "max_locations_viaroute must be an integral number"); + return engine_config_ptr(); + } + if (!max_locations_distance_table.IsUndefined() && !max_locations_distance_table.IsNumber()) + { + ThrowError(args.Env(), "max_locations_distance_table must be an integral number"); + return engine_config_ptr(); + } + if (!max_locations_map_matching.IsUndefined() && !max_locations_map_matching.IsNumber()) + { + ThrowError(args.Env(), "max_locations_map_matching must be an integral number"); + return engine_config_ptr(); + } + if (!max_results_nearest.IsUndefined() && !max_results_nearest.IsNumber()) + { + ThrowError(args.Env(), "max_results_nearest must be an integral number"); + return engine_config_ptr(); + } + if (!max_alternatives.IsUndefined() && !max_alternatives.IsNumber()) + { + ThrowError(args.Env(), "max_alternatives must be an integral number"); + return engine_config_ptr(); + } + if (!default_radius.IsUndefined() && !default_radius.IsNumber()) + { + ThrowError(args.Env(), "default_radius must be an integral number"); + return engine_config_ptr(); + } + + if (max_locations_trip.IsNumber()) + engine_config->max_locations_trip = max_locations_trip.ToNumber().Int32Value(); + if (max_locations_viaroute.IsNumber()) + engine_config->max_locations_viaroute = max_locations_viaroute.ToNumber().Int32Value(); + if (max_locations_distance_table.IsNumber()) + engine_config->max_locations_distance_table = + max_locations_distance_table.ToNumber().Int32Value(); + if (max_locations_map_matching.IsNumber()) + engine_config->max_locations_map_matching = + max_locations_map_matching.ToNumber().Int32Value(); + if (max_results_nearest.IsNumber()) + engine_config->max_results_nearest = max_results_nearest.ToNumber().Int32Value(); + if (max_alternatives.IsNumber()) + engine_config->max_alternatives = max_alternatives.ToNumber().Int32Value(); + if (max_radius_map_matching.IsNumber()) + engine_config->max_radius_map_matching = max_radius_map_matching.ToNumber().DoubleValue(); + if (default_radius.IsNumber()) + engine_config->default_radius = default_radius.ToNumber().DoubleValue(); + + return engine_config; +} + +inline boost::optional> +parseCoordinateArray(const Napi::Array &coordinates_array) +{ + Napi::HandleScope scope(coordinates_array.Env()); + boost::optional> resulting_coordinates; + std::vector temp_coordinates; + + for (uint32_t i = 0; i < coordinates_array.Length(); ++i) + { + Napi::Value coordinate = coordinates_array.Get(i); + if (coordinate.IsEmpty()) + return resulting_coordinates; + + if (!coordinate.IsArray()) + { + ThrowError(coordinates_array.Env(), "Coordinates must be an array of (lon/lat) pairs"); + return resulting_coordinates; + } + + Napi::Array coordinate_pair = coordinate.As(); + if (coordinate_pair.Length() != 2) + { + ThrowError(coordinates_array.Env(), "Coordinates must be an array of (lon/lat) pairs"); + return resulting_coordinates; + } + + if (!coordinate_pair.Get(static_cast(0)).IsNumber() || + !coordinate_pair.Get(static_cast(1)).IsNumber()) + { + ThrowError(coordinates_array.Env(), + "Each member of a coordinate pair must be a number"); + return resulting_coordinates; + } + + double lon = coordinate_pair.Get(static_cast(0)).As().DoubleValue(); + double lat = coordinate_pair.Get(static_cast(1)).As().DoubleValue(); + + if (std::isnan(lon) || std::isnan(lat) || std::isinf(lon) || std::isinf(lat)) + { + ThrowError(coordinates_array.Env(), "Lng/Lat coordinates must be valid numbers"); + return resulting_coordinates; + } + + if (lon > 180 || lon < -180 || lat > 90 || lat < -90) + { + ThrowError(coordinates_array.Env(), + "Lng/Lat coordinates must be within world bounds " + "(-180 < lng < 180, -90 < lat < 90)"); + return resulting_coordinates; + } + + temp_coordinates.emplace_back(osrm::util::FloatLongitude{std::move(lon)}, + osrm::util::FloatLatitude{std::move(lat)}); + } + + resulting_coordinates = boost::make_optional(std::move(temp_coordinates)); + return resulting_coordinates; +} + +// Parses all the non-service specific parameters +template +inline bool argumentsToParameter(const Napi::CallbackInfo &args, + ParamType ¶ms, + bool requires_multiple_coordinates) +{ + Napi::HandleScope scope(args.Env()); + + if (args.Length() < 2) + { + ThrowTypeError(args.Env(), "Two arguments required"); + return false; + } + + if (!args[0].IsObject()) + { + ThrowTypeError(args.Env(), "First arg must be an object"); + return false; + } + + Napi::Object obj = args[0].As(); + + Napi::Value coordinates = obj.Get("coordinates"); + if (coordinates.IsEmpty()) + return false; + + if (coordinates.IsUndefined()) + { + ThrowError(args.Env(), "Must provide a coordinates property"); + return false; + } + else if (coordinates.IsArray()) + { + auto coordinates_array = coordinates.As(); + if (coordinates_array.Length() < 2 && requires_multiple_coordinates) + { + ThrowError(args.Env(), "At least two coordinates must be provided"); + return false; + } + else if (!requires_multiple_coordinates && coordinates_array.Length() != 1) + { + ThrowError(args.Env(), "Exactly one coordinate pair must be provided"); + return false; + } + auto maybe_coordinates = parseCoordinateArray(coordinates_array); + if (maybe_coordinates) + { + std::copy(maybe_coordinates->begin(), + maybe_coordinates->end(), + std::back_inserter(params->coordinates)); + } + else + { + return false; + } + } + else if (!coordinates.IsUndefined()) + { + BOOST_ASSERT(!coordinates.IsArray()); + ThrowError(args.Env(), "Coordinates must be an array of (lon/lat) pairs"); + return false; + } + + if (obj.Has("approaches")) + { + Napi::Value approaches = obj.Get("approaches"); + if (approaches.IsEmpty()) + return false; + + if (!approaches.IsArray()) + { + ThrowError(args.Env(), "Approaches must be an arrays of strings"); + return false; + } + + auto approaches_array = approaches.As(); + + if (approaches_array.Length() != params->coordinates.size()) + { + ThrowError(args.Env(), + "Approaches array must have the same length as coordinates array"); + return false; + } + + for (uint32_t i = 0; i < approaches_array.Length(); ++i) + { + Napi::Value approach_raw = approaches_array.Get(i); + if (approach_raw.IsEmpty()) + return false; + + if (approach_raw.IsNull()) + { + params->approaches.emplace_back(); + } + else if (approach_raw.IsString()) + { + std::string approach_str = approach_raw.ToString().Utf8Value(); + if (approach_str == "curb") + { + params->approaches.push_back(osrm::Approach::CURB); + } + else if (approach_str == "unrestricted") + { + params->approaches.push_back(osrm::Approach::UNRESTRICTED); + } + else + { + ThrowError(args.Env(), + "'approaches' param must be one of [curb, unrestricted]"); + return false; + } + } + else + { + ThrowError(args.Env(), "Approach must be a string: [curb, unrestricted] or null"); + return false; + } + } + } + + if (obj.Has("bearings")) + { + Napi::Value bearings = obj.Get("bearings"); + if (bearings.IsEmpty()) + return false; + + if (!bearings.IsArray()) + { + ThrowError(args.Env(), "Bearings must be an array of arrays of numbers"); + return false; + } + + auto bearings_array = bearings.As(); + + if (bearings_array.Length() != params->coordinates.size()) + { + ThrowError(args.Env(), "Bearings array must have the same length as coordinates array"); + return false; + } + + for (uint32_t i = 0; i < bearings_array.Length(); ++i) + { + Napi::Value bearing_raw = bearings_array.Get(i); + if (bearing_raw.IsEmpty()) + return false; + + if (bearing_raw.IsNull()) + { + params->bearings.emplace_back(); + } + else if (bearing_raw.IsArray()) + { + auto bearing_pair = bearing_raw.As(); + if (bearing_pair.Length() == 2) + { + if (!bearing_pair.Get(static_cast(0)).IsNumber() || + !bearing_pair.Get(static_cast(1)).IsNumber()) + { + ThrowError(args.Env(), "Bearing values need to be numbers in range 0..360"); + return false; + } + + const auto bearing = + bearing_pair.Get(static_cast(0)).ToNumber().Int32Value(); + const auto range = + bearing_pair.Get(static_cast(1)).ToNumber().Int32Value(); + + if (bearing < 0 || bearing > 360 || range < 0 || range > 180) + { + ThrowError(args.Env(), "Bearing values need to be in range 0..360, 0..180"); + return false; + } + + params->bearings.push_back( + osrm::Bearing{static_cast(bearing), static_cast(range)}); + } + else + { + ThrowError(args.Env(), "Bearing must be an array of [bearing, range] or null"); + return false; + } + } + else + { + ThrowError(args.Env(), "Bearing must be an array of [bearing, range] or null"); + return false; + } + } + } + + if (obj.Has("hints")) + { + Napi::Value hints = obj.Get("hints"); + if (hints.IsEmpty()) + return false; + + if (!hints.IsArray()) + { + ThrowError(args.Env(), "Hints must be an array of strings/null"); + return false; + } + + Napi::Array hints_array = hints.As(); + + if (hints_array.Length() != params->coordinates.size()) + { + ThrowError(args.Env(), "Hints array must have the same length as coordinates array"); + return false; + } + + for (uint32_t i = 0; i < hints_array.Length(); ++i) + { + Napi::Value hint = hints_array.Get(i); + if (hint.IsEmpty()) + return false; + + if (hint.IsString()) + { + if (hint.ToString().Utf8Value().length() == 0) + { + ThrowError(args.Env(), "Hint cannot be an empty string"); + return false; + } + + params->hints.emplace_back( + osrm::engine::Hint::FromBase64(hint.ToString().Utf8Value())); + } + else if (hint.IsNull()) + { + params->hints.emplace_back(); + } + else + { + ThrowError(args.Env(), "Hint must be null or string"); + return false; + } + } + } + + if (obj.Has("radiuses")) + { + Napi::Value radiuses = obj.Get("radiuses"); + if (radiuses.IsEmpty()) + return false; + + if (!radiuses.IsArray()) + { + ThrowError(args.Env(), "Radiuses must be an array of non-negative doubles or null"); + return false; + } + + Napi::Array radiuses_array = radiuses.As(); + + if (radiuses_array.Length() != params->coordinates.size()) + { + ThrowError(args.Env(), "Radiuses array must have the same length as coordinates array"); + return false; + } + + for (uint32_t i = 0; i < radiuses_array.Length(); ++i) + { + Napi::Value radius = radiuses_array.Get(i); + if (radius.IsEmpty()) + return false; + + if (radius.IsNull()) + { + params->radiuses.emplace_back(); + } + else if (radius.IsNumber() && radius.ToNumber().DoubleValue() >= 0) + { + params->radiuses.push_back(radius.ToNumber().DoubleValue()); + } + else + { + ThrowError(args.Env(), "Radius must be non-negative double or null"); + return false; + } + } + } + + if (obj.Has("generate_hints")) + { + Napi::Value generate_hints = obj.Get("generate_hints"); + if (generate_hints.IsEmpty()) + return false; + + if (!generate_hints.IsBoolean()) + { + ThrowError(args.Env(), "generate_hints must be of type Boolean"); + return false; + } + + params->generate_hints = generate_hints.ToBoolean().Value(); + } + + if (obj.Has("skip_waypoints")) + { + Napi::Value skip_waypoints = obj.Get("skip_waypoints"); + if (skip_waypoints.IsEmpty()) + return false; + + if (!skip_waypoints.IsBoolean()) + { + ThrowError(args.Env(), "skip_waypoints must be of type Boolean"); + return false; + } + + params->skip_waypoints = skip_waypoints.ToBoolean().Value(); + } + + if (obj.Has("exclude")) + { + Napi::Value exclude = obj.Get("exclude"); + if (exclude.IsEmpty()) + return false; + + if (!exclude.IsArray()) + { + ThrowError(args.Env(), "Exclude must be an array of strings or empty"); + return false; + } + + Napi::Array exclude_array = exclude.As(); + + for (uint32_t i = 0; i < exclude_array.Length(); ++i) + { + Napi::Value class_name = exclude_array.Get(i); + if (class_name.IsEmpty()) + return false; + + if (class_name.IsString()) + { + std::string class_name_str = class_name.ToString().Utf8Value(); + params->exclude.emplace_back(std::move(class_name_str)); + } + else + { + ThrowError(args.Env(), "Exclude must be an array of strings or empty"); + return false; + } + } + } + + if (obj.Has("format")) + { + Napi::Value format = obj.Get("format"); + if (format.IsEmpty()) + { + return false; + } + + if (!format.IsString()) + { + ThrowError(args.Env(), "format must be a string: \"json\" or \"flatbuffers\""); + return false; + } + + std::string format_str = format.ToString().Utf8Value(); + if (format_str == "json") + { + params->format = osrm::engine::api::BaseParameters::OutputFormatType::JSON; + } + else if (format_str == "flatbuffers") + { + params->format = osrm::engine::api::BaseParameters::OutputFormatType::FLATBUFFERS; + } + else + { + ThrowError(args.Env(), "format must be a string: \"json\" or \"flatbuffers\""); + return false; + } + } + + if (obj.Has("snapping")) + { + Napi::Value snapping = obj.Get("snapping"); + if (snapping.IsEmpty()) + return false; + + if (!snapping.IsString()) + { + ThrowError(args.Env(), "Snapping must be a string: [default, any]"); + return false; + } + + std::string snapping_str = snapping.ToString().Utf8Value(); + + if (snapping_str == "default") + { + params->snapping = osrm::RouteParameters::SnappingType::Default; + } + else if (snapping_str == "any") + { + params->snapping = osrm::RouteParameters::SnappingType::Any; + } + else + { + ThrowError(args.Env(), "'snapping' param must be one of [default, any]"); + return false; + } + } + + return true; +} + +template +inline bool parseCommonParameters(const Napi::Object &obj, ParamType ¶ms) +{ + if (obj.Has("steps")) + { + auto steps = obj.Get("steps"); + if (steps.IsEmpty()) + return false; + + if (steps.IsBoolean()) + { + params->steps = steps.ToBoolean().Value(); + } + else + { + ThrowError(obj.Env(), "'steps' param must be a boolean"); + return false; + } + } + + if (obj.Has("annotations")) + { + auto annotations = obj.Get("annotations"); + if (annotations.IsEmpty()) + return false; + + if (annotations.IsBoolean()) + { + params->annotations = annotations.ToBoolean().Value(); + params->annotations_type = params->annotations + ? osrm::RouteParameters::AnnotationsType::All + : osrm::RouteParameters::AnnotationsType::None; + } + else if (annotations.IsArray()) + { + Napi::Array annotations_array = annotations.As(); + for (std::size_t i = 0; i < annotations_array.Length(); i++) + { + std::string annotations_str = annotations_array.Get(i).ToString().Utf8Value(); + + if (annotations_str == "duration") + { + params->annotations_type = + params->annotations_type | osrm::RouteParameters::AnnotationsType::Duration; + } + else if (annotations_str == "nodes") + { + params->annotations_type = + params->annotations_type | osrm::RouteParameters::AnnotationsType::Nodes; + } + else if (annotations_str == "distance") + { + params->annotations_type = + params->annotations_type | osrm::RouteParameters::AnnotationsType::Distance; + } + else if (annotations_str == "weight") + { + params->annotations_type = + params->annotations_type | osrm::RouteParameters::AnnotationsType::Weight; + } + else if (annotations_str == "datasources") + { + params->annotations_type = params->annotations_type | + osrm::RouteParameters::AnnotationsType::Datasources; + } + else if (annotations_str == "speed") + { + params->annotations_type = + params->annotations_type | osrm::RouteParameters::AnnotationsType::Speed; + } + else + { + ThrowError(obj.Env(), "this 'annotations' param is not supported"); + return false; + } + + params->annotations = + params->annotations_type != osrm::RouteParameters::AnnotationsType::None; + } + } + else + { + ThrowError(obj.Env(), "this 'annotations' param is not supported"); + return false; + } + } + + if (obj.Has("geometries")) + { + Napi::Value geometries = obj.Get("geometries"); + if (geometries.IsEmpty()) + return false; + + if (!geometries.IsString()) + { + ThrowError(obj.Env(), "Geometries must be a string: [polyline, polyline6, geojson]"); + return false; + } + std::string geometries_str = geometries.ToString().Utf8Value(); + + if (geometries_str == "polyline") + { + params->geometries = osrm::RouteParameters::GeometriesType::Polyline; + } + else if (geometries_str == "polyline6") + { + params->geometries = osrm::RouteParameters::GeometriesType::Polyline6; + } + else if (geometries_str == "geojson") + { + params->geometries = osrm::RouteParameters::GeometriesType::GeoJSON; + } + else + { + ThrowError(obj.Env(), + "'geometries' param must be one of [polyline, polyline6, geojson]"); + return false; + } + } + + if (obj.Has("overview")) + { + Napi::Value overview = obj.Get("overview"); + if (overview.IsEmpty()) + return false; + + if (!overview.IsString()) + { + ThrowError(obj.Env(), "Overview must be a string: [simplified, full, false]"); + return false; + } + + std::string overview_str = overview.ToString().Utf8Value(); + + if (overview_str == "simplified") + { + params->overview = osrm::RouteParameters::OverviewType::Simplified; + } + else if (overview_str == "full") + { + params->overview = osrm::RouteParameters::OverviewType::Full; + } + else if (overview_str == "false") + { + params->overview = osrm::RouteParameters::OverviewType::False; + } + else + { + ThrowError(obj.Env(), "'overview' param must be one of [simplified, full, false]"); + return false; + } + } + + return true; +} + +inline PluginParameters argumentsToPluginParameters( + const Napi::CallbackInfo &args, + const boost::optional &output_format = {}) +{ + if (args.Length() < 3 || !args[1].IsObject()) + { + // output to buffer by default for Flatbuffers + return {output_format == osrm::engine::api::BaseParameters::OutputFormatType::FLATBUFFERS}; + } + Napi::Object obj = args[1].As(); + if (obj.Has("format")) + { + Napi::Value format = obj.Get("format"); + if (format.IsEmpty()) + { + return {}; + } + + if (!format.IsString()) + { + ThrowError(args.Env(), "format must be a string: \"object\" or \"buffer\""); + return {}; + } + + std::string format_str = format.ToString().Utf8Value(); + + if (format_str == "object") + { + if (output_format == osrm::engine::api::BaseParameters::OutputFormatType::FLATBUFFERS) + { + ThrowError(args.Env(), "Flatbuffers result can only output to buffer."); + return {true}; + } + return {false}; + } + else if (format_str == "buffer") + { + return {true}; + } + else if (format_str == "json_buffer") + { + if (output_format && + output_format != osrm::engine::api::BaseParameters::OutputFormatType::JSON) + { + ThrowError(args.Env(), + "Deprecated `json_buffer` can only be used with JSON format"); + } + return {true}; + } + else + { + ThrowError(args.Env(), "format must be a string: \"object\" or \"buffer\""); + return {}; + } + } + + // output to buffer by default for Flatbuffers + return {output_format == osrm::engine::api::BaseParameters::OutputFormatType::FLATBUFFERS}; +} + +inline route_parameters_ptr argumentsToRouteParameter(const Napi::CallbackInfo &args, + bool requires_multiple_coordinates) +{ + route_parameters_ptr params = std::make_unique(); + bool has_base_params = argumentsToParameter(args, params, requires_multiple_coordinates); + if (!has_base_params) + return route_parameters_ptr(); + + Napi::Object obj = args[0].As(); + + if (obj.Has("continue_straight")) + { + auto value = obj.Get("continue_straight"); + if (value.IsEmpty()) + return route_parameters_ptr(); + + if (!value.IsBoolean() && !value.IsNull()) + { + ThrowError(args.Env(), "'continue_straight' param must be boolean or null"); + return route_parameters_ptr(); + } + if (value.IsBoolean()) + { + params->continue_straight = value.ToBoolean().Value(); + } + } + + if (obj.Has("alternatives")) + { + auto value = obj.Get("alternatives"); + if (value.IsEmpty()) + return route_parameters_ptr(); + + if (value.IsBoolean()) + { + params->alternatives = value.ToBoolean().Value(); + params->number_of_alternatives = value.ToBoolean().Value() ? 1u : 0u; + } + else if (value.IsNumber()) + { + params->alternatives = value.ToBoolean().Value(); + params->number_of_alternatives = value.ToNumber().Int32Value(); + } + else + { + ThrowError(args.Env(), "'alternatives' param must be boolean or number"); + return route_parameters_ptr(); + } + } + + if (obj.Has("waypoints")) + { + Napi::Value waypoints = obj.Get("waypoints"); + if (waypoints.IsEmpty()) + return route_parameters_ptr(); + + // must be array + if (!waypoints.IsArray()) + { + ThrowError( + args.Env(), + "Waypoints must be an array of integers corresponding to the input coordinates."); + return route_parameters_ptr(); + } + + auto waypoints_array = waypoints.As(); + // must have at least two elements + if (waypoints_array.Length() < 2) + { + ThrowError(args.Env(), "At least two waypoints must be provided"); + return route_parameters_ptr(); + } + auto coords_size = params->coordinates.size(); + auto waypoints_array_size = waypoints_array.Length(); + + const auto first_index = + waypoints_array.Get(static_cast(0)).ToNumber().Uint32Value(); + const auto last_index = + waypoints_array.Get(waypoints_array_size - 1).ToNumber().Uint32Value(); + if (first_index != 0 || last_index != coords_size - 1) + { + ThrowError(args.Env(), + "First and last waypoints values must correspond to first and last " + "coordinate indices"); + return route_parameters_ptr(); + } + + for (uint32_t i = 0; i < waypoints_array_size; ++i) + { + Napi::Value waypoint_value = waypoints_array.Get(i); + // all elements must be numbers + if (!waypoint_value.IsNumber()) + { + ThrowError(args.Env(), "Waypoint values must be an array of integers"); + return route_parameters_ptr(); + } + // check that the waypoint index corresponds with an inpute coordinate + const auto index = waypoint_value.ToNumber().Uint32Value(); + if (index >= coords_size) + { + ThrowError(args.Env(), + "Waypoints must correspond with the index of an input coordinate"); + return route_parameters_ptr(); + } + params->waypoints.emplace_back(index); + } + + if (!params->waypoints.empty()) + { + for (std::size_t i = 0; i < params->waypoints.size() - 1; i++) + { + if (params->waypoints[i] >= params->waypoints[i + 1]) + { + ThrowError(args.Env(), "Waypoints must be supplied in increasing order"); + return route_parameters_ptr(); + } + } + } + } + + bool parsedSuccessfully = parseCommonParameters(obj, params); + if (!parsedSuccessfully) + { + return route_parameters_ptr(); + } + + return params; +} + +inline tile_parameters_ptr argumentsToTileParameters(const Napi::CallbackInfo &args, + bool /*unused*/) +{ + tile_parameters_ptr params = std::make_unique(); + + if (args.Length() < 2) + { + ThrowTypeError(args.Env(), "Coordinate object and callback required"); + return tile_parameters_ptr(); + } + + if (!args[0].IsArray()) + { + ThrowTypeError(args.Env(), "Parameter must be an array [x, y, z]"); + return tile_parameters_ptr(); + } + + Napi::Array array = args[0].As(); + + if (array.Length() != 3) + { + ThrowTypeError(args.Env(), "Parameter must be an array [x, y, z]"); + return tile_parameters_ptr(); + } + + Napi::Value x = array.Get(static_cast(0)); + Napi::Value y = array.Get(static_cast(1)); + Napi::Value z = array.Get(static_cast(2)); + if (x.IsEmpty() || y.IsEmpty() || z.IsEmpty()) + return tile_parameters_ptr(); + + if (!IsUnsignedInteger(x) && !x.IsUndefined()) + { + ThrowError(args.Env(), "Tile x coordinate must be unsigned interger"); + return tile_parameters_ptr(); + } + if (!IsUnsignedInteger(y) && !y.IsUndefined()) + { + ThrowError(args.Env(), "Tile y coordinate must be unsigned interger"); + return tile_parameters_ptr(); + } + if (!IsUnsignedInteger(z) && !z.IsUndefined()) + { + ThrowError(args.Env(), "Tile z coordinate must be unsigned interger"); + return tile_parameters_ptr(); + } + + params->x = x.ToNumber().Uint32Value(); + params->y = y.ToNumber().Uint32Value(); + params->z = z.ToNumber().Uint32Value(); + + if (!params->IsValid()) + { + ThrowError(args.Env(), "Invalid tile coordinates"); + return tile_parameters_ptr(); + } + + return params; +} + +inline nearest_parameters_ptr argumentsToNearestParameter(const Napi::CallbackInfo &args, + bool requires_multiple_coordinates) +{ + nearest_parameters_ptr params = std::make_unique(); + bool has_base_params = argumentsToParameter(args, params, requires_multiple_coordinates); + if (!has_base_params) + return nearest_parameters_ptr(); + + Napi::Object obj = args[0].As(); + if (obj.IsEmpty()) + return nearest_parameters_ptr(); + + if (obj.Has("number")) + { + Napi::Value number = obj.Get("number"); + + if (!IsUnsignedInteger(number)) + { + ThrowError(args.Env(), "Number must be an integer greater than or equal to 1"); + return nearest_parameters_ptr(); + } + else + { + unsigned number_value = number.ToNumber().Uint32Value(); + + if (number_value < 1) + { + ThrowError(args.Env(), "Number must be an integer greater than or equal to 1"); + return nearest_parameters_ptr(); + } + + params->number_of_results = number_value; + } + } + + return params; +} + +inline table_parameters_ptr argumentsToTableParameter(const Napi::CallbackInfo &args, + bool requires_multiple_coordinates) +{ + table_parameters_ptr params = std::make_unique(); + bool has_base_params = argumentsToParameter(args, params, requires_multiple_coordinates); + if (!has_base_params) + return table_parameters_ptr(); + + Napi::Object obj = args[0].As(); + if (obj.IsEmpty()) + return table_parameters_ptr(); + + if (obj.Has("sources")) + { + Napi::Value sources = obj.Get("sources"); + if (sources.IsEmpty()) + return table_parameters_ptr(); + + if (!sources.IsArray()) + { + ThrowError(args.Env(), "Sources must be an array of indices (or undefined)"); + return table_parameters_ptr(); + } + + Napi::Array sources_array = sources.As(); + for (uint32_t i = 0; i < sources_array.Length(); ++i) + { + Napi::Value source = sources_array.Get(i); + if (source.IsEmpty()) + return table_parameters_ptr(); + + if (IsUnsignedInteger(source)) + { + size_t source_value = source.ToNumber().Uint32Value(); + if (source_value >= params->coordinates.size()) + { + ThrowError(args.Env(), + "Source indices must be less than the number of coordinates"); + return table_parameters_ptr(); + } + + params->sources.push_back(source.ToNumber().Uint32Value()); + } + else + { + ThrowError(args.Env(), "Source must be an integer"); + return table_parameters_ptr(); + } + } + } + + if (obj.Has("destinations")) + { + Napi::Value destinations = obj.Get("destinations"); + if (destinations.IsEmpty()) + return table_parameters_ptr(); + + if (!destinations.IsArray()) + { + ThrowError(args.Env(), "Destinations must be an array of indices (or undefined)"); + return table_parameters_ptr(); + } + + Napi::Array destinations_array = destinations.As(); + for (uint32_t i = 0; i < destinations_array.Length(); ++i) + { + Napi::Value destination = destinations_array.Get(i); + if (destination.IsEmpty()) + return table_parameters_ptr(); + + if (IsUnsignedInteger(destination)) + { + size_t destination_value = destination.ToNumber().Uint32Value(); + if (destination_value >= params->coordinates.size()) + { + ThrowError(args.Env(), + "Destination indices must be less than the number " + "of coordinates"); + return table_parameters_ptr(); + } + + params->destinations.push_back(destination_value); + } + else + { + ThrowError(args.Env(), "Destination must be an integer"); + return table_parameters_ptr(); + } + } + } + + if (obj.Has("annotations")) + { + Napi::Value annotations = obj.Get("annotations"); + if (annotations.IsEmpty()) + return table_parameters_ptr(); + + if (!annotations.IsArray()) + { + ThrowError(args.Env(), + "Annotations must an array containing 'duration' or 'distance', or both"); + return table_parameters_ptr(); + } + + params->annotations = osrm::TableParameters::AnnotationsType::None; + + Napi::Array annotations_array = annotations.As(); + for (std::size_t i = 0; i < annotations_array.Length(); ++i) + { + std::string annotations_str = annotations_array.Get(i).ToString().Utf8Value(); + + if (annotations_str == "duration") + { + params->annotations = + params->annotations | osrm::TableParameters::AnnotationsType::Duration; + } + else if (annotations_str == "distance") + { + params->annotations = + params->annotations | osrm::TableParameters::AnnotationsType::Distance; + } + else + { + ThrowError(args.Env(), "this 'annotations' param is not supported"); + return table_parameters_ptr(); + } + } + } + + if (obj.Has("fallback_speed")) + { + auto fallback_speed = obj.Get("fallback_speed"); + + if (!fallback_speed.IsNumber()) + { + ThrowError(args.Env(), "fallback_speed must be a number"); + return table_parameters_ptr(); + } + else if (fallback_speed.ToNumber().DoubleValue() <= 0) + { + ThrowError(args.Env(), "fallback_speed must be > 0"); + return table_parameters_ptr(); + } + + params->fallback_speed = fallback_speed.ToNumber().DoubleValue(); + } + + if (obj.Has("fallback_coordinate")) + { + auto fallback_coordinate = obj.Get("fallback_coordinate"); + + if (!fallback_coordinate.IsString()) + { + ThrowError(args.Env(), "fallback_coordinate must be a string: [input, snapped]"); + return table_parameters_ptr(); + } + + std::string fallback_coordinate_str = fallback_coordinate.ToString().Utf8Value(); + + if (fallback_coordinate_str == "snapped") + { + params->fallback_coordinate_type = + osrm::TableParameters::FallbackCoordinateType::Snapped; + } + else if (fallback_coordinate_str == "input") + { + params->fallback_coordinate_type = osrm::TableParameters::FallbackCoordinateType::Input; + } + else + { + ThrowError(args.Env(), "'fallback_coordinate' param must be one of [input, snapped]"); + return table_parameters_ptr(); + } + } + + if (obj.Has("scale_factor")) + { + auto scale_factor = obj.Get("scale_factor"); + + if (!scale_factor.IsNumber()) + { + ThrowError(args.Env(), "scale_factor must be a number"); + return table_parameters_ptr(); + } + else if (scale_factor.ToNumber().DoubleValue() <= 0) + { + ThrowError(args.Env(), "scale_factor must be > 0"); + return table_parameters_ptr(); + } + + params->scale_factor = scale_factor.ToNumber().DoubleValue(); + } + + return params; +} + +inline trip_parameters_ptr argumentsToTripParameter(const Napi::CallbackInfo &args, + bool requires_multiple_coordinates) +{ + trip_parameters_ptr params = std::make_unique(); + bool has_base_params = argumentsToParameter(args, params, requires_multiple_coordinates); + if (!has_base_params) + return trip_parameters_ptr(); + + Napi::Object obj = args[0].As(); + + bool parsedSuccessfully = parseCommonParameters(obj, params); + if (!parsedSuccessfully) + { + return trip_parameters_ptr(); + } + + if (obj.Has("roundtrip")) + { + auto roundtrip = obj.Get("roundtrip"); + if (roundtrip.IsEmpty()) + return trip_parameters_ptr(); + + if (roundtrip.IsBoolean()) + { + params->roundtrip = roundtrip.ToBoolean().Value(); + } + else + { + ThrowError(args.Env(), "'roundtrip' param must be a boolean"); + return trip_parameters_ptr(); + } + } + + if (obj.Has("source")) + { + Napi::Value source = obj.Get("source"); + if (source.IsEmpty()) + return trip_parameters_ptr(); + + if (!source.IsString()) + { + ThrowError(args.Env(), "Source must be a string: [any, first]"); + return trip_parameters_ptr(); + } + + std::string source_str = source.ToString().Utf8Value(); + + if (source_str == "first") + { + params->source = osrm::TripParameters::SourceType::First; + } + else if (source_str == "any") + { + params->source = osrm::TripParameters::SourceType::Any; + } + else + { + ThrowError(args.Env(), "'source' param must be one of [any, first]"); + return trip_parameters_ptr(); + } + } + + if (obj.Has("destination")) + { + Napi::Value destination = obj.Get("destination"); + if (destination.IsEmpty()) + return trip_parameters_ptr(); + + if (!destination.IsString()) + { + ThrowError(args.Env(), "Destination must be a string: [any, last]"); + return trip_parameters_ptr(); + } + + std::string destination_str = destination.ToString().Utf8Value(); + + if (destination_str == "last") + { + params->destination = osrm::TripParameters::DestinationType::Last; + } + else if (destination_str == "any") + { + params->destination = osrm::TripParameters::DestinationType::Any; + } + else + { + ThrowError(args.Env(), "'destination' param must be one of [any, last]"); + return trip_parameters_ptr(); + } + } + + return params; +} + +inline match_parameters_ptr argumentsToMatchParameter(const Napi::CallbackInfo &args, + bool requires_multiple_coordinates) +{ + match_parameters_ptr params = std::make_unique(); + bool has_base_params = argumentsToParameter(args, params, requires_multiple_coordinates); + if (!has_base_params) + return match_parameters_ptr(); + + Napi::Object obj = args[0].As(); + + if (obj.Has("timestamps")) + { + Napi::Value timestamps = obj.Get("timestamps"); + if (timestamps.IsEmpty()) + return match_parameters_ptr(); + + if (!timestamps.IsArray()) + { + ThrowError(args.Env(), "Timestamps must be an array of integers (or undefined)"); + return match_parameters_ptr(); + } + + Napi::Array timestamps_array = timestamps.As(); + + if (params->coordinates.size() != timestamps_array.Length()) + { + ThrowError(args.Env(), + "Timestamp array must have the same size as the coordinates " + "array"); + return match_parameters_ptr(); + } + + for (uint32_t i = 0; i < timestamps_array.Length(); ++i) + { + Napi::Value timestamp = timestamps_array.Get(i); + if (timestamp.IsEmpty()) + return match_parameters_ptr(); + + if (!timestamp.IsNumber()) + { + ThrowError(args.Env(), "Timestamps array items must be numbers"); + return match_parameters_ptr(); + } + params->timestamps.emplace_back(timestamp.ToNumber().Int64Value()); + } + } + + if (obj.Has("gaps")) + { + Napi::Value gaps = obj.Get("gaps"); + if (gaps.IsEmpty()) + return match_parameters_ptr(); + + if (!gaps.IsString()) + { + ThrowError(args.Env(), "Gaps must be a string: [split, ignore]"); + return match_parameters_ptr(); + } + + std::string gaps_str = gaps.ToString().Utf8Value(); + + if (gaps_str == "split") + { + params->gaps = osrm::MatchParameters::GapsType::Split; + } + else if (gaps_str == "ignore") + { + params->gaps = osrm::MatchParameters::GapsType::Ignore; + } + else + { + ThrowError(args.Env(), "'gaps' param must be one of [split, ignore]"); + return match_parameters_ptr(); + } + } + + if (obj.Has("tidy")) + { + Napi::Value tidy = obj.Get("tidy"); + if (tidy.IsEmpty()) + return match_parameters_ptr(); + + if (!tidy.IsBoolean()) + { + ThrowError(args.Env(), "tidy must be of type Boolean"); + return match_parameters_ptr(); + } + + params->tidy = tidy.ToBoolean().Value(); + } + + if (obj.Has("waypoints")) + { + Napi::Value waypoints = obj.Get("waypoints"); + if (waypoints.IsEmpty()) + return match_parameters_ptr(); + + // must be array + if (!waypoints.IsArray()) + { + ThrowError( + args.Env(), + "Waypoints must be an array of integers corresponding to the input coordinates."); + return match_parameters_ptr(); + } + + auto waypoints_array = waypoints.As(); + // must have at least two elements + if (waypoints_array.Length() < 2) + { + ThrowError(args.Env(), "At least two waypoints must be provided"); + return match_parameters_ptr(); + } + auto coords_size = params->coordinates.size(); + auto waypoints_array_size = waypoints_array.Length(); + + const auto first_index = + waypoints_array.Get(static_cast(0)).ToNumber().Uint32Value(); + const auto last_index = + waypoints_array.Get(waypoints_array_size - 1).ToNumber().Uint32Value(); + if (first_index != 0 || last_index != coords_size - 1) + { + ThrowError(args.Env(), + "First and last waypoints values must correspond to first and last " + "coordinate indices"); + return match_parameters_ptr(); + } + + for (uint32_t i = 0; i < waypoints_array_size; ++i) + { + Napi::Value waypoint_value = waypoints_array.Get(i); + // all elements must be numbers + if (!waypoint_value.IsNumber()) + { + ThrowError(args.Env(), "Waypoint values must be an array of integers"); + return match_parameters_ptr(); + } + // check that the waypoint index corresponds with an inpute coordinate + const auto index = waypoint_value.ToNumber().Uint32Value(); + if (index >= coords_size) + { + ThrowError(args.Env(), + "Waypoints must correspond with the index of an input coordinate"); + return match_parameters_ptr(); + } + params->waypoints.emplace_back(index); + } + } + + bool parsedSuccessfully = parseCommonParameters(obj, params); + if (!parsedSuccessfully) + { + return match_parameters_ptr(); + } + + return params; +} + +} // namespace node_osrm + +#endif From c579436a78255482724a7f4ae4eb044445a6d8a9 Mon Sep 17 00:00:00 2001 From: Siarhei Fedartsou Date: Tue, 21 May 2024 20:52:17 +0200 Subject: [PATCH 5/9] Remove src/nodejs files --- src/nodejs/json_v8_renderer.hpp | 68 -- src/nodejs/node_osrm.hpp | 32 - src/nodejs/node_osrm_support.hpp | 1706 ------------------------------ 3 files changed, 1806 deletions(-) delete mode 100644 src/nodejs/json_v8_renderer.hpp delete mode 100644 src/nodejs/node_osrm.hpp delete mode 100644 src/nodejs/node_osrm_support.hpp diff --git a/src/nodejs/json_v8_renderer.hpp b/src/nodejs/json_v8_renderer.hpp deleted file mode 100644 index 4b8bbd193d8..00000000000 --- a/src/nodejs/json_v8_renderer.hpp +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef OSRM_BINDINGS_NODE_JSON_V8_RENDERER_HPP -#define OSRM_BINDINGS_NODE_JSON_V8_RENDERER_HPP - -#include "osrm/json_container.hpp" -#include - -#include - -namespace node_osrm -{ - -struct V8Renderer -{ - explicit V8Renderer(const Napi::Env &env, Napi::Value &out) : env(env), out(out) {} - - void operator()(const osrm::json::String &string) const - { - out = Napi::String::New(env, string.value); - } - - void operator()(const osrm::json::Number &number) const - { - out = Napi::Number::New(env, number.value); - } - - void operator()(const osrm::json::Object &object) const - { - Napi::Object obj = Napi::Object::New(env); - for (const auto &keyValue : object.values) - { - Napi::Value child; - mapbox::util::apply_visitor(V8Renderer(env, child), keyValue.second); - obj.Set(keyValue.first, child); - } - out = obj; - } - - void operator()(const osrm::json::Array &array) const - { - Napi::Array a = Napi::Array::New(env, array.values.size()); - for (auto i = 0u; i < array.values.size(); ++i) - { - Napi::Value child; - mapbox::util::apply_visitor(V8Renderer(env, child), array.values[i]); - a.Set(i, child); - } - out = a; - } - - void operator()(const osrm::json::True &) const { out = Napi::Boolean::New(env, true); } - - void operator()(const osrm::json::False &) const { out = Napi::Boolean::New(env, false); } - - void operator()(const osrm::json::Null &) const { out = env.Null(); } - - private: - const Napi::Env &env; - Napi::Value &out; -}; - -inline void renderToV8(const Napi::Env &env, Napi::Value &out, const osrm::json::Object &object) -{ - V8Renderer renderer(env, out); - renderer(object); -} -} // namespace node_osrm - -#endif // JSON_V8_RENDERER_HPP diff --git a/src/nodejs/node_osrm.hpp b/src/nodejs/node_osrm.hpp deleted file mode 100644 index f85fb536235..00000000000 --- a/src/nodejs/node_osrm.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef OSRM_BINDINGS_NODE_HPP -#define OSRM_BINDINGS_NODE_HPP - -#include "osrm/osrm_fwd.hpp" - -#include - -#include - -namespace node_osrm -{ - -class Engine final : public Napi::ObjectWrap -{ - public: - static Napi::Object Init(Napi::Env env, Napi::Object exports); - Engine(const Napi::CallbackInfo &info); - - std::shared_ptr this_; - - private: - Napi::Value route(const Napi::CallbackInfo &info); - Napi::Value nearest(const Napi::CallbackInfo &info); - Napi::Value table(const Napi::CallbackInfo &info); - Napi::Value tile(const Napi::CallbackInfo &info); - Napi::Value match(const Napi::CallbackInfo &info); - Napi::Value trip(const Napi::CallbackInfo &info); -}; - -} // namespace node_osrm - -#endif diff --git a/src/nodejs/node_osrm_support.hpp b/src/nodejs/node_osrm_support.hpp deleted file mode 100644 index 5296dc4ed3b..00000000000 --- a/src/nodejs/node_osrm_support.hpp +++ /dev/null @@ -1,1706 +0,0 @@ -#ifndef OSRM_BINDINGS_NODE_SUPPORT_HPP -#define OSRM_BINDINGS_NODE_SUPPORT_HPP - -#include "nodejs/json_v8_renderer.hpp" -#include "engine/api/flatbuffers/fbresult_generated.h" -#include "osrm/approach.hpp" -#include "osrm/bearing.hpp" -#include "osrm/coordinate.hpp" -#include "osrm/engine_config.hpp" -#include "osrm/json_container.hpp" -#include "osrm/match_parameters.hpp" -#include "osrm/nearest_parameters.hpp" -#include "osrm/osrm.hpp" -#include "osrm/route_parameters.hpp" -#include "osrm/status.hpp" -#include "osrm/storage_config.hpp" -#include "osrm/table_parameters.hpp" -#include "osrm/tile_parameters.hpp" -#include "osrm/trip_parameters.hpp" -#include "util/json_renderer.hpp" -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -namespace node_osrm -{ - -using engine_config_ptr = std::unique_ptr; -using route_parameters_ptr = std::unique_ptr; -using trip_parameters_ptr = std::unique_ptr; -using tile_parameters_ptr = std::unique_ptr; -using match_parameters_ptr = std::unique_ptr; -using nearest_parameters_ptr = std::unique_ptr; -using table_parameters_ptr = std::unique_ptr; - -struct PluginParameters -{ - bool renderToBuffer = false; -}; - -using ObjectOrString = typename mapbox::util::variant; - -template inline Napi::Value render(const Napi::Env &env, const ResultT &result); - -template <> Napi::Value inline render(const Napi::Env &env, const std::string &result) -{ - return Napi::Buffer::Copy(env, result.data(), result.size()); -} - -template <> Napi::Value inline render(const Napi::Env &env, const ObjectOrString &result) -{ - if (result.is()) - { - // Convert osrm::json object tree into matching v8 object tree - Napi::Value value; - renderToV8(env, value, result.get()); - return value; - } - else - { - // Return the string object as a node Buffer - return Napi::Buffer::Copy( - env, result.get().data(), result.get().size()); - } -} - -inline bool IsUnsignedInteger(const Napi::Value &value) -{ - if (!value.IsNumber()) - { - return false; - } - const auto doubleValue = value.ToNumber().DoubleValue(); - return doubleValue >= 0.0 && std::floor(doubleValue) == doubleValue; -} - -inline void ParseResult(const osrm::Status &result_status, osrm::json::Object &result) -{ - const auto code_iter = result.values.find("code"); - const auto end_iter = result.values.end(); - - BOOST_ASSERT(code_iter != end_iter); - - if (result_status == osrm::Status::Error) - { - throw std::logic_error(code_iter->second.get().value.c_str()); - } - - result.values.erase(code_iter); - const auto message_iter = result.values.find("message"); - if (message_iter != end_iter) - { - result.values.erase(message_iter); - } -} - -inline void ParseResult(const osrm::Status & /*result_status*/, const std::string & /*unused*/) {} -inline void ParseResult(const osrm::Status &result_status, - const flatbuffers::FlatBufferBuilder &fbs_builder) -{ - auto fbs_result = osrm::engine::api::fbresult::GetFBResult(fbs_builder.GetBufferPointer()); - - if (result_status == osrm::Status::Error) - { - BOOST_ASSERT(fbs_result->code()); - throw std::logic_error(fbs_result->code()->message()->c_str()); - } -} - -inline void ThrowError(const Napi::Env &env, const char *message) -{ - Napi::Error::New(env, message).ThrowAsJavaScriptException(); -} - -inline void ThrowTypeError(const Napi::Env &env, const char *message) -{ - Napi::TypeError::New(env, message).ThrowAsJavaScriptException(); -} - -inline engine_config_ptr argumentsToEngineConfig(const Napi::CallbackInfo &args) -{ - Napi::HandleScope scope(args.Env()); - auto engine_config = std::make_unique(); - - if (args.Length() == 0) - { - return engine_config; - } - else if (args.Length() > 1) - { - ThrowError(args.Env(), "Only accepts one parameter"); - return engine_config_ptr(); - } - - BOOST_ASSERT(args.Length() == 1); - - if (args[0].IsString()) - { - engine_config->storage_config = osrm::StorageConfig(args[0].ToString().Utf8Value()); - engine_config->use_shared_memory = false; - return engine_config; - } - else if (!args[0].IsObject()) - { - ThrowError(args.Env(), "Parameter must be a path or options object"); - return engine_config_ptr(); - } - - BOOST_ASSERT(args[0].IsObject()); - auto params = args[0].As(); - - auto path = params.Get("path"); - if (path.IsEmpty()) - return engine_config_ptr(); - - auto memory_file = params.Get("memory_file"); - if (memory_file.IsEmpty()) - return engine_config_ptr(); - - auto shared_memory = params.Get("shared_memory"); - if (shared_memory.IsEmpty()) - return engine_config_ptr(); - - auto mmap_memory = params.Get("mmap_memory"); - if (mmap_memory.IsEmpty()) - return engine_config_ptr(); - - if (!memory_file.IsUndefined()) - { - if (path.IsUndefined()) - { - ThrowError(args.Env(), "memory_file option requires a path to a file."); - return engine_config_ptr(); - } - - engine_config->memory_file = memory_file.ToString().Utf8Value(); - } - - auto dataset_name = params.Get("dataset_name"); - if (dataset_name.IsEmpty()) - return engine_config_ptr(); - if (!dataset_name.IsUndefined()) - { - if (dataset_name.IsString()) - { - engine_config->dataset_name = dataset_name.ToString().Utf8Value(); - } - else - { - ThrowError(args.Env(), "dataset_name needs to be a string"); - return engine_config_ptr(); - } - } - - if (!path.IsUndefined()) - { - engine_config->storage_config = osrm::StorageConfig(path.ToString().Utf8Value()); - - engine_config->use_shared_memory = false; - } - if (!shared_memory.IsUndefined()) - { - if (shared_memory.IsBoolean()) - { - engine_config->use_shared_memory = shared_memory.ToBoolean().Value(); - } - else - { - ThrowError(args.Env(), "Shared_memory option must be a boolean"); - return engine_config_ptr(); - } - } - if (!mmap_memory.IsUndefined()) - { - if (mmap_memory.IsBoolean()) - { - engine_config->use_mmap = mmap_memory.ToBoolean().Value(); - } - else - { - ThrowError(args.Env(), "mmap_memory option must be a boolean"); - return engine_config_ptr(); - } - } - - if (path.IsUndefined() && !engine_config->use_shared_memory) - { - ThrowError(args.Env(), - "Shared_memory must be enabled if no path is " - "specified"); - return engine_config_ptr(); - } - - auto algorithm = params.Get("algorithm"); - if (algorithm.IsEmpty()) - return engine_config_ptr(); - - if (algorithm.IsString()) - { - auto algorithm_str = algorithm.ToString().Utf8Value(); - if (algorithm_str == "CH") - { - engine_config->algorithm = osrm::EngineConfig::Algorithm::CH; - } - else if (algorithm_str == "CoreCH") - { - engine_config->algorithm = osrm::EngineConfig::Algorithm::CH; - } - else if (algorithm_str == "MLD") - { - engine_config->algorithm = osrm::EngineConfig::Algorithm::MLD; - } - else - { - ThrowError(args.Env(), "algorithm option must be one of 'CH', 'CoreCH', or 'MLD'."); - return engine_config_ptr(); - } - } - else if (!algorithm.IsUndefined()) - { - ThrowError(args.Env(), - "algorithm option must be a string and one of 'CH', 'CoreCH', or 'MLD'."); - return engine_config_ptr(); - } - - // Set EngineConfig system-wide limits on construction, if requested - - auto max_locations_trip = params.Get("max_locations_trip"); - auto max_locations_viaroute = params.Get("max_locations_viaroute"); - auto max_locations_distance_table = params.Get("max_locations_distance_table"); - auto max_locations_map_matching = params.Get("max_locations_map_matching"); - auto max_results_nearest = params.Get("max_results_nearest"); - auto max_alternatives = params.Get("max_alternatives"); - auto max_radius_map_matching = params.Get("max_radius_map_matching"); - auto default_radius = params.Get("default_radius"); - - if (!max_locations_trip.IsUndefined() && !max_locations_trip.IsNumber()) - { - ThrowError(args.Env(), "max_locations_trip must be an integral number"); - return engine_config_ptr(); - } - if (!max_locations_viaroute.IsUndefined() && !max_locations_viaroute.IsNumber()) - { - ThrowError(args.Env(), "max_locations_viaroute must be an integral number"); - return engine_config_ptr(); - } - if (!max_locations_distance_table.IsUndefined() && !max_locations_distance_table.IsNumber()) - { - ThrowError(args.Env(), "max_locations_distance_table must be an integral number"); - return engine_config_ptr(); - } - if (!max_locations_map_matching.IsUndefined() && !max_locations_map_matching.IsNumber()) - { - ThrowError(args.Env(), "max_locations_map_matching must be an integral number"); - return engine_config_ptr(); - } - if (!max_results_nearest.IsUndefined() && !max_results_nearest.IsNumber()) - { - ThrowError(args.Env(), "max_results_nearest must be an integral number"); - return engine_config_ptr(); - } - if (!max_alternatives.IsUndefined() && !max_alternatives.IsNumber()) - { - ThrowError(args.Env(), "max_alternatives must be an integral number"); - return engine_config_ptr(); - } - if (!default_radius.IsUndefined() && !default_radius.IsNumber()) - { - ThrowError(args.Env(), "default_radius must be an integral number"); - return engine_config_ptr(); - } - - if (max_locations_trip.IsNumber()) - engine_config->max_locations_trip = max_locations_trip.ToNumber().Int32Value(); - if (max_locations_viaroute.IsNumber()) - engine_config->max_locations_viaroute = max_locations_viaroute.ToNumber().Int32Value(); - if (max_locations_distance_table.IsNumber()) - engine_config->max_locations_distance_table = - max_locations_distance_table.ToNumber().Int32Value(); - if (max_locations_map_matching.IsNumber()) - engine_config->max_locations_map_matching = - max_locations_map_matching.ToNumber().Int32Value(); - if (max_results_nearest.IsNumber()) - engine_config->max_results_nearest = max_results_nearest.ToNumber().Int32Value(); - if (max_alternatives.IsNumber()) - engine_config->max_alternatives = max_alternatives.ToNumber().Int32Value(); - if (max_radius_map_matching.IsNumber()) - engine_config->max_radius_map_matching = max_radius_map_matching.ToNumber().DoubleValue(); - if (default_radius.IsNumber()) - engine_config->default_radius = default_radius.ToNumber().DoubleValue(); - - return engine_config; -} - -inline boost::optional> -parseCoordinateArray(const Napi::Array &coordinates_array) -{ - Napi::HandleScope scope(coordinates_array.Env()); - boost::optional> resulting_coordinates; - std::vector temp_coordinates; - - for (uint32_t i = 0; i < coordinates_array.Length(); ++i) - { - Napi::Value coordinate = coordinates_array.Get(i); - if (coordinate.IsEmpty()) - return resulting_coordinates; - - if (!coordinate.IsArray()) - { - ThrowError(coordinates_array.Env(), "Coordinates must be an array of (lon/lat) pairs"); - return resulting_coordinates; - } - - Napi::Array coordinate_pair = coordinate.As(); - if (coordinate_pair.Length() != 2) - { - ThrowError(coordinates_array.Env(), "Coordinates must be an array of (lon/lat) pairs"); - return resulting_coordinates; - } - - if (!coordinate_pair.Get(static_cast(0)).IsNumber() || - !coordinate_pair.Get(static_cast(1)).IsNumber()) - { - ThrowError(coordinates_array.Env(), - "Each member of a coordinate pair must be a number"); - return resulting_coordinates; - } - - double lon = coordinate_pair.Get(static_cast(0)).As().DoubleValue(); - double lat = coordinate_pair.Get(static_cast(1)).As().DoubleValue(); - - if (std::isnan(lon) || std::isnan(lat) || std::isinf(lon) || std::isinf(lat)) - { - ThrowError(coordinates_array.Env(), "Lng/Lat coordinates must be valid numbers"); - return resulting_coordinates; - } - - if (lon > 180 || lon < -180 || lat > 90 || lat < -90) - { - ThrowError(coordinates_array.Env(), - "Lng/Lat coordinates must be within world bounds " - "(-180 < lng < 180, -90 < lat < 90)"); - return resulting_coordinates; - } - - temp_coordinates.emplace_back(osrm::util::FloatLongitude{std::move(lon)}, - osrm::util::FloatLatitude{std::move(lat)}); - } - - resulting_coordinates = boost::make_optional(std::move(temp_coordinates)); - return resulting_coordinates; -} - -// Parses all the non-service specific parameters -template -inline bool argumentsToParameter(const Napi::CallbackInfo &args, - ParamType ¶ms, - bool requires_multiple_coordinates) -{ - Napi::HandleScope scope(args.Env()); - - if (args.Length() < 2) - { - ThrowTypeError(args.Env(), "Two arguments required"); - return false; - } - - if (!args[0].IsObject()) - { - ThrowTypeError(args.Env(), "First arg must be an object"); - return false; - } - - Napi::Object obj = args[0].As(); - - Napi::Value coordinates = obj.Get("coordinates"); - if (coordinates.IsEmpty()) - return false; - - if (coordinates.IsUndefined()) - { - ThrowError(args.Env(), "Must provide a coordinates property"); - return false; - } - else if (coordinates.IsArray()) - { - auto coordinates_array = coordinates.As(); - if (coordinates_array.Length() < 2 && requires_multiple_coordinates) - { - ThrowError(args.Env(), "At least two coordinates must be provided"); - return false; - } - else if (!requires_multiple_coordinates && coordinates_array.Length() != 1) - { - ThrowError(args.Env(), "Exactly one coordinate pair must be provided"); - return false; - } - auto maybe_coordinates = parseCoordinateArray(coordinates_array); - if (maybe_coordinates) - { - std::copy(maybe_coordinates->begin(), - maybe_coordinates->end(), - std::back_inserter(params->coordinates)); - } - else - { - return false; - } - } - else if (!coordinates.IsUndefined()) - { - BOOST_ASSERT(!coordinates.IsArray()); - ThrowError(args.Env(), "Coordinates must be an array of (lon/lat) pairs"); - return false; - } - - if (obj.Has("approaches")) - { - Napi::Value approaches = obj.Get("approaches"); - if (approaches.IsEmpty()) - return false; - - if (!approaches.IsArray()) - { - ThrowError(args.Env(), "Approaches must be an arrays of strings"); - return false; - } - - auto approaches_array = approaches.As(); - - if (approaches_array.Length() != params->coordinates.size()) - { - ThrowError(args.Env(), - "Approaches array must have the same length as coordinates array"); - return false; - } - - for (uint32_t i = 0; i < approaches_array.Length(); ++i) - { - Napi::Value approach_raw = approaches_array.Get(i); - if (approach_raw.IsEmpty()) - return false; - - if (approach_raw.IsNull()) - { - params->approaches.emplace_back(); - } - else if (approach_raw.IsString()) - { - std::string approach_str = approach_raw.ToString().Utf8Value(); - if (approach_str == "curb") - { - params->approaches.push_back(osrm::Approach::CURB); - } - else if (approach_str == "unrestricted") - { - params->approaches.push_back(osrm::Approach::UNRESTRICTED); - } - else - { - ThrowError(args.Env(), - "'approaches' param must be one of [curb, unrestricted]"); - return false; - } - } - else - { - ThrowError(args.Env(), "Approach must be a string: [curb, unrestricted] or null"); - return false; - } - } - } - - if (obj.Has("bearings")) - { - Napi::Value bearings = obj.Get("bearings"); - if (bearings.IsEmpty()) - return false; - - if (!bearings.IsArray()) - { - ThrowError(args.Env(), "Bearings must be an array of arrays of numbers"); - return false; - } - - auto bearings_array = bearings.As(); - - if (bearings_array.Length() != params->coordinates.size()) - { - ThrowError(args.Env(), "Bearings array must have the same length as coordinates array"); - return false; - } - - for (uint32_t i = 0; i < bearings_array.Length(); ++i) - { - Napi::Value bearing_raw = bearings_array.Get(i); - if (bearing_raw.IsEmpty()) - return false; - - if (bearing_raw.IsNull()) - { - params->bearings.emplace_back(); - } - else if (bearing_raw.IsArray()) - { - auto bearing_pair = bearing_raw.As(); - if (bearing_pair.Length() == 2) - { - if (!bearing_pair.Get(static_cast(0)).IsNumber() || - !bearing_pair.Get(static_cast(1)).IsNumber()) - { - ThrowError(args.Env(), "Bearing values need to be numbers in range 0..360"); - return false; - } - - const auto bearing = - bearing_pair.Get(static_cast(0)).ToNumber().Int32Value(); - const auto range = - bearing_pair.Get(static_cast(1)).ToNumber().Int32Value(); - - if (bearing < 0 || bearing > 360 || range < 0 || range > 180) - { - ThrowError(args.Env(), "Bearing values need to be in range 0..360, 0..180"); - return false; - } - - params->bearings.push_back( - osrm::Bearing{static_cast(bearing), static_cast(range)}); - } - else - { - ThrowError(args.Env(), "Bearing must be an array of [bearing, range] or null"); - return false; - } - } - else - { - ThrowError(args.Env(), "Bearing must be an array of [bearing, range] or null"); - return false; - } - } - } - - if (obj.Has("hints")) - { - Napi::Value hints = obj.Get("hints"); - if (hints.IsEmpty()) - return false; - - if (!hints.IsArray()) - { - ThrowError(args.Env(), "Hints must be an array of strings/null"); - return false; - } - - Napi::Array hints_array = hints.As(); - - if (hints_array.Length() != params->coordinates.size()) - { - ThrowError(args.Env(), "Hints array must have the same length as coordinates array"); - return false; - } - - for (uint32_t i = 0; i < hints_array.Length(); ++i) - { - Napi::Value hint = hints_array.Get(i); - if (hint.IsEmpty()) - return false; - - if (hint.IsString()) - { - if (hint.ToString().Utf8Value().length() == 0) - { - ThrowError(args.Env(), "Hint cannot be an empty string"); - return false; - } - - params->hints.emplace_back( - osrm::engine::Hint::FromBase64(hint.ToString().Utf8Value())); - } - else if (hint.IsNull()) - { - params->hints.emplace_back(); - } - else - { - ThrowError(args.Env(), "Hint must be null or string"); - return false; - } - } - } - - if (obj.Has("radiuses")) - { - Napi::Value radiuses = obj.Get("radiuses"); - if (radiuses.IsEmpty()) - return false; - - if (!radiuses.IsArray()) - { - ThrowError(args.Env(), "Radiuses must be an array of non-negative doubles or null"); - return false; - } - - Napi::Array radiuses_array = radiuses.As(); - - if (radiuses_array.Length() != params->coordinates.size()) - { - ThrowError(args.Env(), "Radiuses array must have the same length as coordinates array"); - return false; - } - - for (uint32_t i = 0; i < radiuses_array.Length(); ++i) - { - Napi::Value radius = radiuses_array.Get(i); - if (radius.IsEmpty()) - return false; - - if (radius.IsNull()) - { - params->radiuses.emplace_back(); - } - else if (radius.IsNumber() && radius.ToNumber().DoubleValue() >= 0) - { - params->radiuses.push_back(radius.ToNumber().DoubleValue()); - } - else - { - ThrowError(args.Env(), "Radius must be non-negative double or null"); - return false; - } - } - } - - if (obj.Has("generate_hints")) - { - Napi::Value generate_hints = obj.Get("generate_hints"); - if (generate_hints.IsEmpty()) - return false; - - if (!generate_hints.IsBoolean()) - { - ThrowError(args.Env(), "generate_hints must be of type Boolean"); - return false; - } - - params->generate_hints = generate_hints.ToBoolean().Value(); - } - - if (obj.Has("skip_waypoints")) - { - Napi::Value skip_waypoints = obj.Get("skip_waypoints"); - if (skip_waypoints.IsEmpty()) - return false; - - if (!skip_waypoints.IsBoolean()) - { - ThrowError(args.Env(), "skip_waypoints must be of type Boolean"); - return false; - } - - params->skip_waypoints = skip_waypoints.ToBoolean().Value(); - } - - if (obj.Has("exclude")) - { - Napi::Value exclude = obj.Get("exclude"); - if (exclude.IsEmpty()) - return false; - - if (!exclude.IsArray()) - { - ThrowError(args.Env(), "Exclude must be an array of strings or empty"); - return false; - } - - Napi::Array exclude_array = exclude.As(); - - for (uint32_t i = 0; i < exclude_array.Length(); ++i) - { - Napi::Value class_name = exclude_array.Get(i); - if (class_name.IsEmpty()) - return false; - - if (class_name.IsString()) - { - std::string class_name_str = class_name.ToString().Utf8Value(); - params->exclude.emplace_back(std::move(class_name_str)); - } - else - { - ThrowError(args.Env(), "Exclude must be an array of strings or empty"); - return false; - } - } - } - - if (obj.Has("format")) - { - Napi::Value format = obj.Get("format"); - if (format.IsEmpty()) - { - return false; - } - - if (!format.IsString()) - { - ThrowError(args.Env(), "format must be a string: \"json\" or \"flatbuffers\""); - return false; - } - - std::string format_str = format.ToString().Utf8Value(); - if (format_str == "json") - { - params->format = osrm::engine::api::BaseParameters::OutputFormatType::JSON; - } - else if (format_str == "flatbuffers") - { - params->format = osrm::engine::api::BaseParameters::OutputFormatType::FLATBUFFERS; - } - else - { - ThrowError(args.Env(), "format must be a string: \"json\" or \"flatbuffers\""); - return false; - } - } - - if (obj.Has("snapping")) - { - Napi::Value snapping = obj.Get("snapping"); - if (snapping.IsEmpty()) - return false; - - if (!snapping.IsString()) - { - ThrowError(args.Env(), "Snapping must be a string: [default, any]"); - return false; - } - - std::string snapping_str = snapping.ToString().Utf8Value(); - - if (snapping_str == "default") - { - params->snapping = osrm::RouteParameters::SnappingType::Default; - } - else if (snapping_str == "any") - { - params->snapping = osrm::RouteParameters::SnappingType::Any; - } - else - { - ThrowError(args.Env(), "'snapping' param must be one of [default, any]"); - return false; - } - } - - return true; -} - -template -inline bool parseCommonParameters(const Napi::Object &obj, ParamType ¶ms) -{ - if (obj.Has("steps")) - { - auto steps = obj.Get("steps"); - if (steps.IsEmpty()) - return false; - - if (steps.IsBoolean()) - { - params->steps = steps.ToBoolean().Value(); - } - else - { - ThrowError(obj.Env(), "'steps' param must be a boolean"); - return false; - } - } - - if (obj.Has("annotations")) - { - auto annotations = obj.Get("annotations"); - if (annotations.IsEmpty()) - return false; - - if (annotations.IsBoolean()) - { - params->annotations = annotations.ToBoolean().Value(); - params->annotations_type = params->annotations - ? osrm::RouteParameters::AnnotationsType::All - : osrm::RouteParameters::AnnotationsType::None; - } - else if (annotations.IsArray()) - { - Napi::Array annotations_array = annotations.As(); - for (std::size_t i = 0; i < annotations_array.Length(); i++) - { - std::string annotations_str = annotations_array.Get(i).ToString().Utf8Value(); - - if (annotations_str == "duration") - { - params->annotations_type = - params->annotations_type | osrm::RouteParameters::AnnotationsType::Duration; - } - else if (annotations_str == "nodes") - { - params->annotations_type = - params->annotations_type | osrm::RouteParameters::AnnotationsType::Nodes; - } - else if (annotations_str == "distance") - { - params->annotations_type = - params->annotations_type | osrm::RouteParameters::AnnotationsType::Distance; - } - else if (annotations_str == "weight") - { - params->annotations_type = - params->annotations_type | osrm::RouteParameters::AnnotationsType::Weight; - } - else if (annotations_str == "datasources") - { - params->annotations_type = params->annotations_type | - osrm::RouteParameters::AnnotationsType::Datasources; - } - else if (annotations_str == "speed") - { - params->annotations_type = - params->annotations_type | osrm::RouteParameters::AnnotationsType::Speed; - } - else - { - ThrowError(obj.Env(), "this 'annotations' param is not supported"); - return false; - } - - params->annotations = - params->annotations_type != osrm::RouteParameters::AnnotationsType::None; - } - } - else - { - ThrowError(obj.Env(), "this 'annotations' param is not supported"); - return false; - } - } - - if (obj.Has("geometries")) - { - Napi::Value geometries = obj.Get("geometries"); - if (geometries.IsEmpty()) - return false; - - if (!geometries.IsString()) - { - ThrowError(obj.Env(), "Geometries must be a string: [polyline, polyline6, geojson]"); - return false; - } - std::string geometries_str = geometries.ToString().Utf8Value(); - - if (geometries_str == "polyline") - { - params->geometries = osrm::RouteParameters::GeometriesType::Polyline; - } - else if (geometries_str == "polyline6") - { - params->geometries = osrm::RouteParameters::GeometriesType::Polyline6; - } - else if (geometries_str == "geojson") - { - params->geometries = osrm::RouteParameters::GeometriesType::GeoJSON; - } - else - { - ThrowError(obj.Env(), - "'geometries' param must be one of [polyline, polyline6, geojson]"); - return false; - } - } - - if (obj.Has("overview")) - { - Napi::Value overview = obj.Get("overview"); - if (overview.IsEmpty()) - return false; - - if (!overview.IsString()) - { - ThrowError(obj.Env(), "Overview must be a string: [simplified, full, false]"); - return false; - } - - std::string overview_str = overview.ToString().Utf8Value(); - - if (overview_str == "simplified") - { - params->overview = osrm::RouteParameters::OverviewType::Simplified; - } - else if (overview_str == "full") - { - params->overview = osrm::RouteParameters::OverviewType::Full; - } - else if (overview_str == "false") - { - params->overview = osrm::RouteParameters::OverviewType::False; - } - else - { - ThrowError(obj.Env(), "'overview' param must be one of [simplified, full, false]"); - return false; - } - } - - return true; -} - -inline PluginParameters argumentsToPluginParameters( - const Napi::CallbackInfo &args, - const boost::optional &output_format = {}) -{ - if (args.Length() < 3 || !args[1].IsObject()) - { - // output to buffer by default for Flatbuffers - return {output_format == osrm::engine::api::BaseParameters::OutputFormatType::FLATBUFFERS}; - } - Napi::Object obj = args[1].As(); - if (obj.Has("format")) - { - Napi::Value format = obj.Get("format"); - if (format.IsEmpty()) - { - return {}; - } - - if (!format.IsString()) - { - ThrowError(args.Env(), "format must be a string: \"object\" or \"buffer\""); - return {}; - } - - std::string format_str = format.ToString().Utf8Value(); - - if (format_str == "object") - { - if (output_format == osrm::engine::api::BaseParameters::OutputFormatType::FLATBUFFERS) - { - ThrowError(args.Env(), "Flatbuffers result can only output to buffer."); - return {true}; - } - return {false}; - } - else if (format_str == "buffer") - { - return {true}; - } - else if (format_str == "json_buffer") - { - if (output_format && - output_format != osrm::engine::api::BaseParameters::OutputFormatType::JSON) - { - ThrowError(args.Env(), - "Deprecated `json_buffer` can only be used with JSON format"); - } - return {true}; - } - else - { - ThrowError(args.Env(), "format must be a string: \"object\" or \"buffer\""); - return {}; - } - } - - // output to buffer by default for Flatbuffers - return {output_format == osrm::engine::api::BaseParameters::OutputFormatType::FLATBUFFERS}; -} - -inline route_parameters_ptr argumentsToRouteParameter(const Napi::CallbackInfo &args, - bool requires_multiple_coordinates) -{ - route_parameters_ptr params = std::make_unique(); - bool has_base_params = argumentsToParameter(args, params, requires_multiple_coordinates); - if (!has_base_params) - return route_parameters_ptr(); - - Napi::Object obj = args[0].As(); - - if (obj.Has("continue_straight")) - { - auto value = obj.Get("continue_straight"); - if (value.IsEmpty()) - return route_parameters_ptr(); - - if (!value.IsBoolean() && !value.IsNull()) - { - ThrowError(args.Env(), "'continue_straight' param must be boolean or null"); - return route_parameters_ptr(); - } - if (value.IsBoolean()) - { - params->continue_straight = value.ToBoolean().Value(); - } - } - - if (obj.Has("alternatives")) - { - auto value = obj.Get("alternatives"); - if (value.IsEmpty()) - return route_parameters_ptr(); - - if (value.IsBoolean()) - { - params->alternatives = value.ToBoolean().Value(); - params->number_of_alternatives = value.ToBoolean().Value() ? 1u : 0u; - } - else if (value.IsNumber()) - { - params->alternatives = value.ToBoolean().Value(); - params->number_of_alternatives = value.ToNumber().Int32Value(); - } - else - { - ThrowError(args.Env(), "'alternatives' param must be boolean or number"); - return route_parameters_ptr(); - } - } - - if (obj.Has("waypoints")) - { - Napi::Value waypoints = obj.Get("waypoints"); - if (waypoints.IsEmpty()) - return route_parameters_ptr(); - - // must be array - if (!waypoints.IsArray()) - { - ThrowError( - args.Env(), - "Waypoints must be an array of integers corresponding to the input coordinates."); - return route_parameters_ptr(); - } - - auto waypoints_array = waypoints.As(); - // must have at least two elements - if (waypoints_array.Length() < 2) - { - ThrowError(args.Env(), "At least two waypoints must be provided"); - return route_parameters_ptr(); - } - auto coords_size = params->coordinates.size(); - auto waypoints_array_size = waypoints_array.Length(); - - const auto first_index = - waypoints_array.Get(static_cast(0)).ToNumber().Uint32Value(); - const auto last_index = - waypoints_array.Get(waypoints_array_size - 1).ToNumber().Uint32Value(); - if (first_index != 0 || last_index != coords_size - 1) - { - ThrowError(args.Env(), - "First and last waypoints values must correspond to first and last " - "coordinate indices"); - return route_parameters_ptr(); - } - - for (uint32_t i = 0; i < waypoints_array_size; ++i) - { - Napi::Value waypoint_value = waypoints_array.Get(i); - // all elements must be numbers - if (!waypoint_value.IsNumber()) - { - ThrowError(args.Env(), "Waypoint values must be an array of integers"); - return route_parameters_ptr(); - } - // check that the waypoint index corresponds with an inpute coordinate - const auto index = waypoint_value.ToNumber().Uint32Value(); - if (index >= coords_size) - { - ThrowError(args.Env(), - "Waypoints must correspond with the index of an input coordinate"); - return route_parameters_ptr(); - } - params->waypoints.emplace_back(index); - } - - if (!params->waypoints.empty()) - { - for (std::size_t i = 0; i < params->waypoints.size() - 1; i++) - { - if (params->waypoints[i] >= params->waypoints[i + 1]) - { - ThrowError(args.Env(), "Waypoints must be supplied in increasing order"); - return route_parameters_ptr(); - } - } - } - } - - bool parsedSuccessfully = parseCommonParameters(obj, params); - if (!parsedSuccessfully) - { - return route_parameters_ptr(); - } - - return params; -} - -inline tile_parameters_ptr argumentsToTileParameters(const Napi::CallbackInfo &args, - bool /*unused*/) -{ - tile_parameters_ptr params = std::make_unique(); - - if (args.Length() < 2) - { - ThrowTypeError(args.Env(), "Coordinate object and callback required"); - return tile_parameters_ptr(); - } - - if (!args[0].IsArray()) - { - ThrowTypeError(args.Env(), "Parameter must be an array [x, y, z]"); - return tile_parameters_ptr(); - } - - Napi::Array array = args[0].As(); - - if (array.Length() != 3) - { - ThrowTypeError(args.Env(), "Parameter must be an array [x, y, z]"); - return tile_parameters_ptr(); - } - - Napi::Value x = array.Get(static_cast(0)); - Napi::Value y = array.Get(static_cast(1)); - Napi::Value z = array.Get(static_cast(2)); - if (x.IsEmpty() || y.IsEmpty() || z.IsEmpty()) - return tile_parameters_ptr(); - - if (!IsUnsignedInteger(x) && !x.IsUndefined()) - { - ThrowError(args.Env(), "Tile x coordinate must be unsigned interger"); - return tile_parameters_ptr(); - } - if (!IsUnsignedInteger(y) && !y.IsUndefined()) - { - ThrowError(args.Env(), "Tile y coordinate must be unsigned interger"); - return tile_parameters_ptr(); - } - if (!IsUnsignedInteger(z) && !z.IsUndefined()) - { - ThrowError(args.Env(), "Tile z coordinate must be unsigned interger"); - return tile_parameters_ptr(); - } - - params->x = x.ToNumber().Uint32Value(); - params->y = y.ToNumber().Uint32Value(); - params->z = z.ToNumber().Uint32Value(); - - if (!params->IsValid()) - { - ThrowError(args.Env(), "Invalid tile coordinates"); - return tile_parameters_ptr(); - } - - return params; -} - -inline nearest_parameters_ptr argumentsToNearestParameter(const Napi::CallbackInfo &args, - bool requires_multiple_coordinates) -{ - nearest_parameters_ptr params = std::make_unique(); - bool has_base_params = argumentsToParameter(args, params, requires_multiple_coordinates); - if (!has_base_params) - return nearest_parameters_ptr(); - - Napi::Object obj = args[0].As(); - if (obj.IsEmpty()) - return nearest_parameters_ptr(); - - if (obj.Has("number")) - { - Napi::Value number = obj.Get("number"); - - if (!IsUnsignedInteger(number)) - { - ThrowError(args.Env(), "Number must be an integer greater than or equal to 1"); - return nearest_parameters_ptr(); - } - else - { - unsigned number_value = number.ToNumber().Uint32Value(); - - if (number_value < 1) - { - ThrowError(args.Env(), "Number must be an integer greater than or equal to 1"); - return nearest_parameters_ptr(); - } - - params->number_of_results = number_value; - } - } - - return params; -} - -inline table_parameters_ptr argumentsToTableParameter(const Napi::CallbackInfo &args, - bool requires_multiple_coordinates) -{ - table_parameters_ptr params = std::make_unique(); - bool has_base_params = argumentsToParameter(args, params, requires_multiple_coordinates); - if (!has_base_params) - return table_parameters_ptr(); - - Napi::Object obj = args[0].As(); - if (obj.IsEmpty()) - return table_parameters_ptr(); - - if (obj.Has("sources")) - { - Napi::Value sources = obj.Get("sources"); - if (sources.IsEmpty()) - return table_parameters_ptr(); - - if (!sources.IsArray()) - { - ThrowError(args.Env(), "Sources must be an array of indices (or undefined)"); - return table_parameters_ptr(); - } - - Napi::Array sources_array = sources.As(); - for (uint32_t i = 0; i < sources_array.Length(); ++i) - { - Napi::Value source = sources_array.Get(i); - if (source.IsEmpty()) - return table_parameters_ptr(); - - if (IsUnsignedInteger(source)) - { - size_t source_value = source.ToNumber().Uint32Value(); - if (source_value >= params->coordinates.size()) - { - ThrowError(args.Env(), - "Source indices must be less than the number of coordinates"); - return table_parameters_ptr(); - } - - params->sources.push_back(source.ToNumber().Uint32Value()); - } - else - { - ThrowError(args.Env(), "Source must be an integer"); - return table_parameters_ptr(); - } - } - } - - if (obj.Has("destinations")) - { - Napi::Value destinations = obj.Get("destinations"); - if (destinations.IsEmpty()) - return table_parameters_ptr(); - - if (!destinations.IsArray()) - { - ThrowError(args.Env(), "Destinations must be an array of indices (or undefined)"); - return table_parameters_ptr(); - } - - Napi::Array destinations_array = destinations.As(); - for (uint32_t i = 0; i < destinations_array.Length(); ++i) - { - Napi::Value destination = destinations_array.Get(i); - if (destination.IsEmpty()) - return table_parameters_ptr(); - - if (IsUnsignedInteger(destination)) - { - size_t destination_value = destination.ToNumber().Uint32Value(); - if (destination_value >= params->coordinates.size()) - { - ThrowError(args.Env(), - "Destination indices must be less than the number " - "of coordinates"); - return table_parameters_ptr(); - } - - params->destinations.push_back(destination_value); - } - else - { - ThrowError(args.Env(), "Destination must be an integer"); - return table_parameters_ptr(); - } - } - } - - if (obj.Has("annotations")) - { - Napi::Value annotations = obj.Get("annotations"); - if (annotations.IsEmpty()) - return table_parameters_ptr(); - - if (!annotations.IsArray()) - { - ThrowError(args.Env(), - "Annotations must an array containing 'duration' or 'distance', or both"); - return table_parameters_ptr(); - } - - params->annotations = osrm::TableParameters::AnnotationsType::None; - - Napi::Array annotations_array = annotations.As(); - for (std::size_t i = 0; i < annotations_array.Length(); ++i) - { - std::string annotations_str = annotations_array.Get(i).ToString().Utf8Value(); - - if (annotations_str == "duration") - { - params->annotations = - params->annotations | osrm::TableParameters::AnnotationsType::Duration; - } - else if (annotations_str == "distance") - { - params->annotations = - params->annotations | osrm::TableParameters::AnnotationsType::Distance; - } - else - { - ThrowError(args.Env(), "this 'annotations' param is not supported"); - return table_parameters_ptr(); - } - } - } - - if (obj.Has("fallback_speed")) - { - auto fallback_speed = obj.Get("fallback_speed"); - - if (!fallback_speed.IsNumber()) - { - ThrowError(args.Env(), "fallback_speed must be a number"); - return table_parameters_ptr(); - } - else if (fallback_speed.ToNumber().DoubleValue() <= 0) - { - ThrowError(args.Env(), "fallback_speed must be > 0"); - return table_parameters_ptr(); - } - - params->fallback_speed = fallback_speed.ToNumber().DoubleValue(); - } - - if (obj.Has("fallback_coordinate")) - { - auto fallback_coordinate = obj.Get("fallback_coordinate"); - - if (!fallback_coordinate.IsString()) - { - ThrowError(args.Env(), "fallback_coordinate must be a string: [input, snapped]"); - return table_parameters_ptr(); - } - - std::string fallback_coordinate_str = fallback_coordinate.ToString().Utf8Value(); - - if (fallback_coordinate_str == "snapped") - { - params->fallback_coordinate_type = - osrm::TableParameters::FallbackCoordinateType::Snapped; - } - else if (fallback_coordinate_str == "input") - { - params->fallback_coordinate_type = osrm::TableParameters::FallbackCoordinateType::Input; - } - else - { - ThrowError(args.Env(), "'fallback_coordinate' param must be one of [input, snapped]"); - return table_parameters_ptr(); - } - } - - if (obj.Has("scale_factor")) - { - auto scale_factor = obj.Get("scale_factor"); - - if (!scale_factor.IsNumber()) - { - ThrowError(args.Env(), "scale_factor must be a number"); - return table_parameters_ptr(); - } - else if (scale_factor.ToNumber().DoubleValue() <= 0) - { - ThrowError(args.Env(), "scale_factor must be > 0"); - return table_parameters_ptr(); - } - - params->scale_factor = scale_factor.ToNumber().DoubleValue(); - } - - return params; -} - -inline trip_parameters_ptr argumentsToTripParameter(const Napi::CallbackInfo &args, - bool requires_multiple_coordinates) -{ - trip_parameters_ptr params = std::make_unique(); - bool has_base_params = argumentsToParameter(args, params, requires_multiple_coordinates); - if (!has_base_params) - return trip_parameters_ptr(); - - Napi::Object obj = args[0].As(); - - bool parsedSuccessfully = parseCommonParameters(obj, params); - if (!parsedSuccessfully) - { - return trip_parameters_ptr(); - } - - if (obj.Has("roundtrip")) - { - auto roundtrip = obj.Get("roundtrip"); - if (roundtrip.IsEmpty()) - return trip_parameters_ptr(); - - if (roundtrip.IsBoolean()) - { - params->roundtrip = roundtrip.ToBoolean().Value(); - } - else - { - ThrowError(args.Env(), "'roundtrip' param must be a boolean"); - return trip_parameters_ptr(); - } - } - - if (obj.Has("source")) - { - Napi::Value source = obj.Get("source"); - if (source.IsEmpty()) - return trip_parameters_ptr(); - - if (!source.IsString()) - { - ThrowError(args.Env(), "Source must be a string: [any, first]"); - return trip_parameters_ptr(); - } - - std::string source_str = source.ToString().Utf8Value(); - - if (source_str == "first") - { - params->source = osrm::TripParameters::SourceType::First; - } - else if (source_str == "any") - { - params->source = osrm::TripParameters::SourceType::Any; - } - else - { - ThrowError(args.Env(), "'source' param must be one of [any, first]"); - return trip_parameters_ptr(); - } - } - - if (obj.Has("destination")) - { - Napi::Value destination = obj.Get("destination"); - if (destination.IsEmpty()) - return trip_parameters_ptr(); - - if (!destination.IsString()) - { - ThrowError(args.Env(), "Destination must be a string: [any, last]"); - return trip_parameters_ptr(); - } - - std::string destination_str = destination.ToString().Utf8Value(); - - if (destination_str == "last") - { - params->destination = osrm::TripParameters::DestinationType::Last; - } - else if (destination_str == "any") - { - params->destination = osrm::TripParameters::DestinationType::Any; - } - else - { - ThrowError(args.Env(), "'destination' param must be one of [any, last]"); - return trip_parameters_ptr(); - } - } - - return params; -} - -inline match_parameters_ptr argumentsToMatchParameter(const Napi::CallbackInfo &args, - bool requires_multiple_coordinates) -{ - match_parameters_ptr params = std::make_unique(); - bool has_base_params = argumentsToParameter(args, params, requires_multiple_coordinates); - if (!has_base_params) - return match_parameters_ptr(); - - Napi::Object obj = args[0].As(); - - if (obj.Has("timestamps")) - { - Napi::Value timestamps = obj.Get("timestamps"); - if (timestamps.IsEmpty()) - return match_parameters_ptr(); - - if (!timestamps.IsArray()) - { - ThrowError(args.Env(), "Timestamps must be an array of integers (or undefined)"); - return match_parameters_ptr(); - } - - Napi::Array timestamps_array = timestamps.As(); - - if (params->coordinates.size() != timestamps_array.Length()) - { - ThrowError(args.Env(), - "Timestamp array must have the same size as the coordinates " - "array"); - return match_parameters_ptr(); - } - - for (uint32_t i = 0; i < timestamps_array.Length(); ++i) - { - Napi::Value timestamp = timestamps_array.Get(i); - if (timestamp.IsEmpty()) - return match_parameters_ptr(); - - if (!timestamp.IsNumber()) - { - ThrowError(args.Env(), "Timestamps array items must be numbers"); - return match_parameters_ptr(); - } - params->timestamps.emplace_back(timestamp.ToNumber().Int64Value()); - } - } - - if (obj.Has("gaps")) - { - Napi::Value gaps = obj.Get("gaps"); - if (gaps.IsEmpty()) - return match_parameters_ptr(); - - if (!gaps.IsString()) - { - ThrowError(args.Env(), "Gaps must be a string: [split, ignore]"); - return match_parameters_ptr(); - } - - std::string gaps_str = gaps.ToString().Utf8Value(); - - if (gaps_str == "split") - { - params->gaps = osrm::MatchParameters::GapsType::Split; - } - else if (gaps_str == "ignore") - { - params->gaps = osrm::MatchParameters::GapsType::Ignore; - } - else - { - ThrowError(args.Env(), "'gaps' param must be one of [split, ignore]"); - return match_parameters_ptr(); - } - } - - if (obj.Has("tidy")) - { - Napi::Value tidy = obj.Get("tidy"); - if (tidy.IsEmpty()) - return match_parameters_ptr(); - - if (!tidy.IsBoolean()) - { - ThrowError(args.Env(), "tidy must be of type Boolean"); - return match_parameters_ptr(); - } - - params->tidy = tidy.ToBoolean().Value(); - } - - if (obj.Has("waypoints")) - { - Napi::Value waypoints = obj.Get("waypoints"); - if (waypoints.IsEmpty()) - return match_parameters_ptr(); - - // must be array - if (!waypoints.IsArray()) - { - ThrowError( - args.Env(), - "Waypoints must be an array of integers corresponding to the input coordinates."); - return match_parameters_ptr(); - } - - auto waypoints_array = waypoints.As(); - // must have at least two elements - if (waypoints_array.Length() < 2) - { - ThrowError(args.Env(), "At least two waypoints must be provided"); - return match_parameters_ptr(); - } - auto coords_size = params->coordinates.size(); - auto waypoints_array_size = waypoints_array.Length(); - - const auto first_index = - waypoints_array.Get(static_cast(0)).ToNumber().Uint32Value(); - const auto last_index = - waypoints_array.Get(waypoints_array_size - 1).ToNumber().Uint32Value(); - if (first_index != 0 || last_index != coords_size - 1) - { - ThrowError(args.Env(), - "First and last waypoints values must correspond to first and last " - "coordinate indices"); - return match_parameters_ptr(); - } - - for (uint32_t i = 0; i < waypoints_array_size; ++i) - { - Napi::Value waypoint_value = waypoints_array.Get(i); - // all elements must be numbers - if (!waypoint_value.IsNumber()) - { - ThrowError(args.Env(), "Waypoint values must be an array of integers"); - return match_parameters_ptr(); - } - // check that the waypoint index corresponds with an inpute coordinate - const auto index = waypoint_value.ToNumber().Uint32Value(); - if (index >= coords_size) - { - ThrowError(args.Env(), - "Waypoints must correspond with the index of an input coordinate"); - return match_parameters_ptr(); - } - params->waypoints.emplace_back(index); - } - } - - bool parsedSuccessfully = parseCommonParameters(obj, params); - if (!parsedSuccessfully) - { - return match_parameters_ptr(); - } - - return params; -} - -} // namespace node_osrm - -#endif From 0b1748af3bb0ca075f434d74d205226bb98c8c18 Mon Sep 17 00:00:00 2001 From: Siarhei Fedartsou Date: Tue, 21 May 2024 20:56:28 +0200 Subject: [PATCH 6/9] use std::nullopt --- src/guidance/intersection_handler.cpp | 4 ++-- src/guidance/sliproad_handler.cpp | 10 +++++----- src/guidance/turn_handler.cpp | 4 ++-- src/util/coordinate_calculation.cpp | 8 ++++---- src/util/timezones.cpp | 2 +- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/guidance/intersection_handler.cpp b/src/guidance/intersection_handler.cpp index d08cbcdbce1..b11597d5f46 100644 --- a/src/guidance/intersection_handler.cpp +++ b/src/guidance/intersection_handler.cpp @@ -450,7 +450,7 @@ IntersectionHandler::getNextIntersection(const NodeID at, const EdgeID via) cons if (intersection_parameters.node == SPECIAL_NODEID || intersection_parameters.edge == SPECIAL_EDGEID) { - return {}; + return std::nullopt; } auto intersection = extractor::intersection::getConnectedRoads(node_based_graph, @@ -465,7 +465,7 @@ IntersectionHandler::getNextIntersection(const NodeID at, const EdgeID via) cons if (intersection.size() <= 2 || intersection.isTrafficSignalOrBarrier()) { - return {}; + return std::nullopt; } return std::make_optional(IntersectionViewAndNode{std::move(intersection), intersection_node}); diff --git a/src/guidance/sliproad_handler.cpp b/src/guidance/sliproad_handler.cpp index ae4baf4b760..90a92801f53 100644 --- a/src/guidance/sliproad_handler.cpp +++ b/src/guidance/sliproad_handler.cpp @@ -652,7 +652,7 @@ std::optional SliproadHandler::getObviousIndexWithSliproads( // then the non-Sliproad is the obvious one. if (intersection.size() != 3) { - return {}; + return std::nullopt; } const auto forking = intersection[1].instruction.type == TurnType::Fork && @@ -660,7 +660,7 @@ std::optional SliproadHandler::getObviousIndexWithSliproads( if (!forking) { - return {}; + return std::nullopt; } const auto first = getNextIntersection(at, intersection.getRightmostRoad().eid); @@ -668,12 +668,12 @@ std::optional SliproadHandler::getObviousIndexWithSliproads( if (!first || !second) { - return {}; + return std::nullopt; } if (first->intersection.isDeadEnd() || second->intersection.isDeadEnd()) { - return {}; + return std::nullopt; } // In case of loops at the end of the road, we will arrive back at the intersection @@ -688,7 +688,7 @@ std::optional SliproadHandler::getObviousIndexWithSliproads( return std::make_optional(std::size_t{1}); } - return {}; + return std::nullopt; } bool SliproadHandler::nextIntersectionIsTooFarAway(const NodeID start, const EdgeID onto) const diff --git a/src/guidance/turn_handler.cpp b/src/guidance/turn_handler.cpp index 8fd5c43d0af..0a77243604f 100644 --- a/src/guidance/turn_handler.cpp +++ b/src/guidance/turn_handler.cpp @@ -647,7 +647,7 @@ TurnHandler::findForkCandidatesByGeometry(Intersection &intersection) const } } } - return {}; + return std::nullopt; } // check if the fork candidates (all roads between left and right) and the @@ -740,7 +740,7 @@ std::optional TurnHandler::findFork(const EdgeID via_edge, } } - return {}; + return std::nullopt; } void TurnHandler::handleDistinctConflict(const EdgeID via_edge, diff --git a/src/util/coordinate_calculation.cpp b/src/util/coordinate_calculation.cpp index 72c61a6eb34..00c5efbf54d 100644 --- a/src/util/coordinate_calculation.cpp +++ b/src/util/coordinate_calculation.cpp @@ -181,7 +181,7 @@ circleCenter(const Coordinate C1, const Coordinate C2, const Coordinate C3) // require three distinct points if (C1 == C2 || C2 == C3 || C1 == C3) { - return {}; + return std::nullopt; } // define line through c1, c2 and c2,c3 @@ -196,7 +196,7 @@ circleCenter(const Coordinate C1, const Coordinate C2, const Coordinate C3) (std::abs(C2C1_lat) < std::numeric_limits::epsilon() && std::abs(C3C2_lat) < std::numeric_limits::epsilon())) { - return {}; + return std::nullopt; } else if (std::abs(C2C1_lon) < std::numeric_limits::epsilon()) { @@ -234,7 +234,7 @@ circleCenter(const Coordinate C1, const Coordinate C2, const Coordinate C3) // can this ever happen? if (std::abs(C2C1_slope - C3C2_slope) < std::numeric_limits::epsilon()) - return {}; + return std::nullopt; const double C1_y = static_cast(toFloating(C1.lat)); const double C1_x = static_cast(toFloating(C1.lon)); @@ -248,7 +248,7 @@ circleCenter(const Coordinate C1, const Coordinate C2, const Coordinate C3) (2 * (C3C2_slope - C2C1_slope)); const double lat = (0.5 * (C1_x + C2_x) - lon) / C2C1_slope + 0.5 * (C1_y + C2_y); if (lon < -180.0 || lon > 180.0 || lat < -90.0 || lat > 90.0) - return {}; + return std::nullopt; else return Coordinate(FloatLongitude{lon}, FloatLatitude{lat}); } diff --git a/src/util/timezones.cpp b/src/util/timezones.cpp index e7ef9635645..3fd527d6919 100644 --- a/src/util/timezones.cpp +++ b/src/util/timezones.cpp @@ -168,6 +168,6 @@ std::optional Timezoner::operator()(const point_t &point) const if (boost::geometry::within(point, local_times[index].first)) return local_times[index].second; } - return {}; + return std::nullopt; } } // namespace osrm::updater From b6942d079b0831774812746db052c88947c6b59f Mon Sep 17 00:00:00 2001 From: Siarhei Fedartsou Date: Tue, 21 May 2024 21:18:56 +0200 Subject: [PATCH 7/9] Remove .get() --- include/engine/routing_algorithms/routing_base_ch.hpp | 2 +- include/engine/routing_algorithms/routing_base_mld.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/engine/routing_algorithms/routing_base_ch.hpp b/include/engine/routing_algorithms/routing_base_ch.hpp index b3da739de08..e2e3b540060 100644 --- a/include/engine/routing_algorithms/routing_base_ch.hpp +++ b/include/engine/routing_algorithms/routing_base_ch.hpp @@ -122,7 +122,7 @@ void routingStep(const DataFacade &facade, const EdgeWeight new_weight = reverseHeapNode->weight + heapNode.weight; if (new_weight < upper_bound) { - if (shouldForceStep(force_step_nodes, heapNode, reverseHeapNode.get()) || + if (shouldForceStep(force_step_nodes, heapNode, *reverseHeapNode) || // in this case we are looking at a bi-directional way where the source // and target phantom are on the same edge based node new_weight < EdgeWeight{0}) diff --git a/include/engine/routing_algorithms/routing_base_mld.hpp b/include/engine/routing_algorithms/routing_base_mld.hpp index b85ce549647..ca1d1e40768 100644 --- a/include/engine/routing_algorithms/routing_base_mld.hpp +++ b/include/engine/routing_algorithms/routing_base_mld.hpp @@ -408,7 +408,7 @@ void routingStep(const DataFacade &facade, auto reverse_weight = reverseHeapNode->weight; auto path_weight = weight + reverse_weight; - if (!shouldForceStep(force_step_nodes, heapNode, reverseHeapNode.get()) && + if (!shouldForceStep(force_step_nodes, heapNode, *reverseHeapNode) && (path_weight >= EdgeWeight{0}) && (path_weight < path_upper_bound)) { middle_node = heapNode.node; From 9ddb27ef6067ae3c4277c3032c2fb47a5342c042 Mon Sep 17 00:00:00 2001 From: Siarhei Fedartsou Date: Tue, 21 May 2024 21:19:32 +0200 Subject: [PATCH 8/9] Remove using Result --- include/updater/source.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/include/updater/source.hpp b/include/updater/source.hpp index de692363b73..852b21216ea 100644 --- a/include/updater/source.hpp +++ b/include/updater/source.hpp @@ -14,7 +14,6 @@ template struct LookupTable std::optional operator()(const Key &key) const { using Result = std::optional; - using Result = boost::optional; const auto it = std::lower_bound(lookup.begin(), lookup.end(), From 35b06ee5e496f04056d76b6e9c66b8f6de8fbe68 Mon Sep 17 00:00:00 2001 From: Siarhei Fedartsou Date: Tue, 21 May 2024 22:25:44 +0200 Subject: [PATCH 9/9] add header --- include/engine/geospatial_query.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/engine/geospatial_query.hpp b/include/engine/geospatial_query.hpp index 2fce9c0c922..c4efbcbbbe0 100644 --- a/include/engine/geospatial_query.hpp +++ b/include/engine/geospatial_query.hpp @@ -12,6 +12,8 @@ #include "osrm/coordinate.hpp" +#include + #include #include #include