Skip to content

Commit 3419778

Browse files
committed
URL Support for wide-character strings
This commit finally adds support for wide characters in URI's and addresses the final test errors in the URI implementation. Step after this is the refactoring of the Spirit-based grammar to simplify the URI grammar and reduce the magic that goes on in the implementation.
1 parent f734b3f commit 3419778

File tree

4 files changed

+193
-32
lines changed

4 files changed

+193
-32
lines changed

boost/network/uri/basic_uri.hpp

+8-4
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@ struct uri_base {
2323
:
2424
raw_(uri),
2525
parts_(),
26-
valid_(parse_uri(raw_, parts_))
27-
{ }
26+
valid_(false)
27+
{
28+
valid_ = parse_uri(raw_, parts_);
29+
}
2830

2931
uri_base(const uri_base & other)
3032
:
@@ -116,8 +118,9 @@ class basic_uri : public uri_base<Tag> {
116118

117119
basic_uri() : uri_base<Tag>() {}
118120
basic_uri(typename uri_base<Tag>::string_type const & uri) : uri_base<Tag>(uri) {}
121+
basic_uri(basic_uri const & other) : uri_base<Tag>(other) {}
119122

120-
basic_uri & operator= (basic_uri & rhs) {
123+
basic_uri & operator= (basic_uri rhs) {
121124
rhs.swap(*this);
122125
return *this;
123126
}
@@ -223,7 +226,7 @@ is_valid(basic_uri<Tag> const & uri) {
223226
} // namespace network
224227
} // namespace boost
225228

226-
229+
#ifdef BOOST_NETWORK_DEBUG
227230
// Check that the URI concept is met by the basic_uri type.
228231
#include <boost/network/uri/uri_concept.hpp>
229232
#include <boost/network/tags.hpp>
@@ -233,6 +236,7 @@ BOOST_CONCEPT_ASSERT((URI<basic_uri<boost::network::tags::default_wstring> >));
233236
} // namespace uri
234237
} // namespace network
235238
} // namespace boost
239+
#endif // BOOST_NETWORK_DEBUG
236240

237241
#endif
238242

boost/network/uri/detail/impl/parse_uri.ipp

+101-10
Original file line numberDiff line numberDiff line change
@@ -131,17 +131,100 @@ struct transform_attribute<
131131
static void post(optional<Exposed> &, Transformed const &) { }
132132
};
133133
#endif
134+
135+
template <>
136+
struct transform_attribute<
137+
boost::network::uri::detail::uri_parts_wide_base,
138+
boost::fusion::tuple<
139+
std::wstring &,
140+
boost::fusion::tuple<
141+
boost::optional<std::wstring>&,
142+
boost::optional<std::wstring>&,
143+
boost::optional<boost::uint16_t> &,
144+
std::wstring &
145+
>,
146+
optional<std::wstring>&,
147+
optional<std::wstring>&
148+
>
149+
#if SPIRIT_VERSION >= 0x2030
150+
, boost::spirit::qi::domain
151+
#endif
152+
>
153+
{
154+
typedef
155+
boost::fusion::tuple<
156+
std::wstring &,
157+
boost::fusion::tuple<
158+
boost::optional<std::wstring>&,
159+
boost::optional<std::wstring>&,
160+
boost::optional<boost::uint16_t> &,
161+
std::wstring &
162+
>,
163+
optional<std::wstring>&,
164+
optional<std::wstring>&
165+
> type;
166+
167+
static type pre(boost::network::uri::detail::uri_parts_wide_base & parts) {
168+
boost::fusion::tuple<
169+
boost::optional<std::wstring> &,
170+
boost::optional<std::wstring> &,
171+
boost::optional<boost::uint16_t> &,
172+
std::wstring &
173+
> hier_part =
174+
boost::fusion::tie(
175+
parts.user_info,
176+
parts.host,
177+
parts.port,
178+
parts.path
179+
);
180+
181+
return boost::fusion::tie(
182+
parts.scheme,
183+
hier_part,
184+
parts.query,
185+
parts.fragment
186+
);
187+
}
188+
189+
static void post(boost::network::uri::detail::uri_parts_wide_base &, type const &) { }
190+
191+
#if SPIRIT_VERSION >= 0x2030
192+
static void fail(boost::network::uri::detail::uri_parts_wide_base & val) { }
193+
#endif
194+
};
195+
134196
} // namespace traits
135197
} // namespace spirit
136198
} // namespace boost
137199

