From 7961fa88635f4052d8976dbf4f34a53bc1c3dcaa Mon Sep 17 00:00:00 2001 From: Michael Krasnyk Date: Thu, 15 Dec 2016 11:54:13 +0100 Subject: [PATCH] Added conditional restrictions grammar --- include/util/conditional_restrictions.hpp | 109 ++++++++++++++++++ .../util/conditional_restrictions_parsing.cpp | 40 +++++++ 2 files changed, 149 insertions(+) create mode 100644 include/util/conditional_restrictions.hpp create mode 100644 unit_tests/util/conditional_restrictions_parsing.cpp diff --git a/include/util/conditional_restrictions.hpp b/include/util/conditional_restrictions.hpp new file mode 100644 index 000000000..db519b885 --- /dev/null +++ b/include/util/conditional_restrictions.hpp @@ -0,0 +1,109 @@ +#ifndef OSRM_CONDITIONAL_RESTRICTIONS_HPP +#define OSRM_CONDITIONAL_RESTRICTIONS_HPP + +#include +#include +#include + +namespace osrm +{ +namespace util +{ + +// Helper functions for OSM conditional restrictions +// http://wiki.openstreetmap.org/wiki/Conditional_restrictions +// Consitional restrictions is a vector of ConditionalRestriction +// with a restriction value and a condition string +struct ConditionalRestriction +{ + std::string value; + std::string condition; +}; + +#ifndef NDEBUG +// Debug output stream operators for use with BOOST_SPIRIT_DEBUG +inline std::ostream &operator<<(std::ostream &stream, const ConditionalRestriction &restriction) +{ + return stream << restriction.value << "=" << restriction.condition; +} +#endif +} +} + +BOOST_FUSION_ADAPT_STRUCT(osrm::util::ConditionalRestriction, + (std::string, value)(std::string, condition)) + +namespace osrm +{ +namespace util +{ +namespace detail +{ + +namespace +{ +namespace ph = boost::phoenix; +namespace qi = boost::spirit::qi; +} + +template +struct conditional_restrictions_grammar + : qi::grammar()> +{ + // http://wiki.openstreetmap.org/wiki/Conditional_restrictions + conditional_restrictions_grammar() : conditional_restrictions_grammar::base_type(restrictions) + { + using qi::_1; + using qi::_val; + using qi::lit; + + // clang-format off + + restrictions + = restriction % ';' + ; + + restriction + = value >> '@' >> condition + ; + + value + = +(qi::char_ - '@') + ; + + condition + = *qi::blank + >> (lit('(') >> qi::as_string[qi::no_skip[*~lit(')')]][_val = _1] >> lit(')') + | qi::as_string[qi::no_skip[*~lit(';')]][_val = _1] + ) + ; + + // clang-format on + + BOOST_SPIRIT_DEBUG_NODES((restrictions)(restriction)(value)(condition)); + } + + qi::rule()> restrictions; + qi::rule restriction; + qi::rule value, condition; +}; +} + +inline std::vector ParseConditionalRestrictions(const std::string &str) +{ + auto it(str.begin()), end(str.end()); + const detail::conditional_restrictions_grammar static grammar; + + std::vector result; + bool ok = boost::spirit::qi::phrase_parse(it, end, grammar, boost::spirit::qi::blank, result); + + if (!ok || it != end) + return std::vector(); + + return result; +} + +} // util +} // osrm + +#endif // OSRM_CONDITIONAL_RESTRICTIONS_HPP diff --git a/unit_tests/util/conditional_restrictions_parsing.cpp b/unit_tests/util/conditional_restrictions_parsing.cpp new file mode 100644 index 000000000..bf838037d --- /dev/null +++ b/unit_tests/util/conditional_restrictions_parsing.cpp @@ -0,0 +1,40 @@ +#include "util/conditional_restrictions.hpp" + +#include +#include + +BOOST_AUTO_TEST_SUITE(conditional_restrictions) + +BOOST_AUTO_TEST_CASE(check_conditional_restrictions_grammar) +{ + using osrm::util::ParseConditionalRestrictions; + + const std::string restrictions[] = {"120 @ (06:00-19:00)", + "120 @ (06:00-20:00); 100 @ (22:00-06:00)", + "120 @ 06:00-20:00; 100 @ 22:00-06:00", + "destination @ (weight>5.5)", + "no_left_turn @ (10:00-18:00 AND length>5)", + "no @ (Mo-Fr 06:00-19:00; Sa 12:00-17:00)"}; + + for (auto &restriction : restrictions) + { + BOOST_CHECK_MESSAGE(!ParseConditionalRestrictions(restriction).empty(), + "parsing " << restriction << " failed"); + } +} + +BOOST_AUTO_TEST_CASE(check_conditional_restrictions_values) +{ + using osrm::util::ParseConditionalRestrictions; + + auto restrictions = + ParseConditionalRestrictions("120 @ 06:00-20:00; 100 @ (22:00-06:00 AND length>5)"); + + BOOST_REQUIRE_EQUAL(restrictions.size(), 2); + BOOST_CHECK_EQUAL(restrictions.at(0).value, "120"); + BOOST_CHECK_EQUAL(restrictions.at(0).condition, "06:00-20:00"); + BOOST_CHECK_EQUAL(restrictions.at(1).value, "100"); + BOOST_CHECK_EQUAL(restrictions.at(1).condition, "22:00-06:00 AND length>5"); +} + +BOOST_AUTO_TEST_SUITE_END()