PROTON-1138: c++: get<>/coerce<> API and documentation. Consistent get/coerce templates for proton::value, scalar, message_id and annotation_key.
get<T> - get the value, throw conversion_error if type is not exactly T. coerce<T> - coerce the value to T if it is std::is_convertible, else throw conversion_error - documentation page on C++/AMQP type conversion - API doc for all types involved. - cleanup/hide some internals. Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/d70dab5d Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/d70dab5d Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/d70dab5d Branch: refs/heads/kvdr-PROTON-1159 Commit: d70dab5df243f3a595be21a436f1ef46fa8d8c6d Parents: f5f68d8 Author: Alan Conway <[email protected]> Authored: Mon Mar 14 15:55:46 2016 -0400 Committer: Alan Conway <[email protected]> Committed: Wed Mar 16 16:53:27 2016 -0400 ---------------------------------------------------------------------- examples/cpp/README.dox | 198 +++++++++ examples/cpp/README.hpp | 198 --------- examples/cpp/direct_recv.cpp | 8 +- examples/cpp/encode_decode.cpp | 13 +- examples/cpp/engine/server.cpp | 2 +- examples/cpp/server.cpp | 2 +- examples/cpp/server_direct.cpp | 12 +- proton-c/bindings/cpp/CMakeLists.txt | 2 +- proton-c/bindings/cpp/docs/CMakeLists.txt | 1 + proton-c/bindings/cpp/docs/tutorial.dox | 428 +++++++++++++++++++ proton-c/bindings/cpp/docs/tutorial.hpp | 428 ------------------- proton-c/bindings/cpp/docs/user.doxygen.in | 10 +- proton-c/bindings/cpp/include/proton/amqp.hpp | 40 +- .../cpp/include/proton/annotation_key.hpp | 51 ++- proton-c/bindings/cpp/include/proton/binary.hpp | 26 +- .../bindings/cpp/include/proton/byte_array.hpp | 52 ++- .../bindings/cpp/include/proton/comparable.hpp | 2 + .../cpp/include/proton/connection_engine.hpp | 2 +- proton-c/bindings/cpp/include/proton/data.hpp | 51 +-- .../bindings/cpp/include/proton/decimal.hpp | 5 +- .../bindings/cpp/include/proton/decoder.hpp | 49 ++- proton-c/bindings/cpp/include/proton/deque.hpp | 2 +- .../bindings/cpp/include/proton/duration.hpp | 17 +- .../bindings/cpp/include/proton/encoder.hpp | 65 ++- .../bindings/cpp/include/proton/endpoint.hpp | 5 +- proton-c/bindings/cpp/include/proton/error.hpp | 6 +- .../cpp/include/proton/forward_list.hpp | 2 +- proton-c/bindings/cpp/include/proton/io.hpp | 3 +- proton-c/bindings/cpp/include/proton/link.hpp | 5 + proton-c/bindings/cpp/include/proton/list.hpp | 2 +- .../bindings/cpp/include/proton/message.hpp | 6 +- .../bindings/cpp/include/proton/message_id.hpp | 62 ++- proton-c/bindings/cpp/include/proton/scalar.hpp | 217 ++-------- .../bindings/cpp/include/proton/scalar_base.hpp | 181 ++++++++ .../bindings/cpp/include/proton/session.hpp | 4 +- proton-c/bindings/cpp/include/proton/symbol.hpp | 4 + .../bindings/cpp/include/proton/timestamp.hpp | 18 +- .../bindings/cpp/include/proton/type_id.hpp | 23 +- .../bindings/cpp/include/proton/type_traits.hpp | 108 ++--- proton-c/bindings/cpp/include/proton/types.hpp | 88 +++- .../bindings/cpp/include/proton/types_fwd.hpp | 11 +- proton-c/bindings/cpp/include/proton/url.hpp | 2 +- proton-c/bindings/cpp/include/proton/value.hpp | 106 ++--- proton-c/bindings/cpp/include/proton/vector.hpp | 2 +- proton-c/bindings/cpp/src/decoder.cpp | 127 +++--- proton-c/bindings/cpp/src/encoder.cpp | 21 +- proton-c/bindings/cpp/src/interop_test.cpp | 21 - proton-c/bindings/cpp/src/message.cpp | 4 +- proton-c/bindings/cpp/src/message_test.cpp | 16 +- proton-c/bindings/cpp/src/scalar.cpp | 263 ------------ proton-c/bindings/cpp/src/scalar_base.cpp | 158 +++++++ proton-c/bindings/cpp/src/scalar_test.cpp | 15 +- proton-c/bindings/cpp/src/ssl.cpp | 2 +- proton-c/bindings/cpp/src/test_bits.hpp | 7 + proton-c/bindings/cpp/src/types_internal.hpp | 14 +- proton-c/bindings/cpp/src/value.cpp | 27 +- proton-c/bindings/cpp/src/value_test.cpp | 46 +- tests/tools/apps/cpp/reactor_send.cpp | 2 +- 58 files changed, 1688 insertions(+), 1554 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/examples/cpp/README.dox ---------------------------------------------------------------------- diff --git a/examples/cpp/README.dox b/examples/cpp/README.dox new file mode 100644 index 0000000..1e78774 --- /dev/null +++ b/examples/cpp/README.dox @@ -0,0 +1,198 @@ +// Examples overview. +// +// For a better overview, see the tutorial in the generated documentation. +// +// In your build directory do: +// +// make docs-cpp +// +// then open proton-c/bindings/cpp/docs/html/tutorial.html in your browser. + +// DEVELOPER NOTE: if you are adding or modifying examples you should keep this +// file and ../proton-c/bindings/cpp/docs/tutorial.hpp up to date. + +/** @example helloworld.cpp + +Connects to a broker on 127.0.0.1:5672, establishes a subscription +from the 'examples' node, and creates a sending link to the same +node. Sends one message and receives it back. + +*/ + +/** @example helloworld_direct.cpp + +Variation of helloworld that does not use a broker, but listens for +incoming connections itself. It establishes a connection to itself +with a link over which a single message is sent. This demonstrates the +ease with which a simple daemon an be built using the API. + +*/ + +/** @example simple_send.cpp + +An example of sending a fixed number of messages and tracking their +(asynchronous) acknowledgement. Messages are sent through the 'examples' node on +an intermediary accessible on 127.0.0.1:5672. + +*/ + +/** @example simple_recv.cpp + +Subscribes to the 'examples' node on an intermediary accessible +on 127.0.0.1:5672. Simply prints out the body of received messages. + +*/ + +/** @example direct_send.cpp + +Accepts an incoming connection and then sends like `simple_send`. You can +connect directly to `direct_send` *without* a broker using \ref simple_recv.cpp. +Make sure to stop the broker first or use a different port for `direct_send`. + +*/ + +/** @example direct_recv.cpp + +Accepts an incoming connection and then receives like `simple_recv`. You can +connect directly to `direct_recv` *without* a broker using \ref simple_send.cpp. +Make sure to stop the broker first or use a different port for `direct_recv`. + +*/ + +/// @cond INTERNAL +/** @example encode_decode.cpp + +Shows how C++ data types can be converted to and from AMQP types. + +*/ +/// @endcond + +/** @example client.cpp + +The client part of a request-response example. Sends requests and +prints out responses. Requires an intermediary that supports the AMQP +1.0 dynamic nodes on which the responses are received. The requests +are sent through the 'examples' node. + +*/ + +/** @example server.cpp + +The server part of a request-response example, that receives requests +via the examples node, converts the body to uppercase and sends the +result back to the indicated reply address. + +*/ + +/** @example server_direct.cpp + +A variant of the server part of a request-response example that +accepts incoming connections and does not need an intermediary. Much +like the original server, it receives incoming requests, converts the +body to uppercase and sends the result back to the indicated reply +address. Can be used in conjunction with any of the client +alternatives. + +*/ + +/** @example recurring_timer.cpp + +Shows how to implement recurring time-based events using the scheduler. + +*/ + +/** @example broker.hpp + +Common logic for a simple "mini broker" that creates creates queues +automatically when a client tries to send or subscribe. This file contains +the `queue` class that queues messages and the `broker_handler` class +that manages queues and links and transfers messages to/from clients. + +Examples \ref broker.cpp and \ref engine/broker.cpp use this same +broker logic but show different ways to run it in a server application. + +*/ + +/** @example broker.cpp + +A simple, single-threaded broker using the `proton::container`. You can use this +to run other examples that reqiure an intermediary, or you can use any AMQP 1.0 +broker. This broker creates queues automatically when a client tries to send or +subscribe. + +Uses the broker logic from \ref broker.hpp, the same logic as the +`proton::connection_engine` broker example \ref engine/broker.cpp. + +*/ + +//////////////// connection_engine examples. + +/** \example engine/helloworld.cpp + +`proton::connection_engine` example to send a "Hello World" message to +itself. Compare with the corresponding `proton::container` example \ref +helloworld.cpp. + +*/ + +/** \example engine/simple_send.cpp + +`proton::connection_engine` example of sending a fixed number of messages and +tracking their (asynchronous) acknowledgement. Messages are sent through the +'examples' node on an intermediary accessible on 127.0.0.1:5672. + +*/ + +/** \example engine/simple_recv.cpp + +`proton::connection_engine` example that subscribes to the 'examples' node and prints + the body of received messages. + +*/ + +/** \example engine/direct_send.cpp + +`proton::connection_engine` example accepts an incoming connection and then +sends like `simple_send`. You can connect directly to `direct_send` *without* a +broker using \ref simple_recv.cpp. Make sure to stop the broker first or use a +different port for `direct_send`. + +*/ + +/** \example engine/direct_recv.cpp + +`proton::connection_engine` example accepts an incoming connection and then +receives like `simple_recv`. You can connect directly to `direct_recv` +*without* a broker using \ref simple_send.cpp. Make sure to stop the broker +first or use a different port for `direct_recv`. + +*/ + +/** \example engine/client.cpp + +`proton::connection_engine` client for request-response example. Sends requests and +prints out responses. Requires an intermediary that supports the AMQP 1.0 +dynamic nodes on which the responses are received. The requests are sent through +the 'examples' node. + +*/ + +/** \example engine/server.cpp + +`proton::connection_engine` server for request-response example, that receives +requests via the examples node, converts the body to uppercase and sends the +result back to the indicated reply address. + +*/ + +/** \example engine/broker.cpp + +A simple, single-threaded broker using the `proton::container`. You can use this +to run other examples that reqiure an intermediary, or you can use any AMQP 1.0 +broker. This broker creates queues automatically when a client tries to send or +subscribe. + +Uses the broker logic from \ref broker.hpp, the same logic as the +proton::container` broker example \ref broker.cpp. + +*/ http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/examples/cpp/README.hpp ---------------------------------------------------------------------- diff --git a/examples/cpp/README.hpp b/examples/cpp/README.hpp deleted file mode 100644 index 1e78774..0000000 --- a/examples/cpp/README.hpp +++ /dev/null @@ -1,198 +0,0 @@ -// Examples overview. -// -// For a better overview, see the tutorial in the generated documentation. -// -// In your build directory do: -// -// make docs-cpp -// -// then open proton-c/bindings/cpp/docs/html/tutorial.html in your browser. - -// DEVELOPER NOTE: if you are adding or modifying examples you should keep this -// file and ../proton-c/bindings/cpp/docs/tutorial.hpp up to date. - -/** @example helloworld.cpp - -Connects to a broker on 127.0.0.1:5672, establishes a subscription -from the 'examples' node, and creates a sending link to the same -node. Sends one message and receives it back. - -*/ - -/** @example helloworld_direct.cpp - -Variation of helloworld that does not use a broker, but listens for -incoming connections itself. It establishes a connection to itself -with a link over which a single message is sent. This demonstrates the -ease with which a simple daemon an be built using the API. - -*/ - -/** @example simple_send.cpp - -An example of sending a fixed number of messages and tracking their -(asynchronous) acknowledgement. Messages are sent through the 'examples' node on -an intermediary accessible on 127.0.0.1:5672. - -*/ - -/** @example simple_recv.cpp - -Subscribes to the 'examples' node on an intermediary accessible -on 127.0.0.1:5672. Simply prints out the body of received messages. - -*/ - -/** @example direct_send.cpp - -Accepts an incoming connection and then sends like `simple_send`. You can -connect directly to `direct_send` *without* a broker using \ref simple_recv.cpp. -Make sure to stop the broker first or use a different port for `direct_send`. - -*/ - -/** @example direct_recv.cpp - -Accepts an incoming connection and then receives like `simple_recv`. You can -connect directly to `direct_recv` *without* a broker using \ref simple_send.cpp. -Make sure to stop the broker first or use a different port for `direct_recv`. - -*/ - -/// @cond INTERNAL -/** @example encode_decode.cpp - -Shows how C++ data types can be converted to and from AMQP types. - -*/ -/// @endcond - -/** @example client.cpp - -The client part of a request-response example. Sends requests and -prints out responses. Requires an intermediary that supports the AMQP -1.0 dynamic nodes on which the responses are received. The requests -are sent through the 'examples' node. - -*/ - -/** @example server.cpp - -The server part of a request-response example, that receives requests -via the examples node, converts the body to uppercase and sends the -result back to the indicated reply address. - -*/ - -/** @example server_direct.cpp - -A variant of the server part of a request-response example that -accepts incoming connections and does not need an intermediary. Much -like the original server, it receives incoming requests, converts the -body to uppercase and sends the result back to the indicated reply -address. Can be used in conjunction with any of the client -alternatives. - -*/ - -/** @example recurring_timer.cpp - -Shows how to implement recurring time-based events using the scheduler. - -*/ - -/** @example broker.hpp - -Common logic for a simple "mini broker" that creates creates queues -automatically when a client tries to send or subscribe. This file contains -the `queue` class that queues messages and the `broker_handler` class -that manages queues and links and transfers messages to/from clients. - -Examples \ref broker.cpp and \ref engine/broker.cpp use this same -broker logic but show different ways to run it in a server application. - -*/ - -/** @example broker.cpp - -A simple, single-threaded broker using the `proton::container`. You can use this -to run other examples that reqiure an intermediary, or you can use any AMQP 1.0 -broker. This broker creates queues automatically when a client tries to send or -subscribe. - -Uses the broker logic from \ref broker.hpp, the same logic as the -`proton::connection_engine` broker example \ref engine/broker.cpp. - -*/ - -//////////////// connection_engine examples. - -/** \example engine/helloworld.cpp - -`proton::connection_engine` example to send a "Hello World" message to -itself. Compare with the corresponding `proton::container` example \ref -helloworld.cpp. - -*/ - -/** \example engine/simple_send.cpp - -`proton::connection_engine` example of sending a fixed number of messages and -tracking their (asynchronous) acknowledgement. Messages are sent through the -'examples' node on an intermediary accessible on 127.0.0.1:5672. - -*/ - -/** \example engine/simple_recv.cpp - -`proton::connection_engine` example that subscribes to the 'examples' node and prints - the body of received messages. - -*/ - -/** \example engine/direct_send.cpp - -`proton::connection_engine` example accepts an incoming connection and then -sends like `simple_send`. You can connect directly to `direct_send` *without* a -broker using \ref simple_recv.cpp. Make sure to stop the broker first or use a -different port for `direct_send`. - -*/ - -/** \example engine/direct_recv.cpp - -`proton::connection_engine` example accepts an incoming connection and then -receives like `simple_recv`. You can connect directly to `direct_recv` -*without* a broker using \ref simple_send.cpp. Make sure to stop the broker -first or use a different port for `direct_recv`. - -*/ - -/** \example engine/client.cpp - -`proton::connection_engine` client for request-response example. Sends requests and -prints out responses. Requires an intermediary that supports the AMQP 1.0 -dynamic nodes on which the responses are received. The requests are sent through -the 'examples' node. - -*/ - -/** \example engine/server.cpp - -`proton::connection_engine` server for request-response example, that receives -requests via the examples node, converts the body to uppercase and sends the -result back to the indicated reply address. - -*/ - -/** \example engine/broker.cpp - -A simple, single-threaded broker using the `proton::container`. You can use this -to run other examples that reqiure an intermediary, or you can use any AMQP 1.0 -broker. This broker creates queues automatically when a client tries to send or -subscribe. - -Uses the broker logic from \ref broker.hpp, the same logic as the -proton::container` broker example \ref broker.cpp. - -*/ http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/examples/cpp/direct_recv.cpp ---------------------------------------------------------------------- diff --git a/examples/cpp/direct_recv.cpp b/examples/cpp/direct_recv.cpp index ffb2f03..89bb966 100644 --- a/examples/cpp/direct_recv.cpp +++ b/examples/cpp/direct_recv.cpp @@ -49,16 +49,16 @@ class direct_recv : public proton::handler { void on_message(proton::event &e) { proton::message& msg = e.message(); - - if (msg.id().get<uint64_t>() < received) { + + if (proton::coerce<uint64_t>(msg.id()) < received) { return; // Ignore duplicate } - + if (expected == 0 || received < expected) { std::cout << msg.body() << std::endl; received++; } - + if (received == expected) { e.receiver().close(); e.connection().close(); http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/examples/cpp/encode_decode.cpp ---------------------------------------------------------------------- diff --git a/examples/cpp/encode_decode.cpp b/examples/cpp/encode_decode.cpp index 12fc1ed..b1c39b8 100644 --- a/examples/cpp/encode_decode.cpp +++ b/examples/cpp/encode_decode.cpp @@ -71,13 +71,13 @@ void uniform_containers() { v = a; print(v); std::list<int> a1; - v.get(a1); // Decode as a C++ std::list instead + proton::get(v, a1); std::cout << a1 << std::endl; // You can specify that a container should be encoded as an AMQP list instead. v = proton::codec::encoder::list(a1); print(v); - std::cout << v.get<std::vector<int> >() << std::endl; + std::cout << proton::get<std::vector<int> >(v) << std::endl; // C++ map types (types with key_type, mapped_type) convert to an AMQP map by default. std::map<std::string, int> m; @@ -85,7 +85,7 @@ void uniform_containers() { m["two"] = 2; v = m; print(v); - std::cout << v.get<std::map<std::string, int> >() << std::endl; + std::cout << proton::get<std::map<std::string, int> >(v) << std::endl; // A sequence of pairs encodes as an AMQP MAP, which lets you control the encoded order. std::vector<std::pair<std::string, int> > pairs; @@ -121,16 +121,15 @@ void mixed_containers() { // By default, a sequence of proton::value is treated as an AMQP list. v = l; print(v); - std::vector<proton::value> l2; - v.get(l2); + std::vector<proton::value> l2 = proton::get<std::vector<proton::value> >(v); std::cout << l2 << std::endl; std::map<proton::value, proton::value> m; m[proton::value("five")] = proton::value(5); m[proton::value(4)] = proton::value("four"); v = m; print(v); - std::map<proton::value, proton::value> m2; - v.get(m2); + typedef std::map<proton::value, proton::value> value_map; + value_map m2(proton::get<value_map>(v)); std::cout << m2 << std::endl; } http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/examples/cpp/engine/server.cpp ---------------------------------------------------------------------- diff --git a/examples/cpp/engine/server.cpp b/examples/cpp/engine/server.cpp index 4641c4c..92ee044 100644 --- a/examples/cpp/engine/server.cpp +++ b/examples/cpp/engine/server.cpp @@ -61,7 +61,7 @@ class server : public proton::handler { std::string reply_to = e.message().reply_to(); proton::message reply; reply.address(reply_to); - reply.body(to_upper(e.message().body().get<std::string>())); + reply.body(to_upper(proton::get<std::string>(e.message().body()))); reply.correlation_id(e.message().correlation_id()); if (!senders[reply_to]) senders[reply_to] = e.connection().open_sender(reply_to); http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/examples/cpp/server.cpp ---------------------------------------------------------------------- diff --git a/examples/cpp/server.cpp b/examples/cpp/server.cpp index 8ac34cc..58fe52d 100644 --- a/examples/cpp/server.cpp +++ b/examples/cpp/server.cpp @@ -65,7 +65,7 @@ class server : public proton::handler { proton::message reply; reply.address(reply_to); - reply.body(to_upper(e.message().body().get<std::string>())); + reply.body(to_upper(proton::get<std::string>(e.message().body()))); reply.correlation_id(e.message().correlation_id()); if (!senders[reply_to]) { http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/examples/cpp/server_direct.cpp ---------------------------------------------------------------------- diff --git a/examples/cpp/server_direct.cpp b/examples/cpp/server_direct.cpp index 9d3b79c..c166917 100644 --- a/examples/cpp/server_direct.cpp +++ b/examples/cpp/server_direct.cpp @@ -66,7 +66,7 @@ class server : public proton::handler { void on_link_open(proton::event& e) { proton::link link = e.link(); - + if (!!link.sender() && link.remote_source().dynamic()) { link.local_source().address(generate_address()); senders[link.local_source().address()] = link.sender(); @@ -75,18 +75,18 @@ class server : public proton::handler { void on_message(proton::event &e) { std::cout << "Received " << e.message().body() << std::endl; - + std::string reply_to = e.message().reply_to(); sender_map::iterator it = senders.find(reply_to); - + if (it == senders.end()) { std::cout << "No link for reply_to: " << reply_to << std::endl; } else { proton::sender sender = it->second; proton::message reply; - + reply.address(reply_to); - reply.body(to_upper(e.message().body().get<std::string>())); + reply.body(to_upper(proton::get<std::string>(e.message().body()))); reply.correlation_id(e.message().correlation_id()); sender.send(reply); @@ -102,7 +102,7 @@ int main(int argc, char **argv) { try { opts.parse(); - + server srv(address); proton::container(srv).run(); http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/proton-c/bindings/cpp/CMakeLists.txt ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/CMakeLists.txt b/proton-c/bindings/cpp/CMakeLists.txt index 11b299d..ebd38c1 100644 --- a/proton-c/bindings/cpp/CMakeLists.txt +++ b/proton-c/bindings/cpp/CMakeLists.txt @@ -27,7 +27,7 @@ include_directories( set(qpid-proton-cpp-source src/acceptor.cpp src/binary.cpp - src/scalar.cpp + src/scalar_base.cpp src/condition.cpp src/connection.cpp src/connection_options.cpp http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/proton-c/bindings/cpp/docs/CMakeLists.txt ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/docs/CMakeLists.txt b/proton-c/bindings/cpp/docs/CMakeLists.txt index cf7876e..c5ae4e5 100644 --- a/proton-c/bindings/cpp/docs/CMakeLists.txt +++ b/proton-c/bindings/cpp/docs/CMakeLists.txt @@ -18,6 +18,7 @@ # find_package(Doxygen) + if (DOXYGEN_FOUND) configure_file ( ${CMAKE_CURRENT_SOURCE_DIR}/user.doxygen.in http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/proton-c/bindings/cpp/docs/tutorial.dox ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/docs/tutorial.dox b/proton-c/bindings/cpp/docs/tutorial.dox new file mode 100644 index 0000000..dcfbe05 --- /dev/null +++ b/proton-c/bindings/cpp/docs/tutorial.dox @@ -0,0 +1,428 @@ +// -*-markdown-*- +// NOTE: doxygen can include markdown pages directly but there seems to be a bug +// that shows messed-up line numbers in \skip \until code extracts so this file +// is markdown wrapped in a C++ comment - which works. + +/**\page tutorial Tutorial + +This is a brief tutorial that will walk you through the fundamentals of building +messaging applications in incremental steps. There are further examples, in +addition the ones mentioned in the tutorial. + +Some of the examples require an AMQP *broker* that can receive, store and send +messages. \ref broker.hpp and \ref broker.cpp define a simple example +broker. Run without arguments it listens on `0.0.0.0:5672`, the standard AMQP +port on all network interfaces. To use a different port or network interface: + + broker -a <host>:<port> + +Instead of the example broker, you can use any AMQP 1.0 compliant broker. You +must configure your broker to have a queue (or topic) named "examples". + +The `helloworld` examples take an optional URL argument. The other examples take +an option `-a URL`. A URL looks like: + + HOST:PORT/ADDRESS + +It usually defaults to `127.0.0.1:5672/examples`, but you can change this if +your broker is on a different host or port, or you want to use a different queue +or topic name (the ADDRESS part of the URL). URL details are at `proton::url` + +The first part of the tutorial uses the `proton::container`, later we will +show some of the same examples implemented using the `proton::connection_engine`. +Most of the code is the same for either approach. + +Hello World! +------------ + +\dontinclude helloworld.cpp + +Tradition dictates that we start with hello world! This example sends a message +to a broker and the receives the same message back to demonstrate sending and +receiving. In a realistic system the sender and receiver would normally be in +different processes. The complete example is \ref helloworld.cpp + +We will include the following classes: `proton::container` runs an event loop +which dispatches events to a `proton::handler`. This allows a *reactive* +style of programming which is well suited to messaging applications. `proton::url` is a simple parser for the URL format mentioned above. + +\skip proton/container +\until proton/url + +We will define a class `hello_world` which is a subclass of +`proton::handler` and over-rides functions to handle the events +of interest in sending and receiving a message. + +\skip class hello_world +\until {} + +`on_start()` is called when the event loop first starts. We handle that by +establishing a connection and creating a sender and a receiver. + +\skip on_start +\until } + +`on_sendable()` is called when message can be transferred over the associated +sender link to the remote peer. We create a `proton::message`, set the message +body to `"Hello World!"` and send the message. Then we close the sender as we only +want to send one message. Closing the sender will prevent further calls to +`on_sendable()`. + +\skip on_sendable +\until } + +`on_message()` is called when a message is received. We just print the body of +the message and close the connection, as we only want one message + +\skip on_message +\until } + +The message body is a `proton::value`, see the documentation for more on how to +extract the message body as type-safe C++ values. + +Our `main` function creates an instance of the `hello_world` handler and a +proton::container using that handler. Calling `proton::container::run` sets +things in motion and returns when we close the connection as there is nothing +further to do. It may throw an exception, which will be a subclass of +`proton::error`. That in turn is a subclass of `std::exception`. + +\skip main +\until } +\until } +\until } + +Hello World, Direct! +-------------------- + +\dontinclude helloworld_direct.cpp + +Though often used in conjunction with a broker, AMQP does not *require* this. It +also allows senders and receivers to communicate directly if desired. + +We will modify our example to send a message directly to itself. This is a bit +contrived but illustrates both sides of the direct send/receive scenario. Full +code at \ref helloworld_direct.cpp + +The first difference, is that rather than creating a receiver on the same +connection as our sender, we listen for incoming connections by invoking the +`proton::container::listen()` method on the container. + +\skip on_start +\until } + +As we only need then to initiate one link, the sender, we can do that by +passing in a url rather than an existing connection, and the connection +will also be automatically established for us. + +We send the message in response to the `on_sendable()` callback and +print the message out in response to the `on_message()` callback exactly +as before. + +\skip on_sendable +\until } +\until } + +However we also handle two new events. We now close the connection from +the senders side once the message has been accepted. +The acceptance of the message is an indication of successful transfer to the +peer. We are notified of that event through the `on_delivery_accept()` +callback. + +\skip on_delivery_accept +\until } + +Then, once the connection has been closed, of which we are +notified through the `on_connection_close()` callback, we stop accepting incoming +connections at which point there is no work to be done and the +event loop exits, and the run() method will return. + +\skip on_connection_close +\until } + +So now we have our example working without a broker involved! + +Note that for this example we pick an "unusual" port 8888 since we are talking +to ourselves rather than a broker. + +\skipline url = + +Asynchronous Send and Receive +----------------------------- + +Of course, these `HelloWorld!` examples are very artificial, communicating as +they do over a network connection but with the same process. A more realistic +example involves communication between separate processes (which could indeed be +running on completely separate machines). + +Let's separate the sender from the receiver, and transfer more than a single +message between them. + +We'll start with a simple sender \ref simple_send.cpp. + +\dontinclude simple_send.cpp + +As with the previous example, we define the application logic in a class that +handles events. Because we are transferring more than one message, we need to +keep track of how many we have sent. We'll use a `sent` member variable for +that. The `total` member variable will hold the number of messages we want to +send. + +\skip class simple_send +\until total + +As before, we use the `on_start()` event to establish our sender link over which +we will transfer messages. + +\skip on_start +\until } + +AMQP defines a credit-based flow control mechanism. Flow control allows +the receiver to control how many messages it is prepared to receive at a +given time and thus prevents any component being overwhelmed by the +number of messages it is sent. + +In the `on_sendable()` callback, we check that our sender has credit +before sending messages. We also check that we haven't already sent the +required number of messages. + +\skip on_sendable +\until } +\until } + +The `proton::sender::send()` call above is asynchronous. When it returns the +message has not yet actually been transferred across the network to the +receiver. By handling the `on_accepted()` event, we can get notified when the +receiver has received and accepted the message. In our example we use this event +to track the confirmation of the messages we have sent. We only close the +connection and exit when the receiver has received all the messages we wanted to +send. + +\skip on_delivery_accept +\until } +\until } + +If we are disconnected after a message is sent and before it has been +confirmed by the receiver, it is said to be `in doubt`. We don't know +whether or not it was received. In this example, we will handle that by +resending any in-doubt messages. This is known as an 'at-least-once' +guarantee, since each message should eventually be received at least +once, though a given message may be received more than once (i.e. +duplicates are possible). In the `on_disconnected()` callback, we reset +the sent count to reflect only those that have been confirmed. The +library will automatically try to reconnect for us, and when our sender +is sendable again, we can restart from the point we know the receiver +got to. + +\skip on_disconnect +\until } + +\dontinclude simple_recv.cpp + +Now let's look at the corresponding receiver \ref simple_recv.cpp + +This time we'll use an `expected` member variable for for the number of messages we expect and +a `received` variable to count how many we have received so far. + +\skip class simple_recv +\until received + +We handle `on_start()` by creating our receiver, much like we +did for the sender. + +\skip on_start +\until } + +We also handle the `on_message()` event for received messages and print the +message out as in the `Hello World!` examples. However we add some logic to +allow the receiver to wait for a given number of messages, then to close the +connection and exit. We also add some logic to check for and ignore duplicates, +using a simple sequential id scheme. + +\skip on_message +\until } + +Direct Send and Receive +----------------------- + +Sending between these two examples requires an intermediary broker since neither +accepts incoming connections. AMQP allows us to send messages directly between +two processes. In that case one or other of the processes needs to accept +incoming connections. Let's create a modified version of the receiving example +that does this with \ref direct_recv.cpp + +\dontinclude direct_recv.cpp + +There are only two differences here. Instead of initiating a link (and +implicitly a connection), we listen for incoming connections. + + +\skip on_start +\until } + +When we have received all the expected messages, we then stop listening for +incoming connections by closing the acceptor object. + +\skip on_message +\until } +\until } +\until } +\until } + +You can use the \ref simple_send.cpp example to send to this receiver +directly. (Note: you will need to stop any broker that is listening on the 5672 +port, or else change the port used by specifying a different address to each +example via the -a command line switch). + +We can also modify the sender to allow the original receiver to connect to it, +in \ref direct_send.cpp. Again that just requires two modifications: + +\dontinclude direct_send.cpp + +As with the modified receiver, instead of initiating establishment of a +link, we listen for incoming connections. + +\skip on_start +\until } + +When we have received confirmation of all the messages we sent, we can +close the acceptor in order to exit. + +\skip on_delivery_accept +\until } +\until } + +To try this modified sender, run the original \ref simple_recv.cpp against it. + +The symmetry in the underlying AMQP that enables this is quite unique and +elegant, and in reflecting this the proton API provides a flexible toolkit for +implementing all sorts of interesting intermediaries (\ref broker.hpp and \ref +broker.cpp provide a simple broker for testing purposes is an example of this). + +Request/Response +---------------- + +A common pattern is to send a request message and expect a response message in +return. AMQP has special support for this pattern. Let's have a look at a simple +example. We'll start with \ref server.cpp, the program that will process the +request and send the response. Note that we are still using a broker in this +example. + +Our server will provide a very simple service: it will respond with the +body of the request converted to uppercase. + +\dontinclude server.cpp +\skip class server +\until }; + +The code here is not too different from the simple receiver example. When we +receive a request in `on_message` however, we look at the +`proton::message::reply_to` address and create a sender with that address for +the response. We'll cache the senders incase we get further requests with the +same `reply_to`. + +Now let's create a simple \ref client.cpp to test this service out. + +\dontinclude client.cpp + +Our client takes a list of strings to send as requests + +\skipline client( + +Since we will be sending and receiving, we create a sender and a receiver in +`on_start`. Our receiver has a blank address and sets the `dynamic` flag to +true, which means we expect the remote end (broker or server) to assign a unique +address for us. + +\skip on_start +\until } + +Now a function to send the next request from our list of requests. We set the +reply_to address to be the dynamically assigned address of our receiver. + +\skip send_request +\until } + +We need to use the address assigned by the broker as the `reply_to` address of +our requests, so we can't send them until our receiver has been set up. To do +that, we add an `on_link_open()` method to our handler class, and if the link +associated with event is the receiver, we use that as the trigger to send our +first request. + +\skip on_link_open +\until } + +When we receive a reply, we send the next request. + +\skip on_message +\until } +\until } +\until } + +Direct Request/Response +----------------------- + +We can avoid the intermediary process by writing a server that accepts +connections directly, \ref server_direct.cpp. It involves the following changes +to our original server: + +\dontinclude server_direct.cpp + +Our server must generate a unique reply-to addresses for links from the +client that request a dynamic address (previously this was done by the broker.) +We use a simple counter. + +\skip generate_address +\until } + +Next we need to handle incoming requests for links with dynamic addresses from +the client. We give the link a unique address and record it in our `senders` +map. + +\skip on_link_open +\until } + +Note we are interested in *sender* links above because we are implementing the +server. A *receiver* link created on the client corresponds to a *sender* link +on the server. + +Finally when we receive a message we look up its `reply_to` in our senders map and send the reply. + +\skip on_message +\until } +\until } +\until } + +Connection Engine +----------------- + +The `proton::connection_engine` is an alternative to the container. For simple +applications with a single connection, its use is about the same as the the +`proton::container`, but it allows more flexibility for multi-threaded +applications or applications with unusual IO requirements. + +\dontinclude engine/helloworld.cpp + +We'll look at the \ref engine/helloworld.cpp example step-by-step to see how it differs +from the container \ref helloworld.cpp version. + +First we include the `proton::io::socket_engine` class, which is a `proton::connection_engine` +that uses socket IO. + +\skipline proton/io.hpp + +Our `hello_world` class differs only in the `on_start()` method. Instead of +calling `container.connect()`, we simply call `proton::connection::open` to open the +engine's' connection: + +\skip on_start +\until } + +Our `main` function only differs in that it creates and runs a `socket_engine` +instead of a `container`. + +\skip main +\until } +\until } +\until } + +*/ http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/proton-c/bindings/cpp/docs/tutorial.hpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/docs/tutorial.hpp b/proton-c/bindings/cpp/docs/tutorial.hpp deleted file mode 100644 index dcfbe05..0000000 --- a/proton-c/bindings/cpp/docs/tutorial.hpp +++ /dev/null @@ -1,428 +0,0 @@ -// -*-markdown-*- -// NOTE: doxygen can include markdown pages directly but there seems to be a bug -// that shows messed-up line numbers in \skip \until code extracts so this file -// is markdown wrapped in a C++ comment - which works. - -/**\page tutorial Tutorial - -This is a brief tutorial that will walk you through the fundamentals of building -messaging applications in incremental steps. There are further examples, in -addition the ones mentioned in the tutorial. - -Some of the examples require an AMQP *broker* that can receive, store and send -messages. \ref broker.hpp and \ref broker.cpp define a simple example -broker. Run without arguments it listens on `0.0.0.0:5672`, the standard AMQP -port on all network interfaces. To use a different port or network interface: - - broker -a <host>:<port> - -Instead of the example broker, you can use any AMQP 1.0 compliant broker. You -must configure your broker to have a queue (or topic) named "examples". - -The `helloworld` examples take an optional URL argument. The other examples take -an option `-a URL`. A URL looks like: - - HOST:PORT/ADDRESS - -It usually defaults to `127.0.0.1:5672/examples`, but you can change this if -your broker is on a different host or port, or you want to use a different queue -or topic name (the ADDRESS part of the URL). URL details are at `proton::url` - -The first part of the tutorial uses the `proton::container`, later we will -show some of the same examples implemented using the `proton::connection_engine`. -Most of the code is the same for either approach. - -Hello World! ------------- - -\dontinclude helloworld.cpp - -Tradition dictates that we start with hello world! This example sends a message -to a broker and the receives the same message back to demonstrate sending and -receiving. In a realistic system the sender and receiver would normally be in -different processes. The complete example is \ref helloworld.cpp - -We will include the following classes: `proton::container` runs an event loop -which dispatches events to a `proton::handler`. This allows a *reactive* -style of programming which is well suited to messaging applications. `proton::url` is a simple parser for the URL format mentioned above. - -\skip proton/container -\until proton/url - -We will define a class `hello_world` which is a subclass of -`proton::handler` and over-rides functions to handle the events -of interest in sending and receiving a message. - -\skip class hello_world -\until {} - -`on_start()` is called when the event loop first starts. We handle that by -establishing a connection and creating a sender and a receiver. - -\skip on_start -\until } - -`on_sendable()` is called when message can be transferred over the associated -sender link to the remote peer. We create a `proton::message`, set the message -body to `"Hello World!"` and send the message. Then we close the sender as we only -want to send one message. Closing the sender will prevent further calls to -`on_sendable()`. - -\skip on_sendable -\until } - -`on_message()` is called when a message is received. We just print the body of -the message and close the connection, as we only want one message - -\skip on_message -\until } - -The message body is a `proton::value`, see the documentation for more on how to -extract the message body as type-safe C++ values. - -Our `main` function creates an instance of the `hello_world` handler and a -proton::container using that handler. Calling `proton::container::run` sets -things in motion and returns when we close the connection as there is nothing -further to do. It may throw an exception, which will be a subclass of -`proton::error`. That in turn is a subclass of `std::exception`. - -\skip main -\until } -\until } -\until } - -Hello World, Direct! --------------------- - -\dontinclude helloworld_direct.cpp - -Though often used in conjunction with a broker, AMQP does not *require* this. It -also allows senders and receivers to communicate directly if desired. - -We will modify our example to send a message directly to itself. This is a bit -contrived but illustrates both sides of the direct send/receive scenario. Full -code at \ref helloworld_direct.cpp - -The first difference, is that rather than creating a receiver on the same -connection as our sender, we listen for incoming connections by invoking the -`proton::container::listen()` method on the container. - -\skip on_start -\until } - -As we only need then to initiate one link, the sender, we can do that by -passing in a url rather than an existing connection, and the connection -will also be automatically established for us. - -We send the message in response to the `on_sendable()` callback and -print the message out in response to the `on_message()` callback exactly -as before. - -\skip on_sendable -\until } -\until } - -However we also handle two new events. We now close the connection from -the senders side once the message has been accepted. -The acceptance of the message is an indication of successful transfer to the -peer. We are notified of that event through the `on_delivery_accept()` -callback. - -\skip on_delivery_accept -\until } - -Then, once the connection has been closed, of which we are -notified through the `on_connection_close()` callback, we stop accepting incoming -connections at which point there is no work to be done and the -event loop exits, and the run() method will return. - -\skip on_connection_close -\until } - -So now we have our example working without a broker involved! - -Note that for this example we pick an "unusual" port 8888 since we are talking -to ourselves rather than a broker. - -\skipline url = - -Asynchronous Send and Receive ------------------------------ - -Of course, these `HelloWorld!` examples are very artificial, communicating as -they do over a network connection but with the same process. A more realistic -example involves communication between separate processes (which could indeed be -running on completely separate machines). - -Let's separate the sender from the receiver, and transfer more than a single -message between them. - -We'll start with a simple sender \ref simple_send.cpp. - -\dontinclude simple_send.cpp - -As with the previous example, we define the application logic in a class that -handles events. Because we are transferring more than one message, we need to -keep track of how many we have sent. We'll use a `sent` member variable for -that. The `total` member variable will hold the number of messages we want to -send. - -\skip class simple_send -\until total - -As before, we use the `on_start()` event to establish our sender link over which -we will transfer messages. - -\skip on_start -\until } - -AMQP defines a credit-based flow control mechanism. Flow control allows -the receiver to control how many messages it is prepared to receive at a -given time and thus prevents any component being overwhelmed by the -number of messages it is sent. - -In the `on_sendable()` callback, we check that our sender has credit -before sending messages. We also check that we haven't already sent the -required number of messages. - -\skip on_sendable -\until } -\until } - -The `proton::sender::send()` call above is asynchronous. When it returns the -message has not yet actually been transferred across the network to the -receiver. By handling the `on_accepted()` event, we can get notified when the -receiver has received and accepted the message. In our example we use this event -to track the confirmation of the messages we have sent. We only close the -connection and exit when the receiver has received all the messages we wanted to -send. - -\skip on_delivery_accept -\until } -\until } - -If we are disconnected after a message is sent and before it has been -confirmed by the receiver, it is said to be `in doubt`. We don't know -whether or not it was received. In this example, we will handle that by -resending any in-doubt messages. This is known as an 'at-least-once' -guarantee, since each message should eventually be received at least -once, though a given message may be received more than once (i.e. -duplicates are possible). In the `on_disconnected()` callback, we reset -the sent count to reflect only those that have been confirmed. The -library will automatically try to reconnect for us, and when our sender -is sendable again, we can restart from the point we know the receiver -got to. - -\skip on_disconnect -\until } - -\dontinclude simple_recv.cpp - -Now let's look at the corresponding receiver \ref simple_recv.cpp - -This time we'll use an `expected` member variable for for the number of messages we expect and -a `received` variable to count how many we have received so far. - -\skip class simple_recv -\until received - -We handle `on_start()` by creating our receiver, much like we -did for the sender. - -\skip on_start -\until } - -We also handle the `on_message()` event for received messages and print the -message out as in the `Hello World!` examples. However we add some logic to -allow the receiver to wait for a given number of messages, then to close the -connection and exit. We also add some logic to check for and ignore duplicates, -using a simple sequential id scheme. - -\skip on_message -\until } - -Direct Send and Receive ------------------------ - -Sending between these two examples requires an intermediary broker since neither -accepts incoming connections. AMQP allows us to send messages directly between -two processes. In that case one or other of the processes needs to accept -incoming connections. Let's create a modified version of the receiving example -that does this with \ref direct_recv.cpp - -\dontinclude direct_recv.cpp - -There are only two differences here. Instead of initiating a link (and -implicitly a connection), we listen for incoming connections. - - -\skip on_start -\until } - -When we have received all the expected messages, we then stop listening for -incoming connections by closing the acceptor object. - -\skip on_message -\until } -\until } -\until } -\until } - -You can use the \ref simple_send.cpp example to send to this receiver -directly. (Note: you will need to stop any broker that is listening on the 5672 -port, or else change the port used by specifying a different address to each -example via the -a command line switch). - -We can also modify the sender to allow the original receiver to connect to it, -in \ref direct_send.cpp. Again that just requires two modifications: - -\dontinclude direct_send.cpp - -As with the modified receiver, instead of initiating establishment of a -link, we listen for incoming connections. - -\skip on_start -\until } - -When we have received confirmation of all the messages we sent, we can -close the acceptor in order to exit. - -\skip on_delivery_accept -\until } -\until } - -To try this modified sender, run the original \ref simple_recv.cpp against it. - -The symmetry in the underlying AMQP that enables this is quite unique and -elegant, and in reflecting this the proton API provides a flexible toolkit for -implementing all sorts of interesting intermediaries (\ref broker.hpp and \ref -broker.cpp provide a simple broker for testing purposes is an example of this). - -Request/Response ----------------- - -A common pattern is to send a request message and expect a response message in -return. AMQP has special support for this pattern. Let's have a look at a simple -example. We'll start with \ref server.cpp, the program that will process the -request and send the response. Note that we are still using a broker in this -example. - -Our server will provide a very simple service: it will respond with the -body of the request converted to uppercase. - -\dontinclude server.cpp -\skip class server -\until }; - -The code here is not too different from the simple receiver example. When we -receive a request in `on_message` however, we look at the -`proton::message::reply_to` address and create a sender with that address for -the response. We'll cache the senders incase we get further requests with the -same `reply_to`. - -Now let's create a simple \ref client.cpp to test this service out. - -\dontinclude client.cpp - -Our client takes a list of strings to send as requests - -\skipline client( - -Since we will be sending and receiving, we create a sender and a receiver in -`on_start`. Our receiver has a blank address and sets the `dynamic` flag to -true, which means we expect the remote end (broker or server) to assign a unique -address for us. - -\skip on_start -\until } - -Now a function to send the next request from our list of requests. We set the -reply_to address to be the dynamically assigned address of our receiver. - -\skip send_request -\until } - -We need to use the address assigned by the broker as the `reply_to` address of -our requests, so we can't send them until our receiver has been set up. To do -that, we add an `on_link_open()` method to our handler class, and if the link -associated with event is the receiver, we use that as the trigger to send our -first request. - -\skip on_link_open -\until } - -When we receive a reply, we send the next request. - -\skip on_message -\until } -\until } -\until } - -Direct Request/Response ------------------------ - -We can avoid the intermediary process by writing a server that accepts -connections directly, \ref server_direct.cpp. It involves the following changes -to our original server: - -\dontinclude server_direct.cpp - -Our server must generate a unique reply-to addresses for links from the -client that request a dynamic address (previously this was done by the broker.) -We use a simple counter. - -\skip generate_address -\until } - -Next we need to handle incoming requests for links with dynamic addresses from -the client. We give the link a unique address and record it in our `senders` -map. - -\skip on_link_open -\until } - -Note we are interested in *sender* links above because we are implementing the -server. A *receiver* link created on the client corresponds to a *sender* link -on the server. - -Finally when we receive a message we look up its `reply_to` in our senders map and send the reply. - -\skip on_message -\until } -\until } -\until } - -Connection Engine ------------------ - -The `proton::connection_engine` is an alternative to the container. For simple -applications with a single connection, its use is about the same as the the -`proton::container`, but it allows more flexibility for multi-threaded -applications or applications with unusual IO requirements. - -\dontinclude engine/helloworld.cpp - -We'll look at the \ref engine/helloworld.cpp example step-by-step to see how it differs -from the container \ref helloworld.cpp version. - -First we include the `proton::io::socket_engine` class, which is a `proton::connection_engine` -that uses socket IO. - -\skipline proton/io.hpp - -Our `hello_world` class differs only in the `on_start()` method. Instead of -calling `container.connect()`, we simply call `proton::connection::open` to open the -engine's' connection: - -\skip on_start -\until } - -Our `main` function only differs in that it creates and runs a `socket_engine` -instead of a `container`. - -\skip main -\until } -\until } -\until } - -*/ http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/proton-c/bindings/cpp/docs/user.doxygen.in ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/docs/user.doxygen.in b/proton-c/bindings/cpp/docs/user.doxygen.in index e76337a..26b1784 100644 --- a/proton-c/bindings/cpp/docs/user.doxygen.in +++ b/proton-c/bindings/cpp/docs/user.doxygen.in @@ -25,13 +25,13 @@ OUTPUT_DIRECTORY = . OUTPUT_LANGUAGE = English BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES +ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = YES JAVADOC_AUTOBRIEF = YES MULTILINE_CPP_IS_BRIEF = NO INHERIT_DOCS = YES BUILTIN_STL_SUPPORT = YES INLINE_SIMPLE_STRUCTS = YES -EXTRACT_LOCAL_CLASSES = NO HIDE_UNDOC_CLASSES = YES HIDE_COMPOUND_REFERENCE = YES HIDE_SCOPE_NAMES = YES @@ -44,6 +44,7 @@ ENABLE_PREPROCESSING = YES MACRO_EXPANSION = YES EXPAND_ONLY_PREDEF = YES PREDEFINED = protected=private PN_CPP_EXTERN= +EXCLUDE_SYMBOLS = internal internal::* # Configuration options related to warning and progress messages @@ -52,14 +53,17 @@ WARNINGS = YES # Configuration options related to the input files -INPUT = @CMAKE_SOURCE_DIR@/proton-c/bindings/cpp/include @CMAKE_SOURCE_DIR@/proton-c/bindings/cpp/docs @CMAKE_SOURCE_DIR@/examples/cpp/README.hpp -FILE_PATTERNS = *.hpp *.md +INPUT = @CMAKE_SOURCE_DIR@/proton-c/bindings/cpp/include @CMAKE_SOURCE_DIR@/proton-c/bindings/cpp/docs @CMAKE_SOURCE_DIR@/examples/cpp/README.dox +FILE_PATTERNS = *.hpp *.md *.dox +FULL_PATH_NAMES = YES RECURSIVE = YES +STRIP_FROM_PATH = @CMAKE_SOURCE_DIR@/proton-c/bindings/cpp/include EXAMPLE_PATH = @CMAKE_SOURCE_DIR@/examples/cpp EXAMPLE_RECURSIVE = YES # View and list options +GENERATE_TREEVIEW = YES GENERATE_TODOLIST = NO GENERATE_TESTLIST = NO GENERATE_BUGLIST = NO http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/proton-c/bindings/cpp/include/proton/amqp.hpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/include/proton/amqp.hpp b/proton-c/bindings/cpp/include/proton/amqp.hpp index 2ca122f..990bf06 100644 --- a/proton-c/bindings/cpp/include/proton/amqp.hpp +++ b/proton-c/bindings/cpp/include/proton/amqp.hpp @@ -25,7 +25,8 @@ namespace proton { - +/// AMQP typedefs for C++ types +/// /// This namespace contains typedefs to associate AMQP scalar type names with /// the corresponding C++ types. These are provided as a convenience for those /// familiar with AMQP, you do not need to use them, you can use the C++ types @@ -38,31 +39,31 @@ namespace amqp { ///@name Typedefs for AMQP numeric types. ///@{ -///@ Boolean true or false. + +/// Boolean true or false. typedef bool boolean_type; -///@ 8-bit unsigned byte +/// 8-bit unsigned byte typedef uint8_t ubyte_type; -///@ 8-bit signed byte +/// 8-bit signed byte typedef int8_t byte_type; -///@ 16-bit unsigned short integer +/// 16-bit unsigned short integer typedef uint16_t ushort_type; -///@ 16-bit signed short integer +/// 16-bit signed short integer typedef int16_t short_type; -///@ 32-bit unsigned integer +/// 32-bit unsigned integer typedef uint32_t uint_type; -///@ 32-bit signed integer +/// 32-bit signed integer typedef int32_t int_type; -///@ 64-bit unsigned long integer +/// 64-bit unsigned long integer typedef uint64_t ulong_type; -///@ 64-bit signed long integer +/// 64-bit signed long integer typedef int64_t long_type; -///@ 32-bit unicode code point +/// 32-bit unicode code point typedef wchar_t char_type; -///@ 32-bit binary floating point +/// 32-bit binary floating point typedef float float_type; -///@ 64-bit binary floating point +/// 64-bit binary floating point typedef double double_type; -///@} /// An AMQP string is unicode UTF-8 encoded. typedef std::string string_type; @@ -79,15 +80,14 @@ typedef proton::timestamp timestamp_type; /// A 16-byte universally unique identifier. typedef proton::uuid uuid_type; -///@name AMQP decimal floating point types. -/// -/// These are not usable as arithmetic types in C++. You can pass them on over -/// AMQP or convert the raw bytes using a decimal support library. @see proton::decimal. -/// @{ +/// 32 bit decimal floating point typedef proton::decimal32 decimal32_type; + +/// 64 bit decimal floating point typedef proton::decimal64 decimal64_type; + +/// 128 bit decimal floating point typedef proton::decimal128 decimal128_type; -///@} }} http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/proton-c/bindings/cpp/include/proton/annotation_key.hpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/include/proton/annotation_key.hpp b/proton-c/bindings/cpp/include/proton/annotation_key.hpp index 61b6434..acea44e 100644 --- a/proton-c/bindings/cpp/include/proton/annotation_key.hpp +++ b/proton-c/bindings/cpp/include/proton/annotation_key.hpp @@ -20,7 +20,7 @@ * under the License. */ -#include <proton/scalar.hpp> +#include <proton/scalar_base.hpp> #include <proton/symbol.hpp> namespace proton { @@ -28,39 +28,46 @@ namespace proton { /// A key for use with AMQP annotation maps. /// /// An annotation_key can contain either a uint64_t or a proton::symbol. -class annotation_key : public restricted_scalar { +class annotation_key : public scalar_base { public: + using scalar_base::type; + /// An empty annotation key has a uint64_t == 0 value. - annotation_key() { scalar_ = uint64_t(0); } - annotation_key(const annotation_key& x) { scalar_ = x; } - annotation_key& operator=(const annotation_key& x) { scalar_ = x; return *this; } + annotation_key() { put_(uint64_t(0)); } - annotation_key(uint64_t x) { scalar_ = x; } - annotation_key(const symbol& x) { scalar_ = x; } + /// Construct from any type that can be assigned + template <class T> annotation_key(const T& x) { *this = x; } + ///@name Assign from a uint64_t or symbol. + ///@{ + annotation_key& operator=(uint64_t x) { put_(x); return *this; } + annotation_key& operator=(const symbol& x) { put_(x); return *this; } + ///@} ///@name Extra conversions for strings, treated as amqp::SYMBOL. ///@{ - annotation_key(const std::string& x) { scalar_ = symbol(x); } - annotation_key(const char *x) {scalar_ = symbol(x); } + annotation_key& operator=(const std::string& x) { put_(symbol(x)); return *this; } + annotation_key& operator=(const char *x) { put_(symbol(x)); return *this; } ///@} - annotation_key& operator=(uint64_t x) { scalar_ = x; return *this; } - annotation_key& operator=(const symbol& x) { scalar_ = x; return *this; } - - /// @name Get methods - /// - /// @{ - void get(uint64_t& x) const { scalar_.get(x); } - void get(symbol& x) const { scalar_.get(x); } - /// @} - - /// Return the value as type T. - template<class T> T get() const { T x; get(x); return x; } - + ///@cond INTERNAL friend class message; friend class codec::decoder; + ///@endcond }; +///@cond internal +template <class T> T get(const annotation_key& x); +///@endcond + +/// Get the uint64_t value or throw conversion_error. @related annotation_key +template<> inline uint64_t get<uint64_t>(const annotation_key& x) { return internal::get<uint64_t>(x); } +/// Get the @ref symbol value or throw conversion_error. @related annotation_key +template<> inline symbol get<symbol>(const annotation_key& x) { return internal::get<symbol>(x); } +/// Get the @ref binary value or throw conversion_error. @related annotation_key + +/// @copydoc scalar::coerce +/// @related annotation_key +template<class T> T coerce(const annotation_key& x) { return internal::coerce<T>(x); } } #endif // ANNOTATION_KEY_HPP http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/proton-c/bindings/cpp/include/proton/binary.hpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/include/proton/binary.hpp b/proton-c/bindings/cpp/include/proton/binary.hpp index e907f47..a72ac75 100644 --- a/proton-c/bindings/cpp/include/proton/binary.hpp +++ b/proton-c/bindings/cpp/include/proton/binary.hpp @@ -28,22 +28,24 @@ namespace proton { /// Arbitrary binary data. -class binary : public std::vector<char> { +class binary : public std::vector<uint8_t> { public: - typedef std::vector<char> byte_vector; - - explicit binary() : byte_vector() {} - explicit binary(size_t n) : byte_vector(n) {} - explicit binary(size_t n, char x) : byte_vector(n, x) {} - template <class Iter> binary(Iter first, Iter last) : byte_vector(first, last) {} - explicit binary(const std::string& s) : byte_vector(s.begin(), s.end()) {} - - std::string str() const { return std::string(begin(), end()); } - - binary& operator=(const binary& x) { byte_vector::operator=(x); return *this; } + ///@name Constructors @{ + explicit binary() : std::vector<value_type>() {} + explicit binary(size_t n) : std::vector<value_type>(n) {} + explicit binary(size_t n, value_type x) : std::vector<value_type>(n, x) {} + explicit binary(const std::string& s) : std::vector<value_type>(s.begin(), s.end()) {} + template <class Iter> binary(Iter first, Iter last) : std::vector<value_type>(first, last) {} + ///@} + + /// Convert to std::string + operator std::string() const { return std::string(begin(), end()); } + + /// Assignment binary& operator=(const std::string& x) { assign(x.begin(), x.end()); return *this; } }; +/// Print binary value PN_CPP_EXTERN std::ostream& operator<<(std::ostream&, const binary&); } http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/proton-c/bindings/cpp/include/proton/byte_array.hpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/include/proton/byte_array.hpp b/proton-c/bindings/cpp/include/proton/byte_array.hpp index c2757fa..fe3f864 100644 --- a/proton-c/bindings/cpp/include/proton/byte_array.hpp +++ b/proton-c/bindings/cpp/include/proton/byte_array.hpp @@ -23,6 +23,7 @@ #include <proton/comparable.hpp> #include <algorithm> +#include <iterator> namespace proton { @@ -30,32 +31,51 @@ namespace proton { /// as an array of bytes. template <size_t N> class byte_array : private comparable<byte_array<N> > { public: - typedef char value_type; + ///@name Sequence container typedefs + ///@{ + typedef uint8_t value_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* iterator; + typedef const value_type* const_iterator; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + ///@} - /// Initially all 0. + /// 0-initialized byte array byte_array() { std::fill(bytes_, bytes_+N, '\0'); } - /// Returns N + /// Size of the array static size_t size() { return N; } - uint8_t* begin() { return bytes_; } - uint8_t* end() { return bytes_+N; } - uint8_t& operator[](size_t i) { return bytes_[i]; } + ///@name Array operators + ///@{ + value_type* begin() { return bytes_; } + value_type* end() { return bytes_+N; } + value_type& operator[](size_t i) { return bytes_[i]; } - const uint8_t* begin() const { return bytes_; } - const uint8_t* end() const { return bytes_+N; } - const uint8_t& operator[](size_t i) const { return bytes_[i]; } + const value_type* begin() const { return bytes_; } + const value_type* end() const { return bytes_+N; } + const value_type& operator[](size_t i) const { return bytes_[i]; } + ///@} - friend bool operator==(const byte_array& x, const byte_array& y) { - return std::equal(x.begin(), x.end(), y.begin()); - } + ///@name Comparison operators + ///@{ + friend bool operator==(const byte_array& x, const byte_array& y) { + return std::equal(x.begin(), x.end(), y.begin()); + } - friend bool operator<(const byte_array& x, const byte_array& y) { - return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); - } + friend bool operator<(const byte_array& x, const byte_array& y) { + return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); + } + ///@} private: - uint8_t bytes_[N]; + value_type bytes_[N]; }; } http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/proton-c/bindings/cpp/include/proton/comparable.hpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/include/proton/comparable.hpp b/proton-c/bindings/cpp/include/proton/comparable.hpp index 8bf0e47..cca0e62 100644 --- a/proton-c/bindings/cpp/include/proton/comparable.hpp +++ b/proton-c/bindings/cpp/include/proton/comparable.hpp @@ -22,6 +22,8 @@ namespace proton { +///@cond INTERNAL + /// Base class for comparable types with operator< and /// operator==. Provides remaining operators. template <class T> class comparable { http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/proton-c/bindings/cpp/include/proton/connection_engine.hpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/include/proton/connection_engine.hpp b/proton-c/bindings/cpp/include/proton/connection_engine.hpp index e6946c7..0b1a947 100644 --- a/proton-c/bindings/cpp/include/proton/connection_engine.hpp +++ b/proton-c/bindings/cpp/include/proton/connection_engine.hpp @@ -125,7 +125,7 @@ PN_CPP_CLASS_EXTERN connection_engine { /// Thrown by io_read and io_write functions to indicate an error. struct PN_CPP_CLASS_EXTERN io_error : public error { - PN_CPP_EXTERN explicit io_error(const std::string&); + PN_CPP_EXTERN explicit io_error(const std::string&); ///< Construct with message }; protected: http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/proton-c/bindings/cpp/include/proton/data.hpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/include/proton/data.hpp b/proton-c/bindings/cpp/include/proton/data.hpp index 3d39154..2dadd51 100644 --- a/proton-c/bindings/cpp/include/proton/data.hpp +++ b/proton-c/bindings/cpp/include/proton/data.hpp @@ -24,55 +24,62 @@ #include <proton/types_fwd.hpp> #include <proton/type_id.hpp> +///@file + struct pn_data_t; namespace proton { class value; +///@defgroup codec Internal details of AMQP encoding. +/// +/// You can use these classes on an experimental basis to create your own AMQP +/// encodings for C++ types, but they may change in the future. For examples of use +/// see the built-in encodings, for example in proton/vector.hpp or proton/map.hpp +/// @ingroup codec namespace codec { /// Wrapper for a proton data object. class data : public internal::object<pn_data_t> { public: + /// Wrap an existing proton-C data object. data(pn_data_t* d=0) : internal::object<pn_data_t>(d) {} + /// Create a new data object. PN_CPP_EXTERN static data create(); - // Copy the contents of another data object. + /// Copy the contents of another data object. PN_CPP_EXTERN void copy(const data&); - /** Clear the data. */ + /// Clear the data. PN_CPP_EXTERN void clear(); - /** Rewind current position to the start */ + /// Rewind current position to the start. PN_CPP_EXTERN void rewind(); - /** True if there are no values. */ + /// True if there are no values. PN_CPP_EXTERN bool empty() const; - /** Return the data cursor position */ - PN_CPP_EXTERN void* point() const; - - /** Restore the cursor position to a previously saved position */ - PN_CPP_EXTERN void restore(void* h); - - PN_CPP_EXTERN void narrow(); - - PN_CPP_EXTERN void widen(); - + /// Append the contents of another data object. PN_CPP_EXTERN int append(data src); + /// Append up to limit items from data object. PN_CPP_EXTERN int appendn(data src, int limit); + protected: + PN_CPP_EXTERN void* point() const; + PN_CPP_EXTERN void restore(void* h); + PN_CPP_EXTERN void narrow(); + PN_CPP_EXTERN void widen(); PN_CPP_EXTERN bool next(); - PN_CPP_EXTERN bool prev(); + friend struct state_guard; friend PN_CPP_EXTERN std::ostream& operator<<(std::ostream&, const data&); }; -/// state_guard saves the state and restores it in dtor unless cancel() is called. +// state_guard saves the state and restores it in dtor unless cancel() is called. struct state_guard { data& data_; void* point_; @@ -83,13 +90,6 @@ struct state_guard { void cancel() { cancel_ = true; } }; -/// Narrow the data object, widen it in dtor. -struct narrow_guard { - data& data_; - narrow_guard(data& d) : data_(d) { data_.narrow(); } - ~narrow_guard() { data_.widen(); } -}; - // Start encoding a complex type. struct start { start(type_id type_=NULL_TYPE, type_id element_=NULL_TYPE, @@ -107,10 +107,11 @@ struct start { PN_CPP_EXTERN static start described() { return start(DESCRIBED, NULL_TYPE, true); } }; -/// Finish inserting or extracting a complex type. +// Finish inserting or extracting a complex type. struct finish {}; } // codec + } // proton -#endif // PROTON_DATA_HPP +#endif /*!PROTON_DATA_HPP*/ http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/proton-c/bindings/cpp/include/proton/decimal.hpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/include/proton/decimal.hpp b/proton-c/bindings/cpp/include/proton/decimal.hpp index ddb8ea8..dada944 100644 --- a/proton-c/bindings/cpp/include/proton/decimal.hpp +++ b/proton-c/bindings/cpp/include/proton/decimal.hpp @@ -49,13 +49,16 @@ class decimal64 : public byte_array<8> {}; /// 128-bit decimal floating point. class decimal128 : public byte_array<16> {}; +///@} +/// Print decimal values +///@{ PN_CPP_EXTERN std::ostream& operator<<(std::ostream&, const decimal32&); PN_CPP_EXTERN std::ostream& operator<<(std::ostream&, const decimal64&); PN_CPP_EXTERN std::ostream& operator<<(std::ostream&, const decimal128&); - ///@} + } #endif // DECIMAL_HPP http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/proton-c/bindings/cpp/include/proton/decoder.hpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/include/proton/decoder.hpp b/proton-c/bindings/cpp/include/proton/decoder.hpp index 9a835c0..e6fc78b 100644 --- a/proton-c/bindings/cpp/include/proton/decoder.hpp +++ b/proton-c/bindings/cpp/include/proton/decoder.hpp @@ -20,10 +20,12 @@ */ #include <proton/data.hpp> +#include <proton/types_fwd.hpp> #include <proton/type_traits.hpp> #include <utility> +// Proton namespace namespace proton { class annotation_key; @@ -32,19 +34,23 @@ class scalar; class value; class value_base; +/// @ingroup codec namespace codec { /// Stream-like decoder from AMQP bytes to C++ values. /// -/// Internal use only, see proton::value, proton::scalar and proton::amqp +/// Internal use only, see proton::value, proton::scalar and \ref types /// for the recommended ways to manage AMQP data. class decoder : public data { public: - ///@internal - explicit decoder(const data& d) : data(d) {} + + /// Wrap Proton-C data object. + /// The exact flag if set means decode only when there is an exact match + /// between the AMQP and C++ type. If not set then perform automatic conversions. + explicit decoder(const data& d, bool exact=false) : data(d), exact_(exact) {} /// Attach decoder to a proton::value. The decoder is rewound to the start of the data. - PN_CPP_EXTERN explicit decoder(const value_base&); + PN_CPP_EXTERN explicit decoder(const value_base&, bool exact=false); /// Decode AMQP data from a buffer and add it to the end of the decoders stream. */ PN_CPP_EXTERN void decode(const char* buffer, size_t size); @@ -59,11 +65,9 @@ class decoder : public data { /// @throw conversion_error if no more values. @see decoder::more(). PN_CPP_EXTERN type_id next_type(); - /** @name Extract simple types - * Overloads to extract simple types. - * @throw conversion_error if the decoder is empty or has an incompatible type. - * @{ - */ + /// @name Extract built-in types + /// @throw conversion_error if the decoder is empty or has an incompatible type. + /// @{ PN_CPP_EXTERN decoder& operator>>(bool&); PN_CPP_EXTERN decoder& operator>>(uint8_t&); PN_CPP_EXTERN decoder& operator>>(int8_t&); @@ -96,10 +100,10 @@ class decoder : public data { /// Call finish() to "exit" the container and move on to the next value. PN_CPP_EXTERN decoder& operator>>(start&); - // Finish decoding a container type, and move on to the next value in the stream. + /// Finish decoding a container type, and move on to the next value in the stream. PN_CPP_EXTERN decoder& operator>>(const finish&); - // XXX doc + ///@cond INTERNAL template <class T> struct sequence_ref { T& ref; sequence_ref(T& r) : ref(r) {} }; template <class T> struct associative_ref { T& ref; associative_ref(T& r) : ref(r) {} }; template <class T> struct pair_sequence_ref { T& ref; pair_sequence_ref(T& r) : ref(r) {} }; @@ -107,6 +111,7 @@ class decoder : public data { template <class T> static sequence_ref<T> sequence(T& x) { return sequence_ref<T>(x); } template <class T> static associative_ref<T> associative(T& x) { return associative_ref<T>(x); } template <class T> static pair_sequence_ref<T> pair_sequence(T& x) { return pair_sequence_ref<T>(x); } + ///@endcond /** Extract any AMQP sequence (ARRAY, LIST or MAP) to a C++ sequence * container of T if the elements types are convertible to T. A MAP is @@ -124,6 +129,7 @@ class decoder : public data { /** Extract an AMQP MAP to a C++ associative container */ template <class T> decoder& operator>>(associative_ref<T> r) { + using namespace internal; start s; *this >> s; assert_type_equal(MAP, s.type); @@ -140,6 +146,7 @@ class decoder : public data { /// Extract an AMQP MAP to a C++ push_back sequence of pairs /// preserving encoded order. template <class T> decoder& operator>>(pair_sequence_ref<T> r) { + using namespace internal; start s; *this >> s; assert_type_equal(MAP, s.type); @@ -154,30 +161,32 @@ class decoder : public data { return *this; } - /// Extract and return a value. - template <class T> T extract() { T x; *this >> x; return x; } - private: type_id pre_get(); template <class T, class U> decoder& extract(T& x, U (*get)(pn_data_t*)); + bool exact_; friend class message; }; +template<class T> T get(decoder& d) { + assert_type_equal(internal::type_id_of<T>::value, d.next_type()); + T x; + d >> x; + return x; +} + // operator >> for integer types that are not covered by the standard overrides. -template <class T> typename codec::enable_unknown_integer<T, decoder&>::type +template <class T> typename internal::enable_if<internal::is_unknown_integer<T>::value, decoder&>::type operator>>(decoder& d, T& i) { + using namespace internal; typename integer_type<sizeof(T), is_signed<T>::value>::type v; d >> v; // Extract as a known integer type i = v; // C++ conversion to the target type. return d; } -///@cond INTERNAL - -} // internal +} // codec } // proton -/// @endcond - #endif // PROTON_DECODER_HPP http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/proton-c/bindings/cpp/include/proton/deque.hpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/include/proton/deque.hpp b/proton-c/bindings/cpp/include/proton/deque.hpp index 18d142d..7d0b278 100644 --- a/proton-c/bindings/cpp/include/proton/deque.hpp +++ b/proton-c/bindings/cpp/include/proton/deque.hpp @@ -31,7 +31,7 @@ namespace codec { /// std::deque<T> for most T is encoded as an amqp::ARRAY (same type elements) template <class T, class A> encoder& operator<<(encoder& e, const std::deque<T, A>& x) { - return e << encoder::array(x, type_id_of<T>::value); + return e << encoder::array(x, internal::type_id_of<T>::value); } /// std::deque<value> encodes as amqp::LIST (mixed type elements) http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/proton-c/bindings/cpp/include/proton/duration.hpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/include/proton/duration.hpp b/proton-c/bindings/cpp/include/proton/duration.hpp index 51f7a46..9d41d2d 100644 --- a/proton-c/bindings/cpp/include/proton/duration.hpp +++ b/proton-c/bindings/cpp/include/proton/duration.hpp @@ -33,11 +33,13 @@ namespace proton { /// A span of time in milliseconds. class duration : private comparable<duration> { public: - typedef uint64_t numeric_type; - explicit duration(numeric_type ms = 0) : ms_(ms) {} - duration& operator=(numeric_type ms) { ms_ = ms; return *this; } - numeric_type milliseconds() const { return ms_; } - numeric_type ms() const { return ms_; } + typedef uint64_t numeric_type; ///< Numeric type used to store milliseconds + + explicit duration(numeric_type ms = 0) : ms_(ms) {} ///< Construct from milliseconds + duration& operator=(numeric_type ms) { ms_ = ms; return *this; } ///< Assign + + numeric_type milliseconds() const { return ms_; } ///< Return milliseconds + numeric_type ms() const { return ms_; } ///< Return milliseconds PN_CPP_EXTERN static const duration FOREVER; ///< Wait for ever PN_CPP_EXTERN static const duration IMMEDIATE; ///< Don't wait at all @@ -48,8 +50,11 @@ class duration : private comparable<duration> { numeric_type ms_; }; +/// Print duration PN_CPP_EXTERN std::ostream& operator<<(std::ostream&, duration); +///@name Comparison and arithmetic operators +///@{ inline bool operator<(duration x, duration y) { return x.ms() < y.ms(); } inline bool operator==(duration x, duration y) { return x.ms() == y.ms(); } @@ -57,7 +62,7 @@ inline duration operator+(duration x, duration y) { return duration(x.ms() + y.m inline duration operator-(duration x, duration y) { return duration(x.ms() - y.ms()); } inline duration operator*(duration d, uint64_t n) { return duration(d.ms()*n); } inline duration operator*(uint64_t n, duration d) { return d * n; } - +///@} } #endif // PROTON_CPP_DURATION_H http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/proton-c/bindings/cpp/include/proton/encoder.hpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/include/proton/encoder.hpp b/proton-c/bindings/cpp/include/proton/encoder.hpp index c76c9ce..b9d4461 100644 --- a/proton-c/bindings/cpp/include/proton/encoder.hpp +++ b/proton-c/bindings/cpp/include/proton/encoder.hpp @@ -1,5 +1,5 @@ -#ifndef ENCODER_H -#define ENCODER_H +#ifndef PROTON_ENCODER_HPP +#define PROTON_ENCODER_HPP /* * Licensed to the Apache Software Foundation (ASF) under one @@ -21,23 +21,24 @@ */ #include <proton/data.hpp> +#include <proton/types_fwd.hpp> #include <proton/type_traits.hpp> namespace proton { -class scalar; -class value; +class scalar_base; class value_base; +/// @ingroup codec namespace codec { /// Stream-like encoder from AMQP bytes to C++ values. /// -/// Internal use only, see proton::value, proton::scalar and proton::amqp +/// Internal use only, see proton::value, proton::scalar and \ref types /// for the recommended ways to manage AMQP data. class encoder : public data { public: - ///@internal + /// Wrap Proton-C data object. explicit encoder(const data& d) : data(d) {} /// Encoder into v. Clears any current value in v. @@ -63,6 +64,8 @@ class encoder : public data { /** Encode the current values into a std::string. Clears the encoder. */ PN_CPP_EXTERN std::string encode(); + /// @name Insert built-in types + /// @{ PN_CPP_EXTERN encoder& operator<<(bool); PN_CPP_EXTERN encoder& operator<<(uint8_t); PN_CPP_EXTERN encoder& operator<<(int8_t); @@ -83,17 +86,24 @@ class encoder : public data { PN_CPP_EXTERN encoder& operator<<(const std::string&); PN_CPP_EXTERN encoder& operator<<(const symbol&); PN_CPP_EXTERN encoder& operator<<(const binary&); - PN_CPP_EXTERN encoder& operator<<(const scalar&); + PN_CPP_EXTERN encoder& operator<<(const scalar_base&); PN_CPP_EXTERN encoder& operator<<(const null&); + ///@} - /// Inserts proton::value. + /// Insert a proton::value. + /// @internal NOTE insert value_base, not value to avoid recursive implicit conversions. PN_CPP_EXTERN encoder& operator<<(const value_base&); + /// Start a complex type PN_CPP_EXTERN encoder& operator<<(const start&); /// Finish a complex type PN_CPP_EXTERN encoder& operator<<(const finish&); - // XXX doc + ///@cond INTERNAL + + // Undefined template to prevent pointers being implicitly converted to bool. + template <class T> void* operator<<(const T*); + template <class T> struct list_cref { T& ref; list_cref(T& r) : ref(r) {} }; template <class T> struct map_cref { T& ref; map_cref(T& r) : ref(r) {} }; @@ -135,26 +145,47 @@ class encoder : public data { *this << finish(); return *this; } + ///@endcond private: template<class T, class U> encoder& insert(const T& x, int (*put)(pn_data_t*, U)); void check(long result); }; -///@internal -/// Invalid template to prevent pointers being implicitly converted to bool. -template <class T> void* operator<<(encoder&, const T*); -// Treat char* as string +/// Treat char* as string inline encoder& operator<<(encoder& e, const char* s) { return e << std::string(s); } -// operator << for integer types that are not covered by the standard overrides. -template <class T> typename codec::enable_unknown_integer<T, encoder&>::type +/// operator << for integer types that are not covered by the standard overrides. +template <class T> typename internal::enable_if<internal::is_unknown_integer<T>::value, encoder&>::type operator<<(encoder& e, T i) { + using namespace internal; return e << static_cast<typename integer_type<sizeof(T), is_signed<T>::value>::type>(i); } -} // internal +///@cond INTERNAL +namespace is_encodable_impl { // Protected the world from wildcard operator<< + +using namespace internal; + +sfinae::no operator<<(sfinae::wildcard, sfinae::wildcard); // Fallback + +template<typename T> struct is_encodable : public sfinae { + static yes test(encoder); + static no test(...); // Failed test, no match. + static encoder &e; + static const T& t; + static bool const value = sizeof(test(e << t)) == sizeof(yes); +}; +// Avoid recursion +template <> struct is_encodable<value> : public true_type {}; + +} // namespace is_encodable_impl + +using is_encodable_impl::is_encodable; +///@endcond + +} // codec } // proton -#endif // ENCODER_H +#endif /*!PROTON_ENCODER_HPP*/ http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/d70dab5d/proton-c/bindings/cpp/include/proton/endpoint.hpp ---------------------------------------------------------------------- diff --git a/proton-c/bindings/cpp/include/proton/endpoint.hpp b/proton-c/bindings/cpp/include/proton/endpoint.hpp index 705ce7d..d59e093 100644 --- a/proton-c/bindings/cpp/include/proton/endpoint.hpp +++ b/proton-c/bindings/cpp/include/proton/endpoint.hpp @@ -75,6 +75,7 @@ PN_CPP_CLASS_EXTERN endpoint { #endif }; +///@cond INTERNAL namespace internal { template <class T, class D> class iter_base { @@ -86,7 +87,7 @@ template <class T, class D> class iter_base { D operator++(int) { D x(*this); ++(*this); return x; } bool operator==(const iter_base<T, D>& x) const { return obj_ == x.obj_; } bool operator!=(const iter_base<T, D>& x) const { return obj_ != x.obj_; } - + ///@} protected: explicit iter_base(T p = 0) : obj_(p) {} T obj_; @@ -105,6 +106,8 @@ template<class I> class iter_range { }; } // namespace internal +///@endcond + } // namespace proton #endif // PROTON_CPP_H --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