138200

139201
namespace boost { namespace network { namespace uri { namespace detail {
202+
203+
template <class String>
204+
struct unsupported_string;
205+
206+
template <class String, class Dummy = void>
207+
struct choose_uri_base
208+
{
209+
typedef unsupported_string<String> type;
210+
};
211+
212+
template <class Dummy>
213+
struct choose_uri_base<std::string, Dummy>
214+
{
215+
typedef uri_parts_default_base type;
216+
};
217+
218+
template <class Dummy>
219+
struct choose_uri_base<std::wstring, Dummy>
220+
{
221+
typedef uri_parts_wide_base type;
222+
};
140223

141224
namespace qi = boost::spirit::qi;
142225

143-
template <typename Iterator>
144-
struct uri_grammar_default : qi::grammar<Iterator, uri_parts_default_base()> {
226+
template <typename Iterator, typename String>
227+
struct uri_grammar_default : qi::grammar<Iterator, typename choose_uri_base<String>::type()> {
145228
uri_grammar_default() : uri_grammar_default::base_type(start, "uri") {
146229
// gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
147230
gen_delims %= qi::char_(":/?#[]@");
@@ -223,8 +306,8 @@ struct uri_grammar_default : qi::grammar<Iterator, uri_parts_default_base()> {
223306
)
224307
|
225308
(
226-
qi::attr(optional<std::string>())
227-
>> qi::attr(optional<std::string>())
309+
qi::attr(optional<String>())
310+
>> qi::attr(optional<String>())
228311
>> qi::attr(optional<boost::uint16_t>())
229312
>> (
230313
path_absolute
@@ -242,7 +325,7 @@ struct uri_grammar_default : qi::grammar<Iterator, uri_parts_default_base()> {
242325
start %= uri.alias();
243326
}
244327

245-
typedef std::string string_type;
328+
typedef String string_type;
246329

247330
qi::rule<Iterator, typename string_type::value_type()>
248331
gen_delims, sub_delims, reserved, unreserved;
@@ -268,7 +351,7 @@ struct uri_grammar_default : qi::grammar<Iterator, uri_parts_default_base()> {
268351
>()> hier_part;
269352

270353
// start rule of grammar
271-
qi::rule<Iterator, uri_parts_default_base()> start;
354+
qi::rule<Iterator, typename choose_uri_base<String>::type()> start;
272355

273356
// actual uri parser
274357
qi::rule<
@@ -290,20 +373,28 @@ struct uri_grammar_default : qi::grammar<Iterator, uri_parts_default_base()> {
290373

291374
BOOST_NETWORK_INLINE bool parse_uri_impl(boost::iterator_range<std::string::const_iterator> & range, uri_parts_default_base & parts, boost::network::tags::default_string) {
292375
// Qualified boost::begin and boost::end because MSVC complains
293-
// of ambiguity on call to begin(range) and end(rand).
376+
// of ambiguity on call to begin(range) and end(range).
294377
std::string::const_iterator start_ = boost::begin(range);
295378
std::string::const_iterator end_ = boost::end(range);
296379

297-
static uri_grammar_default<std::string::const_iterator> grammar;
380+
static uri_grammar_default<std::string::const_iterator, std::string> grammar;
298381

299382
bool ok = qi::parse(start_, end_, grammar, parts);
300383

301384
return ok && start_ == end_;
302385
}
303386

304387
BOOST_NETWORK_INLINE bool parse_uri_impl(boost::iterator_range<std::wstring::const_iterator> & range, uri_parts_wide_base & parts, boost::network::tags::default_wstring) {
305-
// TODO implement the grammar that supports wide strings
306-
return false; // this always fails because it's not supported yet!
388+
// Qualified boost::begin and boost::end because MSVC complains
389+
// of ambiguity on call to begin(range) and end(range).
390+
std::wstring::const_iterator start_ = boost::begin(range);
391+
std::wstring::const_iterator end_ = boost::end(range);
392+
393+
static uri_grammar_default<std::wstring::const_iterator, std::wstring> grammar;
394+
395+
bool ok = qi::parse(start_, end_, grammar, parts);
396+
397+
return ok && start_ == end_;
307398
}
308399

309400
} /* detail */

boost/network/uri/detail/uri_parts.hpp

+83-18
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,36 @@ namespace detail {
2626
string_type path;
2727
optional<string_type> query;
2828
optional<string_type> fragment;
29+
30+
uri_parts_default_base(uri_parts_default_base const & other)
31+
: scheme(other.scheme)
32+
, user_info(other.user_info)
33+
, host(other.host)
34+
, port(other.port)
35+
, path(other.path)
36+
, query(other.query)
37+
, fragment(other.fragment)
38+
{}
39+
40+
uri_parts_default_base()
41+
{}
42+
43+
uri_parts_default_base & operator=(uri_parts_default_base rhs)
44+
{
45+
rhs.swap(*this);
46+
return *this;
47+
}
48+
49+
void swap(uri_parts_default_base & rhs)
50+
{
51+
std::swap(scheme, rhs.scheme);
52+
std::swap(user_info, rhs.user_info);
53+
std::swap(host, rhs.host);
54+
std::swap(port, rhs.port);
55+
std::swap(path, rhs.path);
56+
std::swap(query, rhs.query);
57+
std::swap(fragment, rhs.fragment);
58+
}
2959
};
3060

3161
struct uri_parts_wide_base {
@@ -37,6 +67,36 @@ namespace detail {
3767
string_type path;
3868
optional<string_type> query;
3969
optional<string_type> fragment;
70+
71+
uri_parts_wide_base(uri_parts_wide_base const & other)
72+
: scheme(other.scheme)
73+
, user_info(other.user_info)
74+
, host(other.host)
75+
, port(other.port)
76+
, path(other.path)
77+
, query(other.query)
78+
, fragment(other.fragment)
79+
{}
80+
81+
uri_parts_wide_base()
82+
{}
83+
84+
uri_parts_wide_base & operator=(uri_parts_wide_base rhs)
85+
{
86+
rhs.swap(*this);
87+
return *this;
88+
}
89+
90+
void swap(uri_parts_wide_base & rhs)
91+
{
92+
std::swap(this->scheme, rhs.scheme);
93+
std::swap(this->user_info, rhs.user_info);
94+
std::swap(this->host, rhs.host);
95+
std::swap(this->port, rhs.port);
96+
std::swap(this->path, rhs.path);
97+
std::swap(this->query, rhs.query);
98+
std::swap(this->fragment, rhs.fragment);
99+
}
40100
};
41101

42102
template <class Tag>
@@ -46,23 +106,21 @@ struct uri_parts :
46106
, uri_parts_default_base
47107
, uri_parts_wide_base
48108
>::type
49-
{};
50-
51-
template <class Tag>
52-
struct uri_parts_tuple {
53-
typedef typename string<Tag>::type string_type;
54-
55-
typedef typename boost::fusion::tuple<
56-
string_type &,
57-
boost::fusion::tuple<
58-
optional<string_type> &,
59-
optional<string_type> &,
60-
optional<boost::uint16_t> &,
61-
string_type &
62-
>,
63-
optional<string_type> &,
64-
optional<string_type> &
65-
> type;
109+
{
110+
typedef typename mpl::if_<
111+
is_default_string<Tag>
112+
, uri_parts_default_base
113+
, uri_parts_wide_base
114+
>::type base_type;
115+
uri_parts() : base_type() {}
116+
uri_parts(uri_parts const & other)
117+
: base_type(other)
118+
{}
119+
uri_parts & operator=(uri_parts rhs)
120+
{
121+
swap(*this, rhs);
122+
return *this;
123+
}
66124
};
67125

68126
template <class Tag>
@@ -93,8 +151,15 @@ bool operator==(uri_parts<Tag> const & l, uri_parts<Tag> const & r) {
93151
template <class Tag>
94152
inline
95153
bool operator!=(uri_parts<Tag> const & l, uri_parts<Tag> const & r) {
96-
return !(l == r);
154+
return (l.scheme != r.scheme) &&
155+
(l.user_info != r.user_info) &&
156+
(l.host != r.host) &&
157+
(l.port != r.port) &&
158+
(l.path != r.path) &&
159+
(l.query != r.query) &&
160+
(l.fragment != r.fragment);
97161
}
162+
98163
} // namespace detail
99164
} // namespace uri
100165
} // namespace network

libs/network/test/url_test.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -212,5 +212,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(assignment_test, T, tag_types) {
212212
uri_type instance(string_type(boost::begin(url), boost::end(url)));
213213
uri_type copy;
214214
copy = instance;
215+
BOOST_CHECK(instance.raw() == copy.raw());
215216
BOOST_CHECK(instance == copy);
216217
}

0 commit comments

Comments
 (0)