Skip to content

Commit b74ce4c

Browse files
committed
Moving URI Parsers to Static Lib
This commit moves out the implementation of the URI parsing routines out from the headers and into a single .cpp file. Now it means that cpp-netlib is no longer just a header-only library. It also means that this is proof enough that the compile times are really greatly affected by the template metaprogramming happening under the hood of Boost.Spirit. Now things to do because of this commit: * Overhaul the documentation regarding the installation and the distribution of the library. * Re-think the implementation of certain things like the static dispatch of whether to use an asynchronous or synchronous client. * Start making larger changes now that the compile-times are down when building the tests. That's it folks, header-only was fun while it lasted, unfortunately the Boost.Spirit parts are taking too much a toll on the library's usability. Hopefully this change makes the library more usable in a larger context.
1 parent 8171e39 commit b74ce4c

File tree

8 files changed

+279
-261
lines changed

8 files changed

+279
-261
lines changed

CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,15 @@
66
cmake_minimum_required(VERSION 2.6)
77
project(CPP-NETLIB)
88
find_package( Boost 1.41.0 )
9+
set(CMAKE_VERBOSE_MAKEFILE true)
910
if (Boost_FOUND)
1011
set(Boost_USE_STATIC_LIBS ON)
1112
set(Boost_USE_MULTI_THREADED ON)
1213
include_directories(${Boost_INCLUDE_DIRS})
1314
endif()
1415
enable_testing()
16+
add_subdirectory(libs/network/build)
1517
add_subdirectory(libs/network/test)
1618
add_subdirectory(libs/mime/test)
1719
add_subdirectory(libs/network/example)
20+

boost/network/uri/detail/parse_uri.hpp

Lines changed: 24 additions & 241 deletions
Original file line numberDiff line numberDiff line change
@@ -6,256 +6,39 @@
66
// (See accompanying file LICENSE_1_0.txt or copy at
77
// http://www.boost.org/LICENSE_1_0.txt)
88

9-
#include <boost/spirit/include/phoenix_operator.hpp>
10-
#include <boost/spirit/include/qi_attr.hpp>
11-
#include <boost/spirit/include/qi_core.hpp>
12-
#include <boost/spirit/include/qi_eps.hpp>
13-
#include <boost/spirit/include/qi_grammar.hpp>
14-
#include <boost/spirit/include/qi_omit.hpp>
15-
#include <boost/spirit/include/qi_raw.hpp>
16-
#include <boost/spirit/include/qi_rule.hpp>
17-
#include <boost/spirit/include/qi_sequence.hpp>
18-
#include <boost/spirit/include/version.hpp>
199
#include <boost/network/uri/detail/uri_parts.hpp>
20-
21-
22-
namespace boost { namespace spirit { namespace traits {
23-
template <class Tag>
24-
struct transform_attribute<
25-
boost::network::uri::detail::uri_parts<Tag>,
26-
typename boost::network::uri::detail::uri_parts_tuple<Tag>::type
27-
#if SPIRIT_VERSION >= 0x2030
28-
, boost::spirit::qi::domain
29-
#endif
30-
>
31-
{
32-
typedef typename boost::network::uri::detail::uri_parts_tuple<Tag>::type type;
33-
34-
static type pre(boost::network::uri::detail::uri_parts<Tag> & parts) {
35-
typedef typename boost::network::string<Tag>::type string_type;
36-
37-
boost::fusion::tuple<
38-
boost::optional<string_type> &,
39-
boost::optional<string_type> &,
40-
boost::optional<boost::uint16_t> &,
41-
string_type &
42-
> hier_part =
43-
boost::fusion::tie(
44-
parts.user_info,
45-
parts.host,
46-
parts.port,
47-
parts.path
48-
);
49-
50-
return boost::fusion::tie(
51-
parts.scheme,
52-
hier_part,
53-
parts.query,
54-
parts.fragment
55-
);
56-
}
57-
58-
static void post(boost::network::uri::detail::uri_parts<Tag> &, type const &) { }
59-
60-
#if SPIRIT_VERSION >= 0x2030
61-
static void fail(boost::network::uri::detail::uri_parts<Tag> & val) { }
62-
#endif
63-
};
64-
65-
#if SPIRIT_VERSION < 0x2030
66-
template <typename Exposed, typename Transformed>
67-
struct transform_attribute<
68-
optional<Exposed>,
69-
Transformed,
70-
typename disable_if<is_same<optional<Exposed>, Transformed> >::type
71-
>
72-
{
73-
typedef Transformed & type;
74-
75-
static Transformed & pre(optional<Exposed> & val) {
76-
if (!val)
77-
val = Transformed();
78-
return boost::get<Transformed>(val);
79-
}
80-
81-
static void post(optional<Exposed> &, Transformed const &) { }
82-
};
83-
#endif
84-
} // namespace traits
85-
} // namespace spirit
86-
} // namespace boost
10+
#include <boost/network/support/is_default_string.hpp>
11+
#include <boost/range/iterator_range.hpp>
8712

