Re-factor URL parser: make grammar stateless

This commit is contained in:
Daniel J. Hofmann 2016-04-01 13:31:51 +02:00 committed by Patrick Niklaus
parent b25cd6aaf2
commit 6f0b6a8158
2 changed files with 70 additions and 76 deletions

View File

@ -3,6 +3,8 @@
#include "util/coordinate.hpp"
#include <boost/fusion/include/adapt_struct.hpp>
#include <string>
#include <vector>
@ -13,15 +15,18 @@ namespace server
namespace api
{
struct ParsedURL
struct ParsedURL final
{
std::string service;
unsigned version;
std::string profile;
std::string query;
};
}
}
}
} // api
} // server
} // osrm
BOOST_FUSION_ADAPT_STRUCT(osrm::server::api::ParsedURL, service, version, profile, query)
#endif

View File

@ -1,17 +1,55 @@
#include "server/api/url_parser.hpp"
#include "engine/polyline_compressor.hpp"
#include <boost/bind.hpp>
#include <boost/spirit/include/qi_char_.hpp>
#include <boost/spirit/include/qi_grammar.hpp>
#include <boost/spirit/include/qi_uint.hpp>
#include <boost/spirit/include/qi_real.hpp>
#include <boost/spirit/include/qi_lit.hpp>
#include <boost/spirit/include/qi_action.hpp>
#include <boost/spirit/include/qi_as_string.hpp>
#include <boost/spirit/include/qi_operator.hpp>
#include <boost/spirit/include/qi_plus.hpp>
//#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <string>
#include <type_traits>
// Keep impl. TU local
namespace
{
namespace qi = boost::spirit::qi;
template <typename Iterator, typename Into> //
struct URLParser final : qi::grammar<Iterator, Into>
{
URLParser() : URLParser::base_type(start)
{
alpha_numeral = qi::char_("a-zA-Z0-9");
polyline_chars = qi::char_("a-zA-Z0-9_.--[]{}@?|\\%~`^");
all_chars = polyline_chars | qi::char_("=,;:&().");
service = +alpha_numeral;
version = qi::uint_;
profile = +alpha_numeral;
query = +all_chars;
// Example input: /route/v1/driving/7.416351,43.731205;7.420363,43.736189
start = qi::lit('/') >> service //
>> qi::lit('/') >> qi::lit('v') >> version //
>> qi::lit('/') >> profile //
>> qi::lit('/') >> query; //
BOOST_SPIRIT_DEBUG_NODES((start)(service)(version)(profile)(query))
}
qi::rule<Iterator, Into> start;
qi::rule<Iterator, std::string()> service;
qi::rule<Iterator, unsigned()> version;
qi::rule<Iterator, std::string()> profile;
qi::rule<Iterator, std::string()> query;
qi::rule<Iterator, char()> alpha_numeral;
qi::rule<Iterator, char()> all_chars;
qi::rule<Iterator, char()> polyline_chars;
};
} // anon.
namespace osrm
{
@ -20,70 +58,21 @@ namespace server
namespace api
{
namespace
{
namespace qi = boost::spirit::qi;
using Iterator = std::string::iterator;
struct URLGrammar : boost::spirit::qi::grammar<Iterator>
{
URLGrammar() : URLGrammar::base_type(url_rule)
{
const auto set_service = [this](std::string service)
{
parsed_url.service = std::move(service);
};
const auto set_version = [this](const unsigned version)
{
parsed_url.version = version;
};
const auto set_profile = [this](std::string profile)
{
parsed_url.profile = std::move(profile);
};
const auto set_query = [this](std::string query)
{
parsed_url.query = std::move(query);
};
alpha_numeral = qi::char_("a-zA-Z0-9");
polyline_chars = qi::char_("a-zA-Z0-9_.--[]{}@?|\\%~`^");
all_chars = polyline_chars | qi::char_("=,;:&().");
service_rule = +alpha_numeral;
version_rule = qi::uint_;
profile_rule = +alpha_numeral;
query_rule = +all_chars;
url_rule = qi::lit('/') >> service_rule[set_service] //
>> qi::lit('/') >> qi::lit('v') >> version_rule[set_version] //
>> qi::lit('/') >> profile_rule[set_profile] //
>> qi::lit('/') >> query_rule[set_query];
}
ParsedURL parsed_url;
qi::rule<Iterator> url_rule;
qi::rule<Iterator, std::string()> service_rule, profile_rule, query_rule;
qi::rule<Iterator, unsigned()> version_rule;
qi::rule<Iterator, char()> alpha_numeral, all_chars, polyline_chars;
};
}
boost::optional<ParsedURL> parseURL(std::string::iterator &iter, const std::string::iterator end)
{
boost::optional<ParsedURL> parsed_url;
using It = std::decay<decltype(iter)>::type;
URLGrammar grammar;
const auto result = boost::spirit::qi::parse(iter, end, grammar);
URLParser<It, ParsedURL> parser;
ParsedURL out;
if (result && iter == end)
{
parsed_url = std::move(grammar.parsed_url);
}
const auto ok = boost::spirit::qi::parse(iter, end, parser, out);
return parsed_url;
}
}
}
if (ok && iter == end)
return boost::make_optional(out);
return boost::none;
}
} // api
} // server
} // osrm