From: K. G. <kim...@gm...> - 2008-10-21 10:22:53
|
Hi guys, Rev. 114 in the uri branch contains enough directive support to pass the test Glyn added (i.e. directives path and query_param). I've gone back and forth between fusion::map and regular members, but after Dean's suggestions that there are indeed benefits in the fusion map, I've gone back to the original layout. There were also some implicit assumptions that the URI was for HTTP, with path normalization, etc. I've removed that, so that clients will need to translate empty path to "/" if necessary, and the same with the port number. Hope that helps, - Kim |
From: Dean M. B. <mik...@gm...> - 2008-10-21 10:27:52
|
Hi Kim, On Tue, Oct 21, 2008 at 6:22 PM, Kim Gräsman <kim...@gm...> wrote: > Hi guys, > > Rev. 114 in the uri branch contains enough directive support to pass > the test Glyn added (i.e. directives path and query_param). > Nice, I'll try and take a look as soon as I get time to do that. > I've gone back and forth between fusion::map and regular members, but > after Dean's suggestions that there are indeed benefits in the fusion > map, I've gone back to the original layout. > > There were also some implicit assumptions that the URI was for HTTP, > with path normalization, etc. I've removed that, so that clients will > need to translate empty path to "/" if necessary, and the same with > the port number. > Okay. Can you try integrating (i.e. merging your changes) with http_integration to make the request object use the refactored URI implementation? > Hope that helps, Sure does, thanks Kim! -- Dean Michael C. Berris Software Engineer, Friendster, Inc. |
From: K. G. <kim...@gm...> - 2008-10-21 12:48:55
|
Hi Dean, On Tue, Oct 21, 2008 at 12:27, Dean Michael Berris <mik...@gm...> wrote: > > Okay. Can you try integrating (i.e. merging your changes) with > http_integration to make the request object use the refactored URI > implementation? I tried, but I got stuck in the tag/traits confusion again. The traits associated with boost::network::http::message_tag are named differently from the ones bundled with boost::network::tags::default_, so when I try to use the basic_request tag with basic_uri, ostringstream's type is no longer available. I tried adding a specialization in boost::network::http called ostringstream, but the compiler lets me know that "symbol cannot be defined within namespace 'http'", presumably because it's defined in boost::network already. Ugh. Time to wake my daghter... - Kim |
From: Glyn M. <gly...@gm...> - 2008-10-21 12:53:44
|
Hi Kim, 2008/10/21 Kim Gräsman <kim...@gm...> > > I've gone back and forth between fusion::map and regular members, but > after Dean's suggestions that there are indeed benefits in the fusion > map, I've gone back to the original layout. > > There were also some implicit assumptions that the URI was for HTTP, > with path normalization, etc. I've removed that, so that clients will > need to translate empty path to "/" if necessary, and the same with > the port number. > Do you still intend to keep the host/port in the fusion map? How do you intend to deal with URIs like this: file:///home/user/myfile.txt mailto:som...@ex... ? Or haven't you got that far yet? ;) G |
From: K. G. <kim...@gm...> - 2008-10-21 13:31:25
|
Hi Glyn, On Tue, Oct 21, 2008 at 14:23, Glyn Matthews <gly...@gm...> wrote: > >> There were also some implicit assumptions that the URI was for HTTP, >> with path normalization, etc. I've removed that, so that clients will >> need to translate empty path to "/" if necessary, and the same with >> the port number. > > Do you still intend to keep the host/port in the fusion map? How do you > intend to deal with URIs like this: > > file:///home/user/myfile.txt > mailto:som...@ex... Yeah, I've been wondering the same thing lately... I'm afraid to even suggest subtyping of some kind :-) >From what I've gathered from the RFC and other places, everything after the scheme prefix is scheme-specific, so I don't know if it makes sense to try and parse differently-schemed URIs the same way at all. - Kim |
From: K. G. <kim...@gm...> - 2008-10-23 07:19:11
|
Glyn, On Tue, Oct 21, 2008 at 14:23, Glyn Matthews <gly...@gm...> wrote: > > Do you still intend to keep the host/port in the fusion map? How do you > intend to deal with URIs like this: > > file:///home/user/myfile.txt > mailto:som...@ex... I just checked briefly how .NET's System.Uri class handles this, and it treats them all the same. > file:///home/user/myfile.txt No host + port here, only a scheme and a path > mailto:som...@ex... No path info, just a user prefix (some.dude) and a host (example.com) I suppose that makes sense in a way... Thoughts? - Kim |
From: Glyn M. <gly...@gm...> - 2008-10-23 21:17:52
|
Hi Kim, 2008/10/23 Kim Gräsman <kim...@gm...> > Glyn, > > On Tue, Oct 21, 2008 at 14:23, Glyn Matthews <gly...@gm...> > wrote: > > > > Do you still intend to keep the host/port in the fusion map? How do you > > intend to deal with URIs like this: > > > > file:///home/user/myfile.txt > > mailto:som...@ex... > > I just checked briefly how .NET's System.Uri class handles this, and > it treats them all the same. > > > file:///home/user/myfile.txt > > No host + port here, only a scheme and a path > > > mailto:som...@ex... > > No path info, just a user prefix (some.dude) and a host (example.com) > > I suppose that makes sense in a way... Thoughts? > so we'd have something like: template <class Tags> class basic_uri { public: typename string<Tags>::type scheme() const; typename string<Tags>::type host() const; int host() const; typename string<Tags>::type user_info() const; typename string<Tags>::type authority() const; // etc. }; and the member functions return empty strings for the components that don't apply? That's not a problem. If you want to compare with other languages, the documentation for Java's URI class is good: http://java.sun.com/j2se/1.5.0/docs/api/java/net/URI.html Do you have time to do a lot with this? Could we target a 0.4 release with a URI class? I can help with what I can, but I'm really busy at work. G |
From: John P. F. <jf...@ov...> - 2008-10-23 22:42:09
|
Glyn Matthews wrote: > Hi Kim, > > 2008/10/23 Kim Gräsman <kim...@gm... > <mailto:kim...@gm...>> > > Glyn, > > On Tue, Oct 21, 2008 at 14:23, Glyn Matthews > <gly...@gm... <mailto:gly...@gm...>> wrote: > > > > Do you still intend to keep the host/port in the fusion map? > How do you > > intend to deal with URIs like this: > > > > file:///home/user/myfile.txt > > mailto:som...@ex... <mailto:som...@ex...> > > I just checked briefly how .NET's System.Uri class handles this, and > it treats them all the same. > > > file:///home/user/myfile.txt > > No host + port here, only a scheme and a path > > > mailto:som...@ex... <mailto:som...@ex...> > > No path info, just a user prefix (some.dude) and a host > (example.com <http://example.com>) > > I suppose that makes sense in a way... Thoughts? > > > so we'd have something like: > > template <class Tags> > class basic_uri { > public: > typename string<Tags>::type scheme() const; > typename string<Tags>::type host() const; > int host() const; > typename string<Tags>::type user_info() const; > typename string<Tags>::type authority() const; > // etc. > }; > > and the member functions return empty strings for the components that > don't apply? That's not a problem. > > If you want to compare with other languages, the documentation for > Java's URI class is good: > > http://java.sun.com/j2se/1.5.0/docs/api/java/net/URI.html > > Do you have time to do a lot with this? Could we target a 0.4 release > with a URI class? I can help with what I can, but I'm really busy at > work. > > G > ------------------------------------------------------------------------ > > ------------------------------------------------------------------------- > This SF.Net email is sponsored by the Moblin Your Move Developer's challenge > Build the coolest Linux based applications with Moblin SDK & win great prizes > Grand prize is a trip for two to an Open Source event anywhere in the world > http://moblin-contest.org/redirect.php?banner_id=100&url=/ > ------------------------------------------------------------------------ > > _______________________________________________ > Cpp-netlib-devel mailing list > Cpp...@li... > https://lists.sourceforge.net/lists/listinfo/cpp-netlib-devel > I implemented this in a similar network client project some time ago: namespace rfc3986 { template < typename ParserInput = std::string, typename Scheme = std::string, typename Authority = std::string, typename Path = std::string, typename Query = std::string, typename Fragment =std::string > class URI { public: ///Public type access typedef Scheme scheme_type; typedef Authority authority_type; typedef Path path_type; typedef Query query_type; typedef Fragment fragment_type; Scheme getScheme() const { return m_scheme; } Authority getAuthority() const { return m_auth; } Path getPath() const { return m_path; } Query getQuery() const { return m_query; } Fragment getFragment() const { return m_fragment; } private: typedef URI< ParserInput, Scheme, Authority, Path, Query, Fragment> Output; friend Output* parse< ParserInput, Output> (std::stack<std::string>& errors, const ParserInput& input); URI(Scheme scheme, Authority auth, Path path, Query query, Fragment fragment) : m_scheme(scheme), m_auth(auth), m_path(path), m_query(query), m_fragment(fragment) {} const Scheme m_scheme; const Authority m_auth; const Path m_path; const Query m_query; const Fragment m_fragment; }; }; The advantage of this is: 1) The relationship between the parser and the validated URI object is explicit. 2) This is a flexible class with a precise interface. IE: typedef URI< URI<>, std::string, HostConnection, std::string, std::string > HTTP; class HostConnection { public: std::string getName() const; const int* getPort() const; HostConnection(const HostConnection& other); ~HostConnection(); private: friend HostConnection* parse<std::string, HostConnection> (std::stack<std::string>& errors, const std::string& input); HostConnection(const std::string& name, const int* port); const std::string m_name; const int* m_port; }; I will provide full sources with parser if requested. John |
From: K. G. <kim...@gm...> - 2008-10-26 12:43:24
|
Hi John, On Thu, Oct 23, 2008 at 23:38, John P. Feltz <jf...@ov...> wrote: > > typedef URI< > URI<>, > std::string, > HostConnection, > std::string, > std::string > > HTTP; > > class HostConnection { > public: > std::string getName() const; > const int* getPort() const; > > HostConnection(const HostConnection& other); > ~HostConnection(); > > private: > friend HostConnection* parse<std::string, HostConnection> > (std::stack<std::string>& errors, const std::string& input); > > HostConnection(const std::string& name, const int* port); > > const std::string m_name; > const int* m_port; > }; Looks pretty interesting. I like how the parse function is free and separated from the data struct. Can parse(string, URI) transparently use parse(string, HostConnection) based on the template args as well? Thanks, - Kim |
From: John P. F. <jf...@ov...> - 2008-10-26 15:43:09
|
Kim Gräsman wrote: > Hi John, > > On Thu, Oct 23, 2008 at 23:38, John P. Feltz <jf...@ov...> wrote: > >> typedef URI< >> URI<>, >> std::string, >> HostConnection, >> std::string, >> std::string >> > HTTP; >> >> class HostConnection { >> public: >> std::string getName() const; >> const int* getPort() const; >> >> HostConnection(const HostConnection& other); >> ~HostConnection(); >> >> private: >> friend HostConnection* parse<std::string, HostConnection> >> (std::stack<std::string>& errors, const std::string& input); >> >> HostConnection(const std::string& name, const int* port); >> >> const std::string m_name; >> const int* m_port; >> }; >> > > Looks pretty interesting. I like how the parse function is free and > separated from the data struct. > > Can parse(string, URI) transparently use parse(string, HostConnection) > based on the template args as well? > > Thanks, > - Kim > > ------------------------------------------------------------------------- > This SF.Net email is sponsored by the Moblin Your Move Developer's challenge > Build the coolest Linux based applications with Moblin SDK & win great prizes > Grand prize is a trip for two to an Open Source event anywhere in the world > http://moblin-contest.org/redirect.php?banner_id=100&url=/ > _______________________________________________ > Cpp-netlib-devel mailing list > Cpp...@li... > https://lists.sourceforge.net/lists/listinfo/cpp-netlib-devel > > Thus far - this is just a specialization for that specific type if I understand what you're asking: template<> HostConnection* parse<std::string, HostConnection> (std::stack<std::string>& errors, const std::string& input) {....} John |
From: Dean M. B. <mik...@gm...> - 2008-10-26 13:14:34
|
Hi John, On Fri, Oct 24, 2008 at 5:38 AM, John P. Feltz <jf...@ov...> wrote: > > I implemented this in a similar network client project some time ago: > > namespace rfc3986 { > template < > typename ParserInput = std::string, > typename Scheme = std::string, > typename Authority = std::string, > typename Path = std::string, > typename Query = std::string, > typename Fragment =std::string > > class URI { > public: We use traits for these things, and have a simple 'Tag' template argument. > > ///Public type access > typedef Scheme scheme_type; > typedef Authority authority_type; > typedef Path path_type; > typedef Query query_type; > typedef Fragment fragment_type; > These are unnecessary since the traits+tag will make the types accessible even without having access to the definition of the class. > Scheme getScheme() const { return m_scheme; } > Authority getAuthority() const { return m_auth; } > Path getPath() const { return m_path; } > Query getQuery() const { return m_query; } > Fragment getFragment() const { return m_fragment; } > > private: > typedef URI< ParserInput, Scheme, Authority, Path, Query, > Fragment> Output; > > friend Output* parse< ParserInput, Output> > (std::stack<std::string>& errors, const ParserInput& input); > Why a friend class for the parsing? > URI(Scheme scheme, Authority auth, Path path, Query query, > Fragment fragment) : > m_scheme(scheme), m_auth(auth), m_path(path), m_query(query), > m_fragment(fragment) {} > > const Scheme m_scheme; > const Authority m_auth; > const Path m_path; > const Query m_query; > const Fragment m_fragment; > }; > }; > There's no way to create a URI object from a constructor? > > The advantage of this is: > > 1) The relationship between the parser and the validated URI object is > explicit. Which is something you don't need to expose, and makes things complicated. This means I can't do something like: uri root("http://www.boost.org/"); > 2) This is a flexible class with a precise interface. IE: > > typedef URI< > URI<>, > std::string, > HostConnection, > std::string, > std::string > > HTTP; > > class HostConnection { > public: > std::string getName() const; > const int* getPort() const; > > HostConnection(const HostConnection& other); > ~HostConnection(); > > private: > friend HostConnection* parse<std::string, HostConnection> > (std::stack<std::string>& errors, const std::string& input); > > HostConnection(const std::string& name, const int* port); > > const std::string m_name; > const int* m_port; > }; > > I will provide full sources with parser if requested. > Why does the parser have to be a free function when it can be part of the constructor which makes the interface a lot simpler? -- Dean Michael C. Berris Software Engineer, Friendster, Inc. |
From: John P. F. <jf...@ov...> - 2008-10-26 16:44:52
|
Dean Michael Berris wrote: > Hi John, > > On Fri, Oct 24, 2008 at 5:38 AM, John P. Feltz <jf...@ov...> wrote: > >> I implemented this in a similar network client project some time ago: >> >> namespace rfc3986 { >> template < >> typename ParserInput = std::string, >> typename Scheme = std::string, >> typename Authority = std::string, >> typename Path = std::string, >> typename Query = std::string, >> typename Fragment =std::string >> > class URI { >> public: >> > > We use traits for these things, and have a simple 'Tag' template argument. > > >> ///Public type access >> typedef Scheme scheme_type; >> typedef Authority authority_type; >> typedef Path path_type; >> typedef Query query_type; >> typedef Fragment fragment_type; >> >> > > These are unnecessary since the traits+tag will make the types > accessible even without having access to the definition of the class. > > >> Scheme getScheme() const { return m_scheme; } >> Authority getAuthority() const { return m_auth; } >> Path getPath() const { return m_path; } >> Query getQuery() const { return m_query; } >> Fragment getFragment() const { return m_fragment; } >> >> private: >> typedef URI< ParserInput, Scheme, Authority, Path, Query, >> Fragment> Output; >> >> friend Output* parse< ParserInput, Output> >> (std::stack<std::string>& errors, const ParserInput& input); >> >> > > Why a friend class for the parsing? > > One of my goals with this design was to provide the contractual guarantee of a valid URI representation. Allowing arbitrary construction wouldn't provide that. The only other alternative I'm aware of is to use ctor originating exceptions; there are several reasons why I chose not to do that, some of which I will discuss below. >> URI(Scheme scheme, Authority auth, Path path, Query query, >> Fragment fragment) : >> m_scheme(scheme), m_auth(auth), m_path(path), m_query(query), >> m_fragment(fragment) {} >> >> const Scheme m_scheme; >> const Authority m_auth; >> const Path m_path; >> const Query m_query; >> const Fragment m_fragment; >> }; >> }; >> >> > > There's no way to create a URI object from a constructor? > In this case, arbitrary construction is mis-construction, unless exceptions are deployed. I find the use of exceptions here problematic. For one it says that an invalid URI string is an exceptional condition -if parsing is what you intend to do. It also says that it is the clients responsibility to validate the input prior to construction of a uri object based off of it. In my library this is not the case; invalid URI strings are an expected, managed condition, which is handled by a return of NULL and error stack. > >> The advantage of this is: >> >> 1) The relationship between the parser and the validated URI object is >> explicit. >> > > Which is something you don't need to expose, and makes things > complicated. This means I can't do something like: > > uri root("http://www.boost.org/"); > > If users absolutely want this, consider a dual approach: class uri { public: uri(const std::string& uri_str) : uri_impl(parse<std::string, URI<> >(errors, uri_str)) { ... if(!uri_impl) throw(...); scheme = uri_impl->getScheme()) //check for support and set appropriate var's ... } ... }; This is just a different solution -based on my own needs- which I hoped this project would be benefited by. Its also nice to get some peer review on it after several months of hermitage :). I like tags and traits, and feel they could be incorporated into this as well where applicable (Infact, I do plan to refactor this once I have a better grasp on their use). John |
From: Dean M. B. <mik...@gm...> - 2008-10-22 07:22:35
|
Hi Kim, On Tue, Oct 21, 2008 at 8:48 PM, Kim Gräsman <kim...@gm...> wrote: > Hi Dean, > > On Tue, Oct 21, 2008 at 12:27, Dean Michael Berris > <mik...@gm...> wrote: >> >> Okay. Can you try integrating (i.e. merging your changes) with >> http_integration to make the request object use the refactored URI >> implementation? > > I tried, but I got stuck in the tag/traits confusion again. The traits > associated with boost::network::http::message_tag are named > differently from the ones bundled with boost::network::tags::default_, > so when I try to use the basic_request tag with basic_uri, > ostringstream's type is no longer available. > > I tried adding a specialization in boost::network::http called > ostringstream, but the compiler lets me know that "symbol cannot be > defined within namespace 'http'", presumably because it's defined in > boost::network already. > Right. Try specializing ostringstream in boost::network and specialize it for boost::network::http::message_tag and see if that works? Or, if you're up for it, you can rename the traits for boost::network::http::message_tag to look like the traits used for boost::network::tags::default_. ;-) HTH -- Dean Michael C. Berris Software Engineer, Friendster, Inc. |
From: K. G. <kim...@gm...> - 2008-10-22 11:26:03
|
Hi Dean, On Wed, Oct 22, 2008 at 09:22, Dean Michael Berris <mik...@gm...> wrote: >> >> I tried adding a specialization in boost::network::http called >> ostringstream, but the compiler lets me know that "symbol cannot be >> defined within namespace 'http'", presumably because it's defined in >> boost::network already. > > Right. Try specializing ostringstream in boost::network and specialize > it for boost::network::http::message_tag and see if that works? I finally figured that out, too. With a couple of other tweaks, I'm almost there :-) - Kim |
From: K. G. <kim...@gm...> - 2008-10-24 19:40:25
|
Glyn, On Thu, Oct 23, 2008 at 23:17, Glyn Matthews <gly...@gm...> wrote: > > so we'd have something like: > > template <class Tags> > class basic_uri { > public: > typename string<Tags>::type scheme() const; > typename string<Tags>::type host() const; > int host() const; > typename string<Tags>::type user_info() const; > typename string<Tags>::type authority() const; > // etc. > }; > > and the member functions return empty strings for the components that don't > apply? That's not a problem. Yeah, that's what I thought. I tried briefly on Thursday to get it to parse user info and host, but I never managed to bend Spirit to my will. I found a pretty solid-looking project -- http://code.google.com/p/uri-grammar/wiki/About -- that does it, but it involved more customizations than I'm comfortable with at the moment. > If you want to compare with other languages, the documentation for Java's > URI class is good: > > http://java.sun.com/j2se/1.5.0/docs/api/java/net/URI.html Thanks, I've seen that one, it _is_ good. > Do you have time to do a lot with this? Could we target a 0.4 release with > a URI class? I can help with what I can, but I'm really busy at work. Not sure. Next is my last week of parental leave, then I'm back to full-time work with a little girl in daycare, so spare time for hacking may be scarce. And given my velocity up till now, it might take a while :) But I'm learning... - Kim |
From: K. G. <kim...@gm...> - 2008-10-26 13:24:22
|
Hi guys, On Fri, Oct 24, 2008 at 21:40, Kim Gräsman <kim...@gm...> wrote: > > Yeah, that's what I thought. I tried briefly on Thursday to get it to > parse user info and host, but I never managed to bend Spirit to my > will. I managed to bend the parser to my will. Committed new version with user info parsing to the uri branch. - Kim |
From: K. G. <kim...@gm...> - 2008-10-26 13:37:06
|
Hi Dean, I'm not John, but his code got me thinking... On Sun, Oct 26, 2008 at 15:14, Dean Michael Berris <mik...@gm...> wrote: > > On Fri, Oct 24, 2008 at 5:38 AM, John P. Feltz <jf...@ov...> wrote: >> >> I implemented this in a similar network client project some time ago: >> >> namespace rfc3986 { >> template < >> typename ParserInput = std::string, >> typename Scheme = std::string, >> typename Authority = std::string, >> typename Path = std::string, >> typename Query = std::string, >> typename Fragment =std::string >> > class URI { >> public: > > We use traits for these things, and have a simple 'Tag' template argument. What's interesting about John's approach is not that std::string is configurable, but that he can write a specific parser for each part of the URI, and maybe compose them in the full parse() function. >> private: >> typedef URI< ParserInput, Scheme, Authority, Path, Query, >> Fragment> Output; >> >> friend Output* parse< ParserInput, Output> >> (std::stack<std::string>& errors, const ParserInput& input); > > Why a friend class for the parsing? Friend function. Presumably because you can easily add new parsers. I think the main parser works something like this: template< class Input, class Output > Output* parse(const Input& input) { return NULL; } template< > URI<>* parse(const URI<>::ParserInput& input) { URI<>::Scheme_type scheme = parse<URI<>::ParserInput, URI<>::Scheme_type>(input); URI<>::Authority_type host = parse<URI<>::ParserInput, URI<>::Authority_type>(input); // ... return new URI<>(scheme, host, ...); } What I think is interesting about this is that we can let the authority be represented by a string where we don't care much about the details (e.g. mailto scheme) or a typed struct where we do (e.g. http scheme), and just provide a new type + corresponding parser to make it work. Not sure if I'm reading too many capabilities into John's design, but I figure this is its main benefit. - Kim |
From: Dean M. B. <mik...@gm...> - 2008-10-26 13:48:37
|
Hi Kim, On Sun, Oct 26, 2008 at 9:36 PM, Kim Gräsman <kim...@gm...> wrote: > Hi Dean, > > I'm not John, but his code got me thinking... > It's alright, it's just for discussion anyway. ;-) > On Sun, Oct 26, 2008 at 15:14, Dean Michael Berris > <mik...@gm...> wrote: >> >> On Fri, Oct 24, 2008 at 5:38 AM, John P. Feltz <jf...@ov...> wrote: >>> >>> I implemented this in a similar network client project some time ago: >>> >>> namespace rfc3986 { >>> template < >>> typename ParserInput = std::string, >>> typename Scheme = std::string, >>> typename Authority = std::string, >>> typename Path = std::string, >>> typename Query = std::string, >>> typename Fragment =std::string >>> > class URI { >>> public: >> >> We use traits for these things, and have a simple 'Tag' template argument. > > What's interesting about John's approach is not that std::string is > configurable, but that he can write a specific parser for each part of > the URI, and maybe compose them in the full parse() function. > But that doesn't require you to not use tags either. >>> private: >>> typedef URI< ParserInput, Scheme, Authority, Path, Query, >>> Fragment> Output; >>> >>> friend Output* parse< ParserInput, Output> >>> (std::stack<std::string>& errors, const ParserInput& input); >> >> Why a friend class for the parsing? > > Friend function. Yes, my bad. Either way, I don't think it's necessary. > Presumably because you can easily add new parsers. I > think the main parser works something like this: > > template< class Input, class Output > > Output* parse(const Input& input) > { > return NULL; > } > > > template< > > URI<>* parse(const URI<>::ParserInput& input) > { > URI<>::Scheme_type scheme = parse<URI<>::ParserInput, > URI<>::Scheme_type>(input); > URI<>::Authority_type host = parse<URI<>::ParserInput, > URI<>::Authority_type>(input); > // ... > > return new URI<>(scheme, host, ...); > } > > What I think is interesting about this is that we can let the > authority be represented by a string where we don't care much about > the details (e.g. mailto scheme) or a typed struct where we do (e.g. > http scheme), and just provide a new type + corresponding parser to > make it work. > But that spells bad design because you're going to be specializing template functions instead of specializing classes (which is what should be done anyway IMO): template <class Tag> struct uri_parts; // container of URI parts template <class Tag> struct uri : uri_parts<Tag>; // a URI can be of many types So for instance I need a uri<http::url> to construct an http::request, then the parser of the uri<http::url> would take into consideration everything that needs to be included in a uri<http::url>. Converting from one uri type to another (defined by the actual protocol you intend to use the URI for) should be a conversion function that throws on error. This makes it predictable and simple. > Not sure if I'm reading too many capabilities into John's design, but > I figure this is its main benefit. > Which actually brings in a brittle design relying on free functions and pointers and whatnot. Let's stick with the simple approach of using POD's (or fusion sequences) and class templates for type safety wherever we can, shall we? ;-) -- Dean Michael C. Berris Software Engineer, Friendster, Inc. |
From: K. G. <kim...@gm...> - 2008-10-26 14:31:33
|
Hi Dean, On Sun, Oct 26, 2008 at 15:48, Dean Michael Berris <mik...@gm...> wrote: > > So for instance I need a uri<http::url> to construct an http::request, > then the parser of the uri<http::url> would take into consideration > everything that needs to be included in a uri<http::url>. You mean we should specialize the whole uri depending on a protocol-specific tag? Or push the parsing code out to another tag-dependent type (http::url, even)? Coming from a more tired object-oriented background, I think all these generic constructs are really counter-intuitive. I've learned to read the stuff more or less (much thanks to guidance from this list), but I still don't write it natively. It's like learning a new language -- reading/listening comes much faster than the ability to express yourself confidently. It'd be interesting to see a mapping chart from OO construct <-> generic construct, most of them have a counterpart on the other side. - Kim |
From: Dean M. B. <mik...@gm...> - 2008-10-26 15:04:05
|
Hi Kim, On Sun, Oct 26, 2008 at 10:31 PM, Kim Gräsman <kim...@gm...> wrote: > Hi Dean, > > On Sun, Oct 26, 2008 at 15:48, Dean Michael Berris > <mik...@gm...> wrote: >> >> So for instance I need a uri<http::url> to construct an http::request, >> then the parser of the uri<http::url> would take into consideration >> everything that needs to be included in a uri<http::url>. > > You mean we should specialize the whole uri depending on a > protocol-specific tag? Or push the parsing code out to another > tag-dependent type (http::url, even)? > I won't go as far as pushing the parsing code out to another tag-dependent type, but I'm thinking more about putting the parsing code in the constructor of a uri<> by passing in a simple string and setting the internal variables of the uri<> appropriately using the parser. Modifying parts of the uri<> can be done with the accessor functions -- and serializing the uri from an instance into a string representation is yet to be done either which should give interesting challenges (normalization, encoding, etc.). > Coming from a more tired object-oriented background, I think all these > generic constructs are really counter-intuitive. I've learned to read > the stuff more or less (much thanks to guidance from this list), but I > still don't write it natively. It's like learning a new language -- > reading/listening comes much faster than the ability to express > yourself confidently. > > It'd be interesting to see a mapping chart from OO construct <-> > generic construct, most of them have a counterpart on the other side. > I don't think there is one chart depicting the OO construct <-> generic construct relationships (I'm not sure there is a mapping anyway), more because the type of generic programming that's happening here occurs in compile time by leveraging the C++ type/template system to enforce rules for us. It's not really generic programming per se, but a very low level of template metaprogramming (our use of traits is already one use of template metaprogramming as well as using tag dispatching on the directives and the constructor of the http::basic_client). It's really more about avoiding as much of the decisions from reaching runtime -- and putting in the decisions in the design. For instance, an HTTP URL has waaaaay different parts from an email address (where both can be depicted as a URI). Another thing you can think of is the conversion from one URI type to a different URI (or URL) can happen with explicit compile-time rules: template <class TargetTag, class SourceTag> uri<TargetTag> convert(uri<SourceTag> const & source) { BOOST_STATIC_ASSERT( valid_conversion<SourceTag, TargetTag> ); return uri<TargetType>(source.str()); }; This way conversion is explicit. It's even easier to do a guard parser if you're using tags: template <class Tag> uri<Tag> parse(string<Tag>::type const str) { if (protocol_id<Tag>::value() != str.substr(0, protocol_id<Tag>::length())) throw invalid_uri<Tag>(str); return uri<Tag>(str); }; So to use this you then have something like: parse<http::url>("http://www.boost.org/"); // won't throw parse<http::url>("mailto:dmb...@fr..."); // will throw This way you're being explicit about the behavior you expect. HTH -- Dean Michael C. Berris Software Engineer, Friendster, Inc. |
From: John P. F. <jf...@ov...> - 2008-10-27 01:16:21
|
John P. Feltz wrote: > Dean Michael Berris wrote: > >> Hi John, >> >> On Fri, Oct 24, 2008 at 5:38 AM, John P. Feltz <jf...@ov...> wrote: >> >> >>> I implemented this in a similar network client project some time ago: >>> >>> namespace rfc3986 { >>> template < >>> typename ParserInput = std::string, >>> typename Scheme = std::string, >>> typename Authority = std::string, >>> typename Path = std::string, >>> typename Query = std::string, >>> typename Fragment =std::string >>> > class URI { >>> public: >>> >>> >> We use traits for these things, and have a simple 'Tag' template argument. >> >> >> >>> ///Public type access >>> typedef Scheme scheme_type; >>> typedef Authority authority_type; >>> typedef Path path_type; >>> typedef Query query_type; >>> typedef Fragment fragment_type; >>> >>> >>> >> These are unnecessary since the traits+tag will make the types >> accessible even without having access to the definition of the class. >> >> >> >>> Scheme getScheme() const { return m_scheme; } >>> Authority getAuthority() const { return m_auth; } >>> Path getPath() const { return m_path; } >>> Query getQuery() const { return m_query; } >>> Fragment getFragment() const { return m_fragment; } >>> >>> private: >>> typedef URI< ParserInput, Scheme, Authority, Path, Query, >>> Fragment> Output; >>> >>> friend Output* parse< ParserInput, Output> >>> (std::stack<std::string>& errors, const ParserInput& input); >>> >>> >>> >> Why a friend class for the parsing? >> >> >> > One of my goals with this design was to provide the contractual > guarantee of a valid URI representation. Allowing arbitrary construction > wouldn't provide that. The only other alternative I'm aware of is to > use ctor originating exceptions; there are several reasons why I chose > not to do that, some of which I will discuss below. > >>> URI(Scheme scheme, Authority auth, Path path, Query query, >>> Fragment fragment) : >>> m_scheme(scheme), m_auth(auth), m_path(path), m_query(query), >>> m_fragment(fragment) {} >>> >>> const Scheme m_scheme; >>> const Authority m_auth; >>> const Path m_path; >>> const Query m_query; >>> const Fragment m_fragment; >>> }; >>> }; >>> >>> >>> >> There's no way to create a URI object from a constructor? >> >> > In this case, arbitrary construction is mis-construction, unless > exceptions are deployed. I find the use of exceptions here problematic. > For one it says that an invalid URI string is an exceptional condition > -if parsing is what you intend to do. It also says that it is the > clients responsibility to validate the input prior to construction of a > uri object based off of it. > In my library this is not the case; invalid URI strings are an expected, > managed condition, which is handled by a return of NULL and error stack. > > >> >> >>> The advantage of this is: >>> >>> 1) The relationship between the parser and the validated URI object is >>> explicit. >>> >>> >> Which is something you don't need to expose, and makes things >> complicated. This means I can't do something like: >> >> uri root("http://www.boost.org/"); >> >> >> > If users absolutely want this, consider a dual approach: > > class uri { > public: > uri(const std::string& uri_str) : > uri_impl(parse<std::string, URI<> >(errors, uri_str)) { > ... > if(!uri_impl) > throw(...); > scheme = uri_impl->getScheme()) > //check for support and set appropriate var's > ... > } > ... > }; > > This is just a different solution -based on my own needs- which I hoped > this project would be benefited by. > Its also nice to get some peer review on it after several months of > hermitage :). > I like tags and traits, and feel they could be incorporated into this as > well where applicable > (Infact, I do plan to refactor this once I have a better grasp on their > use). > > John > > ------------------------------------------------------------------------- > This SF.Net email is sponsored by the Moblin Your Move Developer's challenge > Build the coolest Linux based applications with Moblin SDK & win great prizes > Grand prize is a trip for two to an Open Source event anywhere in the world > http://moblin-contest.org/redirect.php?banner_id=100&url=/ > _______________________________________________ > Cpp-netlib-devel mailing list > Cpp...@li... > https://lists.sourceforge.net/lists/listinfo/cpp-netlib-devel > > I'll be going out to sea for a few months (active duty USN). During this time I'll focus on the http client features, and leave the URI issue for you guys to resolve. I hope this has been of help. John |
From: Dean M. B. <mik...@gm...> - 2008-10-27 12:51:12
|
Hi John! On Mon, Oct 27, 2008 at 9:18 AM, John P. Feltz <jf...@ov...> wrote: > > I'll be going out to sea for a few months (active duty USN). During this > time I'll focus on the http client features, and leave the URI issue for > you guys to resolve. I hope this has been of help. > You take care John, and thanks for the input. Alternative solutions are always welcome especially in an open source project that's just starting like this one. :) -- Dean Michael C. Berris Software Engineer, Friendster, Inc. |
From: K. G. <kim...@gm...> - 2008-10-27 08:15:31
|
Dean, On Sun, Oct 26, 2008 at 16:04, Dean Michael Berris <mik...@gm...> wrote: > > It's really more about avoiding as much of the decisions from reaching > runtime -- and putting in the decisions in the design. For instance, > an HTTP URL has waaaaay different parts from an email address (where > both can be depicted as a URI). Another thing you can think of is the > conversion from one URI type to a different URI (or URL) can happen > with explicit compile-time rules: Sure, I can understand the motivation, but sometimes I think the code gets too "artificial" to warrant the effort. I think that's primarily because I don't recognize the idioms, patterns and practices the way I do in the OO world. I'm going to give up on the URI feature. It's evident that we are thinking in diametrically different directions, and I have no way of expressing myself in these terms. I did learn some interesting techniques along the way, though, thanks for the help. - Kim |
From: Dean M. B. <mik...@gm...> - 2008-10-27 13:11:35
|
Hi Kim, On Mon, Oct 27, 2008 at 4:15 PM, Kim Gräsman <kim...@gm...> wrote: > > On Sun, Oct 26, 2008 at 16:04, Dean Michael Berris > <mik...@gm...> wrote: >> >> It's really more about avoiding as much of the decisions from reaching >> runtime -- and putting in the decisions in the design. For instance, >> an HTTP URL has waaaaay different parts from an email address (where >> both can be depicted as a URI). Another thing you can think of is the >> conversion from one URI type to a different URI (or URL) can happen >> with explicit compile-time rules: > > Sure, I can understand the motivation, but sometimes I think the code > gets too "artificial" to warrant the effort. I think that's primarily > because I don't recognize the idioms, patterns and practices the way I > do in the OO world. > In the beginning, I used to think so too -- that this "artificial" approach to doing something that traditional OO and runtime dynamic polymorphism and runtime checks and switches etc. have "straight forward" solutions to. However remember that one of the goals of the project is to move as much of the logic and decision making at compile-time as much as possible because doing things at runtime is usually inefficient, cumbersome, error-prone, and worst of all inflexible as far as design is concerned (object hierarchies are a little evil if you start thinking generic). I wish though that there was a single book/resource that deals with this subject matter (generic programming and template metaprogramming) but unfortunately there isn't one -- but there are quite a few. Let me try and list the two books that have greatly influenced my thinking here: Modern C++ Design: Generic Programming and Design Patterns Applied (by Andrei Alexandrescu) http://www.amazon.com/Modern-Design-Programming-Patterns-Depth/dp/0201704315 C++ Template Metaprogramming: Concepts, Tools, and Techniques from Boost and Beyond (by David Abrahams and Aleksey Gurtovoy) http://www.amazon.com/Template-Metaprogramming-Concepts-Techniques-Depth/dp/0321227255/ref=sr_1_1?ie=UTF8&s=books&qid=1225112272&sr=1-1 If you have the time (and patience? :D) maybe you'll pick up the idioms and patterns/practices faster than I did. :) > I'm going to give up on the URI feature. It's evident that we are > thinking in diametrically different directions, and I have no way of > expressing myself in these terms. > Give it a little time, it just may grow on you. :) We're not on a (strict) schedule (yet) anyway, so there's still time for experimentation and "getting things right". I'm still just "filibustering" and just presenting a possible way of doing things. I may be wrong in the way I'm thinking about it and maybe the approach you will come up with will be better -- or the synergy of our approaches might come up with something different and eventually better. :) > I did learn some interesting techniques along the way, though, thanks > for the help. No problem, and I do hope you keep contributing! Your efforts have been and continue to be definitely appreciated. -- Dean Michael C. Berris Software Engineer, Friendster, Inc. |
From: K. G. <kim...@gm...> - 2008-10-30 07:56:25
|
Hi Dean, On Mon, Oct 27, 2008 at 14:11, Dean Michael Berris <mik...@gm...> wrote: > > In the beginning, I used to think so too -- that this "artificial" > approach to doing something that traditional OO and runtime dynamic > polymorphism and runtime checks and switches etc. have "straight > forward" solutions to. Yeah, one man's artificial is another man's straight-forward, I guess :) > Modern C++ Design: Generic Programming and Design Patterns Applied (by > Andrei Alexandrescu) > http://www.amazon.com/Modern-Design-Programming-Patterns-Depth/dp/0201704315 I liked that one too, though I don't remember much anymore, it's been a while. > C++ Template Metaprogramming: Concepts, Tools, and Techniques from > Boost and Beyond (by David Abrahams and Aleksey Gurtovoy) > http://www.amazon.com/Template-Metaprogramming-Concepts-Techniques-Depth/dp/0321227255/ref=sr_1_1?ie=UTF8&s=books&qid=1225112272&sr=1-1 I've seen it on Amazon, and considered it... Might be interesting, I'll give it a read. > I may be wrong in the way I'm thinking about it and maybe the approach > you will come up with will be better -- or the synergy of our > approaches might come up with something different and eventually > better. :) We'll see how it goes after I come back to work. I'll probably be exhausted anyway :) Cheers, - Kim |