8813
namespace boost { namespace network { namespace uri { namespace detail {
8914

90-
namespace qi = boost::spirit::qi;
91-
92-
template <typename Iterator, class Tag>
93-
struct uri_grammar : qi::grammar<Iterator, uri_parts<Tag>()> {
94-
uri_grammar() : uri_grammar::base_type(start, "uri") {
95-
// gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
96-
gen_delims %= qi::char_(":/?#[]@");
97-
// sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
98-
sub_delims %= qi::char_("!$&'()*+,;=");
99-
// reserved = gen-delims / sub-delims
100-
reserved %= gen_delims | sub_delims;
101-
// unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
102-
unreserved %= qi::alnum | qi::char_("-._~");
103-
// pct-encoded = "%" HEXDIG HEXDIG
104-
pct_encoded %= qi::char_("%") >> qi::repeat(2)[qi::xdigit];
105-
106-
// pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
107-
pchar %= qi::raw[
108-
unreserved | pct_encoded | sub_delims | qi::char_(":@")
109-
];
110-
111-
// segment = *pchar
112-
segment %= qi::raw[*pchar];
113-
// segment-nz = 1*pchar
114-
segment_nz %= qi::raw[+pchar];
115-
// segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
116-
segment_nz_nc %= qi::raw[
117-
+(unreserved | pct_encoded | sub_delims | qi::char_("@"))
118-
];
119-
// path-abempty = *( "/" segment )
120-
path_abempty %= qi::raw[*(qi::char_("/") >> segment)];
121-
// path-absolute = "/" [ segment-nz *( "/" segment ) ]
122-
path_absolute %= qi::raw[
123-
qi::char_("/")
124-
>> -(segment_nz >> *(qi::char_("/") >> segment))
125-
];
126-
// path-rootless = segment-nz *( "/" segment )
127-
path_rootless %= qi::raw[
128-
segment_nz >> *(qi::char_("/") >> segment)
129-
];
130-
// path-empty = 0<pchar>
131-
path_empty %= qi::eps;
132-
133-
// scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
134-
scheme %= qi::alpha >> *(qi::alnum | qi::char_("+.-"));
135-
136-
// user_info = *( unreserved / pct-encoded / sub-delims / ":" )
137-
user_info %= qi::raw[
138-
*(unreserved | pct_encoded | sub_delims | qi::char_(":"))
139-
];
140-
141-
// dec-octet = DIGIT / %x31-39 DIGIT / "1" 2DIGIT / "2" %x30-34 DIGIT / "25" %x30-35
142-
dec_octet %=
143-
!(qi::lit('0') >> qi::digit)
144-
>> qi::raw[
145-
qi::uint_parser<boost::uint8_t, 10, 1, 3>()
146-
];
147-
// IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
148-
ipv4address %= qi::raw[
149-
dec_octet >> qi::repeat(3)[qi::lit('.') >> dec_octet]
150-
];
151-
// reg-name = *( unreserved / pct-encoded / sub-delims )
152-
reg_name %= qi::raw[
153-
*(unreserved | pct_encoded | sub_delims)
154-
];
155-
// TODO, host = IP-literal / IPv4address / reg-name
156-
host %= ipv4address | reg_name;
157-
158-
// query = *( pchar / "/" / "?" )
159-
query %= qi::raw[*(pchar | qi::char_("/?"))];
160-
// fragment = *( pchar / "/" / "?" )
161-
fragment %= qi::raw[*(pchar | qi::char_("/?"))];
162-
163-
// hier-part = "//" authority path-abempty / path-absolute / path-rootless / path-empty
164-
// authority = [ userinfo "@" ] host [ ":" port ]
165-
hier_part %=
166-
(
167-
"//"
168-
>> -(user_info >> '@')
169-
>> host
170-
>> -(':' >> qi::ushort_)
171-
// >> -(':' >> *qi::digit)
172-
>> path_abempty
173-
)
174-
|
175-
(
176-
qi::attr(optional<typename boost::network::string<Tag>::type>())
177-
>> qi::attr(optional<typename boost::network::string<Tag>::type>())
178-
// >> qi::attr(optional<typename boost::network::string<Tag>::type>())
179-
>> qi::attr(optional<boost::uint16_t>())
180-
>> (
181-
path_absolute
182-
| path_rootless
183-
| path_empty
184-
)
185-
);
186-
187-
uri %=
188-
scheme >> ':'
189-
>> hier_part
190-
>> -('?' >> query)
191-
>> -('#' >> fragment);
192-
193-
start %= uri.alias();
194-
}
195-
196-
typedef typename string<Tag>::type string_type;
197-
198-
qi::rule<Iterator, typename string_type::value_type()>
199-
gen_delims, sub_delims, reserved, unreserved;
200-
qi::rule<Iterator, string_type()>
201-
pct_encoded, pchar;
202-
203-
qi::rule<Iterator, string_type()>
204-
segment, segment_nz, segment_nz_nc;
205-
qi::rule<Iterator, string_type()>
206-
path_abempty, path_absolute, path_rootless, path_empty;
207-
208-
qi::rule<Iterator, string_type()>
209-
dec_octet, ipv4address, reg_name, host;
210-
211-
qi::rule<Iterator, string_type()>
212-
scheme, user_info, query, fragment;
213-
214-
qi::rule<Iterator, boost::fusion::tuple<
215-
optional<string_type> &,
216-
optional<string_type> &,
217-
// optional<string_type> &,
218-
optional<boost::uint16_t> &,
219-
string_type &
220-
>()> hier_part;
221-
222-
// start rule of grammar
223-
qi::rule<Iterator, uri_parts<Tag>()> start;
224-
225-
// actual uri parser
226-
qi::rule<Iterator, typename uri_parts_tuple<Tag>::type()> uri;
227-
};
228-
229-
template <
230-
class Tag
231-
>
232-
inline
233-
bool parse_specific(uri_parts<Tag> & parts) {
15+
template <class Tag>
16+
inline bool parse_specific(uri_parts<Tag> & parts) {
23417
return true;
23518
}
23619

237-
template <
238-
class Range,
239-
class Tag
240-
>
241-
inline
242-
bool parse_uri(Range & range, uri_parts<Tag> & parts) {
243-
typedef typename range_iterator<Range>::type iterator;
244-
245-
// Qualified boost::begin and boost::end because MSVC complains
246-
// of ambiguity on call to begin(range) and end(rand).
247-
iterator start_ = boost::begin(range);
248-
iterator end_ = boost::end(range);
20+
extern bool parse_uri_impl(boost::iterator_range<std::string::const_iterator> & range, uri_parts_default_base & parts, tags::default_string);
21+
extern bool parse_uri_impl(boost::iterator_range<std::wstring::const_iterator> & range, uri_parts_wide_base & parts, tags::default_wstring);
24922

250-
static uri_grammar<iterator, Tag> grammar;
251-
252-
bool ok = qi::parse(start_, end_, grammar, parts);
253-
254-
if (ok)
255-
ok = parse_specific(parts);
256-
257-
return ok && start_ == end_;
23+
template <class Tag>
24+
struct unsupported_tag;
25+
26+
template <class Range, class Tag>
27+
inline bool parse_uri(Range & range, uri_parts<Tag> & parts) {
28+
typedef typename range_iterator<Range const>::type iterator;
29+
boost::iterator_range<iterator> local_range = boost::make_iterator_range(range);
30+
return parse_uri_impl(local_range, parts,
31+
typename mpl::if_<
32+
is_default_string<Tag>,
33+
tags::default_string,
34+
typename mpl::if_<
35+
is_default_wstring<Tag>,
36+
tags::default_wstring,
37+
unsupported_tag<Tag>
38+
>::type
39+
>::type());
25840
}
41+
25942
} // namespace detail
26043
} // namespace uri
26144
} // namespace network

boost/network/uri/detail/uri_parts.hpp

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,43 @@
1010
#include <boost/fusion/tuple.hpp>
1111
#include <boost/optional.hpp>
1212

13+
#include <boost/mpl/if.hpp>
1314
#include <boost/network/traits/string.hpp>
1415

1516
namespace boost { namespace network { namespace uri {
1617

1718
namespace detail {
19+
20+
struct uri_parts_default_base {
21+
typedef std::string string_type;
22+
string_type scheme;
23+
optional<string_type> user_info;
24+
optional<string_type> host;
25+
optional<boost::uint16_t> port;
26+
string_type path;
27+
optional<string_type> query;
28+
optional<string_type> fragment;
29+
};
1830

19-
template <class Tag>
20-
struct uri_parts {
21-
typedef typename string<Tag>::type string_type;
31+
struct uri_parts_wide_base {
32+
typedef std::wstring string_type;
33+
string_type scheme;
34+
optional<string_type> user_info;
35+
optional<string_type> host;
36+
optional<boost::uint16_t> port;
37+
string_type path;
38+
optional<string_type> query;
39+
optional<string_type> fragment;
40+
};
2241

23-
string_type scheme;
24-
optional<string_type> user_info;
25-
optional<string_type> host;
26-
optional<boost::uint16_t> port;
27-
string_type path;
28-
optional<string_type> query;
29-
optional<string_type> fragment;
30-
};
42+
template <class Tag>
43+
struct uri_parts :
44+
mpl::if_<
45+
is_default_string<Tag>
46+
, uri_parts_default_base
47+
, uri_parts_wide_base
48+
>::type
49+
{};
3150

3251
template <class Tag>
3352
struct uri_parts_tuple {

libs/network/build/Jamfile.v2

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ project cpp-netlib :
1313

1414
cpp-pch client : boost/network/include/http/client.hpp ;
1515
cpp-pch server : boost/network/include/http/server.hpp ;
16+
lib cppnetlib-uri-parsers : libs/network/src/parse_uri_impl.cpp ;
1617

1718
install headers : client server
1819
: <location>../../../boost/network/include/http ;

libs/network/example/CMakeLists.txt

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,17 @@ if (Boost_FOUND)
1717
add_executable(hello_world_server http/hello_world_server.cpp)
1818
add_executable(fileserver http/fileserver.cpp)
1919
add_executable(uri uri.cpp)
20-
target_link_libraries(http_client ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_LIBRARIES} )
21-
target_link_libraries(simple_wget ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_LIBRARIES} )
20+
add_dependencies(http_client cppnetlib-uri-parsers)
21+
add_dependencies(simple_wget cppnetlib-uri-parsers)
22+
add_dependencies(uri cppnetlib-uri-parsers)
23+
target_link_libraries(http_client ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_LIBRARIES} cppnetlib-uri-parsers)
24+
target_link_libraries(simple_wget ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_LIBRARIES} cppnetlib-uri-parsers)
2225
target_link_libraries(hello_world_server ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_LIBRARIES} )
2326
target_link_libraries(fileserver ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
24-
set_target_properties(http_client PROPERTIES RUNTIME_OUTPUT_DIRECTORY ../../../build/example)
25-
set_target_properties(simple_wget PROPERTIES RUNTIME_OUTPUT_DIRECTORY ../../../build/example)
26-
set_target_properties(hello_world_server PROPERTIES RUNTIME_OUTPUT_DIRECTORY ../../../build/example)
27-
set_target_properties(fileserver PROPERTIES RUNTIME_OUTPUT_DIRECTORY ../../../build/example)
28-
set_target_properties(uri PROPERTIES RUNTIME_OUTPUT_DIRECTORY ../../../build/example)
27+
target_link_libraries(uri cppnetlib-uri-parsers)
28+
set_target_properties(http_client PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CPP-NETLIB_BINARY_DIR}/example)
29+
set_target_properties(simple_wget PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CPP-NETLIB_BINARY_DIR}/example)
30+
set_target_properties(hello_world_server PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CPP-NETLIB_BINARY_DIR}/example)
31+
set_target_properties(fileserver PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CPP-NETLIB_BINARY_DIR}/example)
32+
set_target_properties(uri PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CPP-NETLIB_BINARY_DIR}/example)
2933
endif()

0 commit comments

Comments
 (0)