You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ac...@apache.org on 2015/11/10 23:43:51 UTC

[1/3] qpid-proton git commit: NO-JIRA: c++: Speed up recurring_timer example.

Repository: qpid-proton
Updated Branches:
  refs/heads/master 1b1b2e596 -> 01e136cc6


NO-JIRA: c++: Speed up recurring_timer example.


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/b131dc19
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/b131dc19
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/b131dc19

Branch: refs/heads/master
Commit: b131dc199f7f2c69a14587e45b6feaf741b53610
Parents: 1b1b2e5
Author: Alan Conway <ac...@redhat.com>
Authored: Thu Nov 5 10:22:49 2015 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Tue Nov 10 17:06:27 2015 -0500

----------------------------------------------------------------------
 examples/cpp/CMakeLists.txt      |  2 +-
 examples/cpp/example_test.py     | 17 ++++++++++++++---
 examples/cpp/recurring_timer.cpp | 29 ++++++++++++++---------------
 3 files changed, 29 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b131dc19/examples/cpp/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/examples/cpp/CMakeLists.txt b/examples/cpp/CMakeLists.txt
index 3e5dafe..8916963 100644
--- a/examples/cpp/CMakeLists.txt
+++ b/examples/cpp/CMakeLists.txt
@@ -60,7 +60,7 @@ else(WIN32)
 endif(WIN32)
 
 add_test(NAME cpp_example_test
-  COMMAND ${PYTHON_EXECUTABLE} ${env_py} -- "PATH=${test_path}" "PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR}" ${VALGRIND_ENV} ${PYTHON_EXECUTABLE} -m unittest -v example_test)
+  COMMAND ${PYTHON_EXECUTABLE} ${env_py} -- "PATH=${test_path}" ${VALGRIND_ENV} ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/example_test.py -v)
 
 set(broker_tests example_test.ExampleTest.test_request_response example_test.ExampleTest.test_simple_send_recv)
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b131dc19/examples/cpp/example_test.py
----------------------------------------------------------------------
diff --git a/examples/cpp/example_test.py b/examples/cpp/example_test.py
index 3ed8b9c..f51cf57 100644
--- a/examples/cpp/example_test.py
+++ b/examples/cpp/example_test.py
@@ -23,6 +23,7 @@ import unittest
 import os, sys, socket, time
 from  random import randrange
 from subprocess import Popen, PIPE, STDOUT
+from copy import copy
 import platform
 
 def cmdline(*args):
@@ -215,14 +216,24 @@ Values: map{string(k1):int(42), symbol(k2):boolean(false)}
         self.assertEqual(expect, execute("encode_decode"))
 
     def test_recurring_timer(self):
-        expect="""Tick...
+        # Disable valgrind, this test is time-sensitive.
+        env = {k: v for k,v in os.environ.iteritems() if k != "VALGRIND"}
+        env, os.environ = os.environ, env
+        try:
+            expect="""Tick...
+Tick...
+Tock...
+Tick...
+Tock...
 Tick...
 Tock...
 Tick...
 Tock...
 """
-        self.maxDiff = None
-        self.assertEqual(expect, execute("recurring_timer", "-t", "3"))
+            self.maxDiff = None
+            self.assertEqual(expect, execute("recurring_timer", "-t", ".01", "-k", ".001"))
+        finally:
+            os.environ = env    # Restore environment
 
 if __name__ == "__main__":
     unittest.main()

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b131dc19/examples/cpp/recurring_timer.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/recurring_timer.cpp b/examples/cpp/recurring_timer.cpp
index b6141fd..37cbfed 100644
--- a/examples/cpp/recurring_timer.cpp
+++ b/examples/cpp/recurring_timer.cpp
@@ -43,53 +43,52 @@ class tocker : public proton::messaging_handler {
 
 class recurring : public proton::messaging_handler {
   private:
-    int remaining_secs;
+    int remaining_msecs, tick_ms;
     ticker tick_handler;
     tocker tock_handler;
     proton::task *cancel_task;
   public:
 
-    recurring(int secs) : remaining_secs(secs), cancel_task(0) {}
+    recurring(int msecs, int tickms) : remaining_msecs(msecs), tick_ms(tickms), cancel_task(0) {}
 
     proton::task& ticktock(proton::event &e) {
         // Show timer events in separate handlers.
-        e.container().schedule(250, &tick_handler);
-        return e.container().schedule(750, &tock_handler);
+        e.container().schedule(tick_ms, &tick_handler);
+        return e.container().schedule(tick_ms * 3, &tock_handler);
     }
 
     void on_start(proton::event &e) {
-        if (remaining_secs <= 0)
+        if (remaining_msecs <= 0)
             return;
         proton::task& first_tock = ticktock(e);
-        e.container().schedule(1000);
-        remaining_secs--;
         // Show a cancel operation.
         cancel_task = &first_tock;
-        e.container().schedule(500);
+        e.container().schedule(tick_ms);
     }
 
     void on_timer_task(proton::event &e) {
         if (cancel_task) {
             cancel_task->cancel();
             cancel_task = 0;
-            return;
         }
-        if (remaining_secs) {
+        remaining_msecs -= tick_ms * 2;
+        if (remaining_msecs > 0) {
             ticktock(e);
-            e.container().schedule(1000);
-            remaining_secs--;
+            e.container().schedule(tick_ms * 4);
         }
     }
 };
 
 int main(int argc, char **argv) {
     // Command line options
-    int running_time_in_secs = 5;
+    double running_time = 5;
+    double tick = 0.25;
     options opts(argc, argv);
-    opts.add_value(running_time_in_secs, 't', "running time", "running time in seconds", "RUNTIME");
+    opts.add_value(running_time, 't', "running time", "running time in seconds", "RUNTIME");
+    opts.add_value(tick, 'k', "tick time", "tick time as fraction of second", "TICK");
     try {
         opts.parse();
-        recurring recurring_handler(running_time_in_secs);
+        recurring recurring_handler(running_time * 1000, tick * 1000);
         proton::container(recurring_handler).run();
         return 0;
     } catch (const bad_option& e) {


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[2/3] qpid-proton git commit: NO-JIRA: Removed dead code container.h

Posted by ac...@apache.org.
NO-JIRA: Removed dead code container.h

Contained only a typedef which is not referred to anywhere, no functions, and
was missing the close brace on 'extern "C" {' which implies it has never
actually been included anywhere or the windows C++ build would have failed.


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/ecbe90a2
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/ecbe90a2
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/ecbe90a2

Branch: refs/heads/master
Commit: ecbe90a2fe28adec97093037df7da27cc9e519d8
Parents: b131dc1
Author: Alan Conway <ac...@redhat.com>
Authored: Wed Nov 4 15:41:46 2015 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Tue Nov 10 17:07:24 2015 -0500

----------------------------------------------------------------------
 proton-c/CMakeLists.txt             |  1 -
 proton-c/include/proton/container.h | 50 --------------------------------
 2 files changed, 51 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ecbe90a2/proton-c/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/proton-c/CMakeLists.txt b/proton-c/CMakeLists.txt
index 6a35170..d80d60a 100644
--- a/proton-c/CMakeLists.txt
+++ b/proton-c/CMakeLists.txt
@@ -344,7 +344,6 @@ set (qpid-proton-include
   include/proton/codec.h
   include/proton/condition.h
   include/proton/connection.h
-  include/proton/container.h
   include/proton/delivery.h
   include/proton/disposition.h
   include/proton/engine.h

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/ecbe90a2/proton-c/include/proton/container.h
----------------------------------------------------------------------
diff --git a/proton-c/include/proton/container.h b/proton-c/include/proton/container.h
deleted file mode 100644
index a1de525..0000000
--- a/proton-c/include/proton/container.h
+++ /dev/null
@@ -1,50 +0,0 @@
-#ifndef PROTON_CONTAINER_H
-#define PROTON_CONTAINER_H 1
-
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-#include <proton/import_export.h>
-#include <proton/type_compat.h>
-#include <stddef.h>
-#include <sys/types.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/** @file
- * Container API for the proton Engine.
- *
- * @defgroup container Container
- * @ingroup engine
- * @{
- */
-
-/**
- * Encapsulates the endpoint state associated with an AMQP Container.
- */
-typedef struct pn_container_t pn_container_t;
-
-/** @}
- */
-
-#endif /* container.h */


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


Re: [1/3] qpid-proton git commit: NO-JIRA: c++: Speed up recurring_timer example.

Posted by Chuck Rolke <cr...@redhat.com>.
This commit seems a bit heavy to be NO-JIRA as it breaks my windows builds several ways.

Compile error:
=============
fixed

Syntax error:
============
Python 2.6.1 complains about:

13:   File "C:/Jenkins/workspace/proton-c-master-windows/examples/cpp/example_test.py", line 228
13:     env = {k: v for k,v in os.environ.iteritems() if k != "VALGRIND"}
13:                   ^

Python 2.7.1 is fine with this. 2.6 works with simpler iteration constructs.

Self test fail:
==============
The test_recurring_time (on my single try) fails with an extra "Tock..." after the first "Tick...".

-Chuck


----- Original Message -----
> From: aconway@apache.org
> To: commits@qpid.apache.org
> Sent: Tuesday, November 10, 2015 5:43:51 PM
> Subject: [1/3] qpid-proton git commit: NO-JIRA: c++: Speed up recurring_timer example.
> 
> Repository: qpid-proton
> Updated Branches:
>   refs/heads/master 1b1b2e596 -> 01e136cc6
> 
> 
> NO-JIRA: c++: Speed up recurring_timer example.
> 
> 
> Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
> Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/b131dc19
> Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/b131dc19
> Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/b131dc19
> 
> Branch: refs/heads/master
> Commit: b131dc199f7f2c69a14587e45b6feaf741b53610
> Parents: 1b1b2e5
> Author: Alan Conway <ac...@redhat.com>
> Authored: Thu Nov 5 10:22:49 2015 -0500
> Committer: Alan Conway <ac...@redhat.com>
> Committed: Tue Nov 10 17:06:27 2015 -0500
> 
> ----------------------------------------------------------------------
>  examples/cpp/CMakeLists.txt      |  2 +-
>  examples/cpp/example_test.py     | 17 ++++++++++++++---
>  examples/cpp/recurring_timer.cpp | 29 ++++++++++++++---------------
>  3 files changed, 29 insertions(+), 19 deletions(-)
> ----------------------------------------------------------------------
> 
> 
> http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b131dc19/examples/cpp/CMakeLists.txt
> ----------------------------------------------------------------------
> diff --git a/examples/cpp/CMakeLists.txt b/examples/cpp/CMakeLists.txt
> index 3e5dafe..8916963 100644
> --- a/examples/cpp/CMakeLists.txt
> +++ b/examples/cpp/CMakeLists.txt
> @@ -60,7 +60,7 @@ else(WIN32)
>  endif(WIN32)
>  
>  add_test(NAME cpp_example_test
> -  COMMAND ${PYTHON_EXECUTABLE} ${env_py} -- "PATH=${test_path}"
> "PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR}" ${VALGRIND_ENV}
> ${PYTHON_EXECUTABLE} -m unittest -v example_test)
> +  COMMAND ${PYTHON_EXECUTABLE} ${env_py} -- "PATH=${test_path}"
> ${VALGRIND_ENV} ${PYTHON_EXECUTABLE}
> ${CMAKE_CURRENT_SOURCE_DIR}/example_test.py -v)
>  
>  set(broker_tests example_test.ExampleTest.test_request_response
>  example_test.ExampleTest.test_simple_send_recv)
>  
> 
> http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b131dc19/examples/cpp/example_test.py
> ----------------------------------------------------------------------
> diff --git a/examples/cpp/example_test.py b/examples/cpp/example_test.py
> index 3ed8b9c..f51cf57 100644
> --- a/examples/cpp/example_test.py
> +++ b/examples/cpp/example_test.py
> @@ -23,6 +23,7 @@ import unittest
>  import os, sys, socket, time
>  from  random import randrange
>  from subprocess import Popen, PIPE, STDOUT
> +from copy import copy
>  import platform
>  
>  def cmdline(*args):
> @@ -215,14 +216,24 @@ Values: map{string(k1):int(42),
> symbol(k2):boolean(false)}
>          self.assertEqual(expect, execute("encode_decode"))
>  
>      def test_recurring_timer(self):
> -        expect="""Tick...
> +        # Disable valgrind, this test is time-sensitive.
> +        env = {k: v for k,v in os.environ.iteritems() if k != "VALGRIND"}
> +        env, os.environ = os.environ, env
> +        try:
> +            expect="""Tick...
> +Tick...
> +Tock...
> +Tick...
> +Tock...
>  Tick...
>  Tock...
>  Tick...
>  Tock...
>  """
> -        self.maxDiff = None
> -        self.assertEqual(expect, execute("recurring_timer", "-t", "3"))
> +            self.maxDiff = None
> +            self.assertEqual(expect, execute("recurring_timer", "-t", ".01",
> "-k", ".001"))
> +        finally:
> +            os.environ = env    # Restore environment
>  
>  if __name__ == "__main__":
>      unittest.main()
> 
> http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/b131dc19/examples/cpp/recurring_timer.cpp
> ----------------------------------------------------------------------
> diff --git a/examples/cpp/recurring_timer.cpp
> b/examples/cpp/recurring_timer.cpp
> index b6141fd..37cbfed 100644
> --- a/examples/cpp/recurring_timer.cpp
> +++ b/examples/cpp/recurring_timer.cpp
> @@ -43,53 +43,52 @@ class tocker : public proton::messaging_handler {
>  
>  class recurring : public proton::messaging_handler {
>    private:
> -    int remaining_secs;
> +    int remaining_msecs, tick_ms;
>      ticker tick_handler;
>      tocker tock_handler;
>      proton::task *cancel_task;
>    public:
>  
> -    recurring(int secs) : remaining_secs(secs), cancel_task(0) {}
> +    recurring(int msecs, int tickms) : remaining_msecs(msecs),
> tick_ms(tickms), cancel_task(0) {}
>  
>      proton::task& ticktock(proton::event &e) {
>          // Show timer events in separate handlers.
> -        e.container().schedule(250, &tick_handler);
> -        return e.container().schedule(750, &tock_handler);
> +        e.container().schedule(tick_ms, &tick_handler);
> +        return e.container().schedule(tick_ms * 3, &tock_handler);
>      }
>  
>      void on_start(proton::event &e) {
> -        if (remaining_secs <= 0)
> +        if (remaining_msecs <= 0)
>              return;
>          proton::task& first_tock = ticktock(e);
> -        e.container().schedule(1000);
> -        remaining_secs--;
>          // Show a cancel operation.
>          cancel_task = &first_tock;
> -        e.container().schedule(500);
> +        e.container().schedule(tick_ms);
>      }
>  
>      void on_timer_task(proton::event &e) {
>          if (cancel_task) {
>              cancel_task->cancel();
>              cancel_task = 0;
> -            return;
>          }
> -        if (remaining_secs) {
> +        remaining_msecs -= tick_ms * 2;
> +        if (remaining_msecs > 0) {
>              ticktock(e);
> -            e.container().schedule(1000);
> -            remaining_secs--;
> +            e.container().schedule(tick_ms * 4);
>          }
>      }
>  };
>  
>  int main(int argc, char **argv) {
>      // Command line options
> -    int running_time_in_secs = 5;
> +    double running_time = 5;
> +    double tick = 0.25;
>      options opts(argc, argv);
> -    opts.add_value(running_time_in_secs, 't', "running time", "running time
> in seconds", "RUNTIME");
> +    opts.add_value(running_time, 't', "running time", "running time in
> seconds", "RUNTIME");
> +    opts.add_value(tick, 'k', "tick time", "tick time as fraction of
> second", "TICK");
>      try {
>          opts.parse();
> -        recurring recurring_handler(running_time_in_secs);
> +        recurring recurring_handler(running_time * 1000, tick * 1000);
>          proton::container(recurring_handler).run();
>          return 0;
>      } catch (const bad_option& e) {
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
> For additional commands, e-mail: commits-help@qpid.apache.org
> 
> 

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@qpid.apache.org
For additional commands, e-mail: dev-help@qpid.apache.org


[3/3] qpid-proton git commit: NO-JIRA: C++: Conversions for complex types

Posted by ac...@apache.org.
NO-JIRA: C++: Conversions for complex types

Intuitive automatic conversions between standard C++ containers and  AMQP types.
User can override for non-standard containers or non-default use of standard containers.

Examples in encode_decode.cpp.


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/01e136cc
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/01e136cc
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/01e136cc

Branch: refs/heads/master
Commit: 01e136cc660a721da9178a98ff43bac143a4c8ce
Parents: ecbe90a
Author: Alan Conway <ac...@redhat.com>
Authored: Thu Nov 5 09:43:45 2015 -0500
Committer: Alan Conway <ac...@redhat.com>
Committed: Tue Nov 10 17:32:40 2015 -0500

----------------------------------------------------------------------
 examples/cpp/direct_send.cpp                    |   2 +-
 examples/cpp/encode_decode.cpp                  | 159 +++++-----
 examples/cpp/example_test.py                    |  24 +-
 examples/cpp/simple_send.cpp                    |   2 +-
 .../bindings/cpp/include/proton/decoder.hpp     | 287 +++++++++++++++----
 .../bindings/cpp/include/proton/encoder.hpp     | 103 +++++--
 proton-c/bindings/cpp/include/proton/engine.hpp |   2 +-
 .../bindings/cpp/include/proton/message.hpp     |  18 +-
 .../bindings/cpp/include/proton/message_id.hpp  |   3 +-
 .../cpp/include/proton/request_response.hpp     |   3 -
 .../bindings/cpp/include/proton/type_traits.hpp |  19 +-
 proton-c/bindings/cpp/include/proton/types.hpp  |  43 +--
 proton-c/bindings/cpp/include/proton/value.hpp  |  32 ++-
 proton-c/bindings/cpp/src/decoder.cpp           |  23 +-
 proton-c/bindings/cpp/src/encoder.cpp           |   8 +-
 proton-c/bindings/cpp/src/interop_test.cpp      |   6 +-
 proton-c/bindings/cpp/src/message.cpp           |   2 +-
 proton-c/bindings/cpp/src/value.cpp             |  16 +-
 18 files changed, 501 insertions(+), 251 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/01e136cc/examples/cpp/direct_send.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/direct_send.cpp b/examples/cpp/direct_send.cpp
index 62e6ab9..13ca510 100644
--- a/examples/cpp/direct_send.cpp
+++ b/examples/cpp/direct_send.cpp
@@ -53,7 +53,7 @@ class simple_send : public proton::messaging_handler {
             msg.id(sent + 1);
             std::map<std::string, int> m;
             m["sequence"] = sent+1;
-            msg.body(proton::as<proton::MAP>(m));
+            msg.body(m);
             sender.send(msg);
             sent++;
         }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/01e136cc/examples/cpp/encode_decode.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/encode_decode.cpp b/examples/cpp/encode_decode.cpp
index 4f88c93..3d6fe48 100644
--- a/examples/cpp/encode_decode.cpp
+++ b/examples/cpp/encode_decode.cpp
@@ -24,8 +24,8 @@
 #include <map>
 #include <sstream>
 #include <vector>
+#include <list>
 
-using namespace std;
 
 // Examples of how to use the encoder and decoder to create and examine AMQP values.
 //
@@ -34,12 +34,18 @@ using namespace std;
 // values from a decoder in terms of their simple components.
 void print(proton::value&);
 
-// Some helper templates to print map and vector results.
+// Some helper templates to print map and std::vector results.
 namespace std {
-template<class T, class U> ostream& operator<<(ostream& o, const pair<T,U>& p) {
+template<class T, class U> ostream& operator<<(ostream& o, const std::pair<T,U>& p) {
     return o << p.first << ":" << p.second;
 }
-template<class T> ostream& operator<<(ostream& o, const vector<T>& v) {
+template<class T> ostream& operator<<(ostream& o, const std::vector<T>& v) {
+    o << "[ ";
+    ostream_iterator<T> oi(o, " ");
+    copy(v.begin(), v.end(), oi);
+    return o << "]";
+}
+template<class T> ostream& operator<<(ostream& o, const std::list<T>& v) {
     o << "[ ";
     ostream_iterator<T> oi(o, " ");
     copy(v.begin(), v.end(), oi);
@@ -47,85 +53,109 @@ template<class T> ostream& operator<<(ostream& o, const vector<T>& v) {
 }
 template<class K, class T> ostream& operator<<(ostream& o, const map<K, T>& m) {
     o << "{ ";
-    ostream_iterator<pair<K,T> > oi(o, " ");
+    ostream_iterator<std::pair<K,T> > oi(o, " ");
     copy(m.begin(), m.end(), oi);
     return o << "}";
 }
 }
 
-// Insert/extract C++ containers.
-void insert_extract_containers() {
-    cout << endl << "== Array, list and map." << endl;
+// Insert/extract native C++ containers with uniform type values.
+void uniform_containers() {
+    std::cout << std::endl << "== Array, list and map of uniform type." << std::endl;
+    proton::value v;
 
-    vector<int> a;
+    std::vector<int> a;
     a.push_back(1);
     a.push_back(2);
     a.push_back(3);
-    vector<int> l;
-    l.push_back(4);
-    l.push_back(5);
-    map<string, int> m;
-    m["one"] = 1;
-    m["two"] = 2;
+    // By default a C++ container is encoded as an AMQP array.
+    v = a;
+    print(v);
+    std::list<int> a1 = v;          // Decode as a C++ std::list instead
+    std::cout << a1 << std::endl;
 
-    proton::value v;
-    v.encoder() << proton::as<proton::ARRAY>(a) << proton::as<proton::LIST>(l) << proton::as<proton::MAP>(m);
+    // You can specify that a container should be encoded as an AMQP list instead.
+    v = proton::as<proton::LIST>(a1);
     print(v);
+    std::cout << v.get<std::vector<int> >() << std::endl;
 
-    vector<int> a1, l1;
-    map<string, int> m1;
-    v.decoder().rewind();
-    v.decoder() >> proton::as<proton::ARRAY>(a1) >> proton::as<proton::LIST>(l1) >> proton::as<proton::MAP>(m1);
-    cout << "Extracted: " << a1 << ", " << l1 << ", " << m1 << endl;
+    // C++ map types (types with key_type, mapped_type) convert to an AMQP map by default.
+    std::map<std::string, int> m;
+    m["one"] = 1;
+    m["two"] = 2;
+    v = m;
+    print(v);
+    std::cout << v.get<std::map<std::string, int> >() << std::endl;
+
+    // You can convert a sequence of pairs to an AMQP map if you need to control the
+    // encoded ordering.
+    std::vector<std::pair<std::string, int> > pairs;
+    pairs.push_back(std::make_pair("z", 3));
+    pairs.push_back(std::make_pair("a", 4));
+    v = proton::as<proton::MAP>(pairs);
+    print(v);
+    // You can also decode an AMQP map as a sequence of pairs using decoder() and proton::to_pairs
+    std::vector<std::pair<std::string, int> > pairs2;
+    v.decoder() >> proton::to_pairs(pairs2);
+    std::cout << pairs2 << std::endl;
 }
 
-// Containers with mixed types, use value to represent arbitrary AMQP types.
+// Containers with mixed types use value to represent arbitrary AMQP types.
 void mixed_containers() {
-    cout << endl << "== List and map of mixed type values." << endl;
-    vector<proton::value> l;
+    std::cout << std::endl << "== List and map of mixed type values." << std::endl;
+    proton::value v;
+
+    std::vector<proton::value> l;
     l.push_back(proton::value(42));
     l.push_back(proton::value(proton::amqp_string("foo")));
-    map<proton::value, proton::value> m;
+    // By default, a sequence of proton::value is treated as an AMQP list.
+    v = l;
+    print(v);
+    std::vector<proton::value> l2 = 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");
-    proton::value v;
-    v.encoder() << proton::as<proton::LIST>(l) << proton::as<proton::MAP>(m);
+    v = m;
     print(v);
-
-    vector<proton::value> l1;
-    map<proton::value, proton::value> m1;
-    v.decoder().rewind();
-    v.decoder() >> proton::as<proton::LIST>(l1) >> proton::as<proton::MAP>(m1);
-    cout << "Extracted: " << l1 << ", " << m1 << endl;
+    std::map<proton::value, proton::value> m2 = v;
+    std::cout << m2 << std::endl;
 }
 
 // Insert using stream operators (see print_next for example of extracting with stream ops.)
-void insert_extract_stream_operators() {
-    cout << endl << "== Insert with stream operators." << endl;
+void insert_stream_operators() {
+    std::cout << std::endl << "== Insert with stream operators." << std::endl;
     proton::value v;
-    // Note: array elements must be encoded with the exact type, they are not
-    // automaticlly converted. Mismatched types for array elements will not
-    // be detected until v.encode() is called.
-    v.encoder() << proton::start::array(proton::INT) << proton::amqp_int(1) << proton::amqp_int(2) << proton::amqp_int(3) << proton::finish();
+
+    // Create an array of INT with values [1, 2, 3]
+    v.encoder() << proton::start::array(proton::INT)
+                << proton::amqp_int(1) << proton::amqp_int(2) << proton::amqp_int(3)
+                << proton::finish();
     print(v);
 
-    v.clear();
-    v.encoder() << proton::start::list() << proton::amqp_int(42) << false << proton::amqp_symbol("x") << proton::finish();
+    // Create a mixed-type list of the values [42, false, "x"].
+    v.encoder() << proton::start::list()
+                << proton::amqp_int(42) << false << proton::amqp_symbol("x")
+                << proton::finish();
     print(v);
 
-    v.clear();
-    v.encoder() << proton::start::map() << "k1" << proton::amqp_int(42) << proton::amqp_symbol("k2") << false << proton::finish();
+    // Create a map { "k1":42, "k2": false }
+    v.encoder() << proton::start::map()
+                << "k1" << proton::amqp_int(42)
+                << proton::amqp_symbol("k2") << false
+                << proton::finish();
     print(v);
 }
 
 int main(int, char**) {
     try {
-        insert_extract_containers();
+        uniform_containers();
         mixed_containers();
-        insert_extract_stream_operators();
+        insert_stream_operators();
         return 0;
-    } catch (const exception& e) {
-        cerr << endl << "error: " << e.what() << endl;
+    } catch (const std::exception& e) {
+        std::cerr << std::endl << "error: " << e.what() << std::endl;
     }
     return 1;
 }
@@ -141,47 +171,47 @@ void print_next(proton::decoder& d) {
     switch (type) {
       case proton::ARRAY: {
           d >> s;
-          cout << "array<" << s.element;
+          std::cout << "array<" << s.element;
           if (s.is_described) {
-              cout  << ", descriptor=";
+              std::cout  << ", descriptor=";
               print_next(d);
           }
-          cout << ">[";
+          std::cout << ">[";
           for (size_t i = 0; i < s.size; ++i) {
-              if (i) cout << ", ";
+              if (i) std::cout << ", ";
               print_next(d);
           }
-          cout << "]";
+          std::cout << "]";
           d >> proton::finish();
           break;
       }
       case proton::LIST: {
           d >> s;
-          cout << "list[";
+          std::cout << "list[";
           for (size_t i = 0; i < s.size; ++i) {
-              if (i) cout << ", ";
+              if (i) std::cout << ", ";
               print_next(d);
           }
-          cout << "]";
+          std::cout << "]";
           d >> proton::finish();
           break;
       }
       case proton::MAP: {
           d >> s;
-          cout << "map{";
+          std::cout << "map{";
           for (size_t i = 0; i < s.size/2; ++i) {
-              if (i) cout << ", ";
+              if (i) std::cout << ", ";
               print_next(d);
-              cout << ":";        // key:value
+              std::cout << ":";        // key:value
               print_next(d);
           }
-          cout << "}";
+          std::cout << "}";
           d >> proton::finish();
           break;
       }
       case proton::DESCRIBED: {
           d >> s;
-          cout << "described(";
+          std::cout << "described(";
           print_next(d);      // Descriptor
           print_next(d);      // value
           d >> proton::finish();
@@ -192,7 +222,7 @@ void print_next(proton::decoder& d) {
         // we will take a short cut and extract to another value and print that.
         proton::value v2;
         d >> v2;
-        cout << type << "(" << v2 << ")";
+        std::cout << type << "(" << v2 << ")";
     }
 }
 
@@ -200,10 +230,9 @@ void print_next(proton::decoder& d) {
 void print(proton::value& v) {
     proton::decoder& d = v.decoder();
     d.rewind();
-    cout << "Values: ";
     while (d.more()) {
         print_next(d);
-        if (d.more()) cout << ", ";
+        if (d.more()) std::cout << ", ";
     }
-    cout << endl;
+    std::cout << std::endl;
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/01e136cc/examples/cpp/example_test.py
----------------------------------------------------------------------
diff --git a/examples/cpp/example_test.py b/examples/cpp/example_test.py
index f51cf57..bc552ab 100644
--- a/examples/cpp/example_test.py
+++ b/examples/cpp/example_test.py
@@ -199,18 +199,26 @@ class ExampleTest(unittest.TestCase):
 
     def test_encode_decode(self):
         expect="""
-== Array, list and map.
-Values: array<int>[int(1), int(2), int(3)], list[int(4), int(5)], map{string(one):int(1), string(two):int(2)}
-Extracted: [ 1 2 3 ], [ 4 5 ], { one:1 two:2 }
+== Array, list and map of uniform type.
+array<int>[int(1), int(2), int(3)]
+[ 1 2 3 ]
+list[int(1), int(2), int(3)]
+[ 1 2 3 ]
+map{string(one):int(1), string(two):int(2)}
+{ one:1 two:2 }
+map{string(z):int(3), string(a):int(4)}
+[ z:3 a:4 ]
 
 == List and map of mixed type values.
-Values: list[int(42), string(foo)], map{int(4):string(four), string(five):int(5)}
-Extracted: [ 42 foo ], { 4:four five:5 }
+list[int(42), string(foo)]
+[ 42 foo ]
+map{int(4):string(four), string(five):int(5)}
+{ 4:four five:5 }
 
 == Insert with stream operators.
-Values: array<int>[int(1), int(2), int(3)]
-Values: list[int(42), boolean(false), symbol(x)]
-Values: map{string(k1):int(42), symbol(k2):boolean(false)}
+array<int>[int(1), int(2), int(3)]
+list[int(42), boolean(false), symbol(x)]
+map{string(k1):int(42), symbol(k2):boolean(false)}
 """
         self.maxDiff = None
         self.assertEqual(expect, execute("encode_decode"))

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/01e136cc/examples/cpp/simple_send.cpp
----------------------------------------------------------------------
diff --git a/examples/cpp/simple_send.cpp b/examples/cpp/simple_send.cpp
index cb33207..31e2c73 100644
--- a/examples/cpp/simple_send.cpp
+++ b/examples/cpp/simple_send.cpp
@@ -51,7 +51,7 @@ class simple_send : public proton::messaging_handler {
             msg.id(sent + 1);
             std::map<std::string, int> m;
             m["sequence"] = sent+1;
-            msg.body(proton::as<proton::MAP>(m));
+            msg.body(m);
             sender.send(msg);
             sent++;
         }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/01e136cc/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 33ddb4f..1d105e9 100644
--- a/proton-c/bindings/cpp/include/proton/decoder.hpp
+++ b/proton-c/bindings/cpp/include/proton/decoder.hpp
@@ -23,51 +23,130 @@
 #include "proton/type_traits.hpp"
 #include "proton/types.hpp"
 #include "proton/facade.hpp"
+
 #include <iosfwd>
 
+#ifndef PN_NO_CONTAINER_CONVERT
+
+#include <vector>
+#include <deque>
+#include <list>
+#include <map>
+
+#if PN_HAS_CPP11
+#include <array>
+#include <forward_list>
+#include <unordered_map>
+#endif // PN_HAS_CPP11
+
+#endif // PN_NO_CONTAINER_CONVERT
+
 struct pn_data_t;
 
 namespace proton {
 
-class data;
 class message_id;
 
 /** Raised by decoder operations on error.*/
 struct decode_error : public error { PN_CPP_EXTERN explicit decode_error(const std::string&) throw(); };
 
-/** Skips a value with `decoder >> skip()`. */
+/** Skips a value with `dec >> skip()`. */
 struct skip{};
 
-/** Rewind the decoder with `decoder >> rewind()`. */
+/** Assert the next type of value in the decoder: `dec >> assert_type(t)`
+ *  throws if decoder.type() != t
+ */
+struct assert_type {
+    type_id type;
+    assert_type(type_id t) : type(t) {}
+};
+
+/** Rewind the decoder with `dec >> rewind()`. */
 struct rewind{};
 
 /**
- * Stream-like decoder from AMQP bytes to a stream of C++ values.
- *
- * types.h defines C++ types corresponding to AMQP types.
- *
- * decoder operator>> will extract AMQP types into corresponding C++ types, and
- * do simple conversions, e.g. from AMQP integer types to corresponding or
- * larger C++ integer types.
- *
- * You can require an exact AMQP type using the `as<type>(value)` helper. E.g.
- *
- *     amqp_int i;
- *     decoder >> as<INT>(i):       // Will throw if decoder does not contain an INT
- *
- * You can also use the `as` helper to extract an AMQP list, array or map into C++ containers.
- *
- *
- *     std::vector<amqp_int> v;
- *     decoder >> as<LIST>(v);     // Extract a list of INT.
- *
- * AMQP maps can be inserted/extracted to any container with pair<X,Y> as
- * value_type, which includes std::map and std::unordered_map but also for
- * example std::vector<std::pair<X,Y> >. This allows you to preserve order when
- * extracting AMQP maps.
- *
- * You can also extract container values element-by-element, see decoder::operator>>(decoder&, start&)
- *
+Stream-like decoder from AMQP bytes to C++ values.
+
+@see types.hpp defines C++ types corresponding to AMQP types.
+
+The decoder operator>> will extract AMQP types into any compatible C++
+type or throw an exception if the types are not compatible.
+
++-------------------------+-------------------------------+
+|AMQP type                |Compatible C++ types           |
++=========================+===============================+
+|BOOLEAN                  |amqp_boolean, bool             |
++-------------------------+-------------------------------+
+|signed integer type I    |C++ signed integer type T where|
+|                         |sizeof(T) >= sizeof(I)         |
++-------------------------+-------------------------------+
+|unsigned integer type U  |C++ unsigned integer type T    |
+|                         |where sizeof(T) >= sizeof(U)   |
++-------------------------+-------------------------------+
+|CHAR                     |amqp_char, wchar_t             |
++-------------------------+-------------------------------+
+|FLOAT                    |amqp_float, float              |
++-------------------------+-------------------------------+
+|DOUBLE                   |amqp_double, double            |
++-------------------------+-------------------------------+
+|STRING                   |amqp_string, std::string       |
++-------------------------+-------------------------------+
+|SYMBOL                   |amqp_symbol, std::string       |
++-------------------------+-------------------------------+
+|BINARY                   |amqp_binary, std::string       |
++-------------------------+-------------------------------+
+|DECIMAL<n>               |amqp_decimal<n>                |
++-------------------------+-------------------------------+
+|TIMESTAMP                |amqp_timestamp                 |
++-------------------------+-------------------------------+
+|UUID                     |amqp_uuid                      |
++-------------------------+-------------------------------+
+
+The special proton::value type can hold any AMQP type, simple or compound.
+
+By default operator >> will do any conversion that does not lose data. For example
+any AMQP signed integer type can be extracted as follows:
+
+    int64_t i;
+    dec >> i;
+
+You can assert the exact AMQP type with proton::assert_type, for example
+the following will throw if the AMQP type is not an AMQP INT (32 bits)
+
+    amqp_int i;
+    dec >> assert_type(INT) >> i;       // Will throw if decoder does not contain an INT
+
+You can extract AMQP ARRAY, LIST or MAP into standard C++ containers of compatible types, for example:
+
+    std::vector<int32_t> v;
+    dec >> v;
+
+This will work if the decoder contains an AMQP ARRAY or LIST of SHORT or INT values. It won't work
+for LONG or other types. It will also work for a MAP with keys and values that are SHORT OR INT,
+the map will be "flattened" into a sequence [ key1, value1, key2, value2 ] This will work with
+std::dequeue, std::array, std::list or std::forward_list.
+
+You can extract a MAP into a std::map or std::unordered_map
+
+    std::map<std::string, std::string> v;
+    dec >> v;
+
+This will work for any AMQP map with keys and values that are STRING, SYMBOL or BINARY.
+
+If you have non-standard container types that meet the most basic requirements for
+the container or associative-container concepts, you can use them via helper functions:
+
+    my_sequence_type<int64_t> s;
+    dec >> proton::to_sequence(s); // Decode sequence of integers
+    my_map_type<amqp_string, bool> s;
+    dec >> proton::to_map(s); // Decode map of string: bool.
+
+Finally you can extract an AMQP LIST with mixed type elements into a container of proton::value, e.g.
+
+    std::vector<proton::value> v;
+    dec >> v;
+
+You can also extract container values element-by-element, see decoder::operator>>(decoder&, start&)
 */
 class decoder : public facade<pn_data_t, decoder> {
   public:
@@ -124,14 +203,11 @@ class decoder : public facade<pn_data_t, decoder> {
     PN_CPP_EXTERN friend decoder& operator>>(decoder&, amqp_uuid&);
     PN_CPP_EXTERN friend decoder& operator>>(decoder&, std::string&);
     PN_CPP_EXTERN friend decoder& operator>>(decoder&, message_id&);
-    PN_CPP_EXTERN friend decoder& operator>>(decoder&, class data&);
+    PN_CPP_EXTERN friend decoder& operator>>(decoder&, value&);
     ///@}
 
     /** Extract and return a value of type T. */
-    template <class T> T get() { T value; *this >> value; return value; }
-
-    /** Extract and return a value of type T, as AMQP type. */
-    template <class T, type_id A> T get_as() { T value; *this >> as<A>(value); return value; }
+    template <class T> T extract() { T value; *this >> value; return value; }
 
     /** Call decoder::start() in constructor, decoder::finish in destructor().
      *
@@ -142,21 +218,15 @@ class decoder : public facade<pn_data_t, decoder> {
         ~scope() { decoder_ >> finish(); }
     };
 
-    template <type_id A, class T> friend decoder& operator>>(decoder& d, ref<T, A> ref) {
-        d.check_type(A);
-        d >> ref.value;
-        return d;
-    }
-
     /** start extracting a container value, one of array, list, map, described.
      * The basic pattern is:
      *
      *     start s;
-     *     decoder >> s;
+     *     dec >> s;
      *     // check s.type() to see if this is an ARRAY, LIST, MAP or DESCRIBED type.
      *     if (s.described) extract the descriptor...
      *     for (size_t i = 0; i < s.size(); ++i) Extract each element...
-     *     decoder >> finish();
+     *     dec >> finish();
      *
      * The first value of an ARRAY is a descriptor if start::descriptor is true,
      * followed by start.size elements of type start::element.
@@ -182,6 +252,9 @@ class decoder : public facade<pn_data_t, decoder> {
     /** Skip a value */
     PN_CPP_EXTERN friend decoder& operator>>(decoder&, skip);
 
+    /** Throw an exception if decoder.type() != assert_type.type */
+    PN_CPP_EXTERN friend decoder& operator>>(decoder&, assert_type);
+
     /** Rewind to the beginning */
     PN_CPP_EXTERN friend decoder& operator>>(decoder&, struct rewind);
 
@@ -191,46 +264,138 @@ class decoder : public facade<pn_data_t, decoder> {
   friend class encoder;
 };
 
+
 // operator >> for integer types that are not covered by the standard overrides.
 template <class T>
-typename enable_if<is_unknown_integer<T>::value, decoder&>::type operator>>(decoder& d, T& i)  {
+typename enable_if<is_unknown_integer<T>::value, decoder&>::type
+operator>>(decoder& d, T& i)  {
     typename integer_type<sizeof(T), is_signed<T>::value>::type v;
     d >> v;                     // Extract as a known integer type
     i = v;
     return d;
 }
 
-template <class T> decoder& operator>>(decoder& d, ref<T, ARRAY> ref)  {
+///@cond INTERNAL
+template <class T> struct sequence_ref {
+    sequence_ref(T& v) : value(v) {}
+    T& value;
+};
+
+template <class T> struct map_ref {
+    map_ref(T& v) : value(v) {}
+    T& value;
+};
+
+template <class T> struct pairs_ref {
+    pairs_ref(T& v) : value(v) {}
+    T& value;
+};
+///@endcond
+
+/**
+ * Return a wrapper for a C++ container to be decoded as a sequence. The AMQP
+ * ARRAY, LIST, and MAP types can all be decoded as a sequence, a map will be
+ * decoded as alternating key and value (provided they can both be converted to
+ * the container's value_type)
+ *
+ * The following expressions must be valid for T t;
+ *     T::iterator
+ *     t.clear()
+ *     t.resize()
+ *     t.begin()
+ *     t.end()
+ */
+template <class T> sequence_ref<T> to_sequence(T& v) { return sequence_ref<T>(v); }
+
+/** Return a wrapper for a C++ map container to be decoded from an AMQP MAP.
+ * The following expressions must be valid for T t;
+ *     T::key_type
+ *     T::mapped_type
+ *     t.clear()
+ *     T::key_type k; T::mapped_type v; t[k] = v;
+ */
+template <class T> map_ref<T> to_map(T& v) { return map_ref<T>(v); }
+
+/** Return a wrapper for a C++ container of std::pair that can be decoded from AMQP maps,
+ * preserving the encoded map order.
+ *
+ * The following expressions must be valid for T t;
+ *     T::iterator
+ *     t.clear()
+ *     t.resize()
+ *     t.begin()
+ *     t.end()
+ *     T::iterator i; i->first; i->second
+ */
+template <class T> pairs_ref<T> to_pairs(T& v) { return pairs_ref<T>(v); }
+
+/** Extract any AMQP sequence (ARRAY, LIST or MAP) to a C++ container of T if
+ * the elements types are convertible to T. A MAP is extracted as [key1, value1,
+ * key2, value2...]
+ */
+template <class T> decoder& operator>>(decoder& d, sequence_ref<T> ref)  {
     decoder::scope s(d);
     if (s.is_described) d >> skip();
-    ref.value.clear();
-    ref.value.resize(s.size);
-    for (typename T::iterator i = ref.value.begin(); i != ref.value.end(); ++i) {
+    T& v = ref.value;
+    v.clear();
+    v.resize(s.size);
+    for (typename T::iterator i = v.begin(); i != v.end(); ++i)
         d >> *i;
-    }
     return d;
 }
 
-template <class T> decoder& operator>>(decoder& d, ref<T, LIST> ref)  {
+void assert_map_scope(const decoder::scope& s);
+
+/** Extract an AMQP MAP to a C++ map */
+template <class T> decoder& operator>>(decoder& d, map_ref<T> ref)  {
     decoder::scope s(d);
-    ref.value.clear();
-    ref.value.resize(s.size);
-    for (typename T::iterator i = ref.value.begin(); i != ref.value.end(); ++i)
-        d >> *i;
+    assert_map_scope(s);
+    T& m = ref.value;
+    m.clear();
+    for (size_t i = 0; i < s.size/2; ++i) {
+        typename remove_const<typename T::key_type>::type k;
+        typename remove_const<typename T::mapped_type>::type v;
+        d >> k >> v;
+        m[k] = v;
+    }
     return d;
 }
 
-template <class T> decoder& operator>>(decoder& d, ref<T, MAP> ref)  {
-    decoder::scope m(d);
-    ref.value.clear();
-    for (size_t i = 0; i < m.size/2; ++i) {
-        typename T::key_type k;
-        typename T::mapped_type v;
-        d >> k >> v;
-        ref.value[k] = v;
+/** Extract an AMQP MAP to a C++ container of std::pair, preserving order. */
+template <class T> decoder& operator>>(decoder& d, pairs_ref<T> ref)  {
+    decoder::scope s(d);
+    assert_map_scope(s);
+    T& m = ref.value;
+    m.clear();
+    m.resize(s.size/2);
+    for (typename T::iterator i = m.begin(); i != m.end(); ++i) {
+        d >> i->first >> i->second;
     }
     return d;
 }
 
+#ifndef PN_NO_CONTAINER_CONVERT
+
+// Decode to sequence.
+template <class T, class A> decoder& operator>>(decoder &d, std::vector<T, A>& v) { return d >> to_sequence(v); }
+template <class T, class A> decoder& operator>>(decoder &d, std::deque<T, A>& v) { return d >> to_sequence(v); }
+template <class T, class A> decoder& operator>>(decoder &d, std::list<T, A>& v) { return d >> to_sequence(v); }
+
+// Decode to map.
+template <class K, class T, class C, class A> decoder& operator>>(decoder &d, std::map<K, T, C, A>& v) { return d >> to_map(v); }
+
+#if PN_HAS_CPP11
+
+// Decode to sequence.
+template <class T, class A> decoder& operator>>(decoder &d, std::forward_list<T, A>& v) { return d >> to_sequence(v); }
+template <class T, std::size_t N> decoder& operator>>(decoder &d, std::array<T, N>& v) { return d >> to_sequence(v); }
+
+// Decode to map.
+template <class K, class T, class C, class A> decoder& operator>>(decoder &d, std::unordered_map<K, T, C, A>& v) { return d >> to_map(v); }
+
+#endif // PN_HAS_CPP11
+#endif // PN_NO_CONTAINER_CONVERT
+
 }
+
 #endif // DECODER_H

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/01e136cc/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 24684c1..7dd7ddb 100644
--- a/proton-c/bindings/cpp/include/proton/encoder.hpp
+++ b/proton-c/bindings/cpp/include/proton/encoder.hpp
@@ -25,39 +25,68 @@
 #include "proton/facade.hpp"
 #include <iosfwd>
 
+#ifndef PN_NO_CONTAINER_CONVERT
+
+#include <vector>
+#include <deque>
+#include <list>
+#include <map>
+
+#if PN_HAS_CPP11
+#include <array>
+#include <forward_list>
+#include <unordered_map>
+#endif // PN_HAS_CPP11
+
+#endif // PN_NO_CONTAINER_CONVERT
+
 struct pn_data_t;
 
 namespace proton {
 
-class data;
 class message_id;
 
 /** Raised by encoder operations on error */
 struct encode_error : public error { PN_CPP_EXTERN explicit encode_error(const std::string&) throw(); };
 
 /**
- * Stream C++ data values into an AMQP encoder using operator<<.
+ * Stream-like encoder from C++ values to AMQP values.
  *
- * types.h defines C++ typedefs and types for AMQP each type. These types insert
- * as the corresponding AMQP type. Conversion rules apply to other types:
+ * types.hpp defines a C++ type for each AMQP type. For simple types they are
+ * just typedefs for corresponding native C++ types. These types encode as the
+ * corresponding AMQP type.
  *
- * - Integer types insert as the AMQP integer of matching size and signedness.
- * - std::string or char* insert as AMQP strings.
+ * There are some special case conversions:
  *
- * C++ containers can be inserted as AMQP containers with the as() helper
- * functions. For example:
+ * - Integer types other than those mentioned in types.hpp encode as the AMQP
+ *   integer type of matching size and signedness.
+ * - std::string or char* insert as AMQP STRING.
  *
- *     std::vector<amqp_symbol> v;
- *     encoder << as<amqp_list>(v);
+ * For example to encode an AMQP INT, BOOLEAN and STRING these are equivalent:
  *
- * AMQP maps can be inserted from any container with std::pair<X,Y> as the
- * value_type. That includes std::map and std::unordered_map but also for
- * example std::vector<std::pair<X,Y> >. This allows you to control the order
- * of elements when inserting AMQP maps.
+ *     enc << proton::amqp_int(1) << proton::amqp_boolean(true) << proton::amqp_string("foo");
+ *     enc << int32_t(1) << true << "foo";
  *
- * You can also insert containers element-by-element, see operator<<(encoder&, const start&)
+ * You can force the encoding using the `proton::as` template function, for example:
+ *
+ *     uint64_t i = 100;
+ *     enc << as<proton::SHORT>(i);
+ *
+ * C++ standard containers can be inserted. By default:
+ *
+ * - std::map and std::unordered_map encode as AMQP MAP
+ * - std::vector, std::deque, std::list, std::array or std::forward_list encode as an AMQP ARRAY.
+ * - std::vector<proton::value> etc. encode as AMQP LIST
+ *
+ * Again you can force the encoding using proton::as<LIST>() or proton::as<ARRAY>()
+ *
+ * Note that you can encode a sequence of pairs as a map, which allows you to control the
+ * encoded order if that is important:
+ *
+ *     std::vector<std::pair<T1, T2> > v;
+ *     enc << proton::as<MAP>(v);
  *
- *@throw decoder::error if the curent value is not a container type.
+ * You can also insert containers element-by-element, see operator<<(encoder&, const start&)
  */
 class encoder : public facade<pn_data_t, encoder> {
   public:
@@ -107,7 +136,7 @@ class encoder : public facade<pn_data_t, encoder> {
   friend PN_CPP_EXTERN encoder& operator<<(encoder&, amqp_symbol);
   friend PN_CPP_EXTERN encoder& operator<<(encoder&, amqp_binary);
   friend PN_CPP_EXTERN encoder& operator<<(encoder&, const message_id&);
-  friend PN_CPP_EXTERN encoder& operator<<(encoder&, const class data&);
+  friend PN_CPP_EXTERN encoder& operator<<(encoder&, const value&);
     ///@}
 
     /**
@@ -118,7 +147,7 @@ class encoder : public facade<pn_data_t, encoder> {
      * and insert it into the encoder, followed by the contained elements.  For
      * example:
      *
-     *      encoder << start::list() << amqp_int(1) << amqp_symbol("two") << 3.0 << finish();
+     *      enc << start::list() << amqp_int(1) << amqp_symbol("two") << 3.0 << finish();
      */
   friend PN_CPP_EXTERN encoder& operator<<(encoder&, const start&);
 
@@ -135,9 +164,6 @@ class encoder : public facade<pn_data_t, encoder> {
   template <class T> friend encoder& operator<<(encoder&, cref<T, MAP>);
     // TODO aconway 2015-06-16: described values.
     ///@}
-
-    /** Copy data from a raw pn_data_t */
-  friend PN_CPP_EXTERN encoder& operator<<(encoder&, pn_data_t*);
 };
 
 // Need to disambiguate char* conversion to bool and std::string as amqp_string.
@@ -179,11 +205,36 @@ template <class T> encoder& operator<<(encoder& e, cref<T, MAP> m){
     e << finish();
     return e;
 }
-///@cond INTERNAL Convert a ref to a cref.
-template <class T, type_id A> encoder& operator<<(encoder& e, ref<T, A> ref) {
-    return e << cref<T,A>(ref);
-}
-///@endcond
 
+#ifndef PN_NO_CONTAINER_CONVERT
+// Encode as ARRAY
+template <class T, class A> encoder& operator<<(encoder &e, const std::vector<T, A>& v) { return e << as<ARRAY>(v); }
+template <class T, class A> encoder& operator<<(encoder &e, const std::deque<T, A>& v) { return e << as<ARRAY>(v); }
+template <class T, class A> encoder& operator<<(encoder &e, const std::list<T, A>& v) { return e << as<ARRAY>(v); }
+
+// Encode as LIST
+template <class A> encoder& operator<<(encoder &e, const std::vector<value, A>& v) { return e << as<LIST>(v); }
+template <class A> encoder& operator<<(encoder &e, const std::deque<value, A>& v) { return e << as<LIST>(v); }
+template <class A> encoder& operator<<(encoder &e, const std::list<value, A>& v) { return e << as<LIST>(v); }
+
+// Encode as MAP
+template <class K, class T, class C, class A> encoder& operator<<(encoder &e, const std::map<K, T, C, A>& v) { return e << as<MAP>(v); }
+
+#if PN_HAS_CPP11
+
+// Encode as ARRAY.
+template <class T, class A> encoder& operator<<(encoder &e, const std::forward_list<T, A>& v) { return e << as<ARRAY>(v); }
+template <class T, std::size_t N> encoder& operator<<(encoder &e, const std::array<T, N>& v) { return e << as<ARRAY>(v); }n
+
+// Encode as LIST.
+template <class value, class A> encoder& operator<<(encoder &e, const std::forward_list<value, A>& v) { return e << as<LIST>(v); }
+template <class value, std::size_t N> encoder& operator<<(encoder &e, const std::array<value, N>& v) { return e << as<LIST>(v); }
+
+// Encode as map.
+template <class K, class T, class C, class A> encoder& operator<<(encoder &e, const std::unordered_map<K, T, C, A>& v) { return e << as<MAP>(v); }
+
+#endif // PN_HAS_CPP11
+
+#endif // PN_NO_CONTAINER_CONVERT
 }
 #endif // ENCODER_H

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/01e136cc/proton-c/bindings/cpp/include/proton/engine.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/engine.hpp b/proton-c/bindings/cpp/include/proton/engine.hpp
index 672e911..f27033d 100644
--- a/proton-c/bindings/cpp/include/proton/engine.hpp
+++ b/proton-c/bindings/cpp/include/proton/engine.hpp
@@ -31,7 +31,7 @@ namespace proton {
 class handler;
 class connection;
 
-/// Pointers to a data buffer.
+/// Pointers to a byte range to use as a buffer.
 template <class T> class buffer {
   public:
     explicit buffer(T* begin__=0, T* end__=0) : begin_(begin__), end_(end__) {}

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/01e136cc/proton-c/bindings/cpp/include/proton/message.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/message.hpp b/proton-c/bindings/cpp/include/proton/message.hpp
index e9862c6..d996f85 100644
--- a/proton-c/bindings/cpp/include/proton/message.hpp
+++ b/proton-c/bindings/cpp/include/proton/message.hpp
@@ -26,6 +26,7 @@
 #include "proton/message_id.hpp"
 #include "proton/data.hpp"
 #include "proton/pn_unique_ptr.hpp"
+#include "proton/value.hpp"
 
 #include <string>
 #include <utility>
@@ -95,32 +96,31 @@ class message
     PN_CPP_EXTERN std::string reply_to_group_id() const;
     ///@}
 
-    /** Set the body. If data has more than one value, each is encoded as an AMQP section. */
-    PN_CPP_EXTERN void body(const data&);
+    /** Set the body. */
+    PN_CPP_EXTERN void body(const value&);
 
-    /** Set the body to any type T that can be converted to proton::data */
-    template <class T> void body(const T& v) { body().clear(); body().encoder() << v; }
-
-    /** Get the body values. */
+    /** Get the body. Note data can be copied to a proton::value */
     PN_CPP_EXTERN const data& body() const;
 
     /** Get a reference to the body data, can be modified in-place. */
     PN_CPP_EXTERN data& body();
 
-    /** Encode into memory starting at buffer.first and ending before buffer.second */
+    // FIXME aconway 2015-11-10: use buffer
+    /** Encode message into memory starting at buffer.first and ending before buffer.second */
     PN_CPP_EXTERN void encode(std::pair<char*, char*> buffer);
 
     /** Encode into a string, growing the string if necessary. */
-    PN_CPP_EXTERN void encode(std::string &data) const;
+    PN_CPP_EXTERN void encode(std::string &bytes) const;
 
     /** Return encoded message as a string */
     PN_CPP_EXTERN std::string encode() const;
 
+    // FIXME aconway 2015-11-10: use buffer
     /** Decode from memory starting at buffer.first and ending before buffer.second */
     PN_CPP_EXTERN void decode(std::pair<const char*, const char*> buffer);
 
     /** Decode from string data into the message. */
-    PN_CPP_EXTERN void decode(const std::string &data);
+    PN_CPP_EXTERN void decode(const std::string &bytes);
 
     /// Decode the message from link corresponding to delivery.
     PN_CPP_EXTERN void decode(proton::link&, proton::delivery&);

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/01e136cc/proton-c/bindings/cpp/include/proton/message_id.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/message_id.hpp b/proton-c/bindings/cpp/include/proton/message_id.hpp
index a472afd..4ff8b52 100644
--- a/proton-c/bindings/cpp/include/proton/message_id.hpp
+++ b/proton-c/bindings/cpp/include/proton/message_id.hpp
@@ -29,6 +29,8 @@ namespace proton {
 class message_id : public comparable<message_id> {
   public:
     message_id() {}
+    message_id(const value& x) : value_(x) {}
+    message_id(const data& x) : value_(x) {}
     message_id(const uint64_t& x) : value_(x) {}
     message_id(const amqp_uuid& x) : value_(x) {}
     message_id(const amqp_binary& x) : value_(x) {}
@@ -71,7 +73,6 @@ class message_id : public comparable<message_id> {
   friend PN_CPP_EXTERN decoder& operator>>(decoder&, message_id&);
 
   private:
-    message_id(const value& v) : value_(v) {}
     value value_;
   friend class message;
 };

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/01e136cc/proton-c/bindings/cpp/include/proton/request_response.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/request_response.hpp b/proton-c/bindings/cpp/include/proton/request_response.hpp
index 957c91a..58b8156 100644
--- a/proton-c/bindings/cpp/include/proton/request_response.hpp
+++ b/proton-c/bindings/cpp/include/proton/request_response.hpp
@@ -29,9 +29,6 @@
 
 #include <string>
 
-struct pn_message_t;
-struct pn_data_t;
-
 namespace proton {
 
 /**

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/01e136cc/proton-c/bindings/cpp/include/proton/type_traits.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/type_traits.hpp b/proton-c/bindings/cpp/include/proton/type_traits.hpp
index bebf0b1..d12e0ed 100644
--- a/proton-c/bindings/cpp/include/proton/type_traits.hpp
+++ b/proton-c/bindings/cpp/include/proton/type_traits.hpp
@@ -30,7 +30,9 @@
 #include "proton/types.hpp"
 
 namespace proton {
-template <bool, class T=void> struct enable_if;
+class value;
+
+template <bool, class T=void> struct enable_if {};
 template <class T> struct enable_if<true, T> { typedef T type; };
 
 struct true_type { static const bool value = true; };
@@ -67,8 +69,15 @@ template <> struct is_signed<unsigned long long> : public false_type {};
 template <> struct is_signed<signed long long> : public true_type {};
 #endif
 
-// Metafunction returning exact AMQP type associated with a C++ type
-template <class T> struct type_id_of;
+template <class T, class U> struct is_same { static const bool value=false; };
+template <class T> struct is_same<T,T> { static const bool value=true; };
+
+
+template< class T > struct remove_const          { typedef T type; };
+template< class T > struct remove_const<const T> { typedef T type; };
+
+// Metafunction returning AMQP type for basic C++ types
+template <class T, class Enable=void> struct type_id_of;
 template<> struct type_id_of<amqp_null> { static const type_id value=NULL_; };
 template<> struct type_id_of<amqp_boolean> { static const type_id value=BOOLEAN; };
 template<> struct type_id_of<amqp_ubyte> { static const type_id value=UBYTE; };
@@ -91,12 +100,12 @@ template<> struct type_id_of<amqp_binary> { static const type_id value=BINARY; }
 template<> struct type_id_of<amqp_string> { static const type_id value=STRING; };
 template<> struct type_id_of<amqp_symbol> { static const type_id value=SYMBOL; };
 
-template <class T, class Enable=void> struct has_type_id { static const bool value = false; };
+template <class T, class Enable=void> struct has_type_id : public false_type {};
 template <class T> struct has_type_id<T, typename enable_if<!!type_id_of<T>::value>::type>  {
     static const bool value = true;
 };
 
-// amqp_map to known integer types by sizeof and signedness.
+// Map arbitrary integral types to know AMQP integral types.
 template<size_t N, bool S> struct integer_type;
 template<> struct integer_type<1, true> { typedef amqp_byte type; };
 template<> struct integer_type<2, true> { typedef amqp_short type; };

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/01e136cc/proton-c/bindings/cpp/include/proton/types.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/types.hpp b/proton-c/bindings/cpp/include/proton/types.hpp
index 0f82ae3..b9fedd1 100644
--- a/proton-c/bindings/cpp/include/proton/types.hpp
+++ b/proton-c/bindings/cpp/include/proton/types.hpp
@@ -159,51 +159,22 @@ struct amqp_timestamp : public comparable<amqp_timestamp> {
 };
 
 ///@cond INTERNAL
-template<class T, type_id A> struct type_pair {
+template<class T, type_id A> struct cref {
     typedef T cpp_type;
-    type_id type;
-};
-
-template<class T, type_id A> struct ref : public type_pair<T, A> {
-    ref(T& v) : value(v) {}
-    T& value;
-};
+    static const type_id type;
 
-template<class T, type_id A> struct cref : public type_pair<T, A> {
     cref(const T& v) : value(v) {}
-    cref(const ref<T,A>& ref) : value(ref.value) {}
     const T& value;
 };
+template <class T, type_id A> const type_id cref<T, A>::type = A;
 ///@endcond INTERNAL
 
-/** A holder for AMQP values. A holder is always encoded/decoded as its amqp_value, no need
- * for the as<TYPE>() helper functions.
- *
- * For example to encode an array of arrays using std::vector:
- *
- *     typedef holder<std::vector<amqp_string>, ARRAY> Inner;
- *     typedef holder<std::vector<Inner>, ARRAY> Outer;
- *     Outer o ...
- *     encoder << o;
- *
- */
-template<class T, type_id A> struct holder : public type_pair<T, A> {
-    T value;
-};
-
-/** Create a reference to value as AMQP type A for decoding.
- * For example to decode an array of amqp_int:
- *
- *     std::vector<amqp_int> v;
- *     decoder >> as<ARRAY>(v);
- */
-template <type_id A, class T> ref<T, A> as(T& value) { return ref<T, A>(value); }
-
-/** Create a const reference to value as AMQP type A for encoding.
- * For example to encode an array of amqp_int:
+/**
+ * Indicate the desired AMQP type to use when encoding T.
+ * For example to encode a vector as a list:
  *
  *     std::vector<amqp_int> v;
- *     encoder << as<ARRAY>(v);
+ *     encoder << as<LIST>(v);
  */
 template <type_id A, class T> cref<T, A> as(const T& value) { return cref<T, A>(value); }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/01e136cc/proton-c/bindings/cpp/include/proton/value.hpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/include/proton/value.hpp b/proton-c/bindings/cpp/include/proton/value.hpp
index 8816064..ddc5501 100644
--- a/proton-c/bindings/cpp/include/proton/value.hpp
+++ b/proton-c/bindings/cpp/include/proton/value.hpp
@@ -30,11 +30,23 @@ class data;
 class encoder;
 class decoder;
 
-/** AMQP data  with normal value semantics: copy, assign etc. */
+/**
+ * Holder for an AMQP value.
+ *
+ * proton::value can hold any AMQP data value, simple or compound.  It has
+ * assignment and conversion operators to convert its contents easily to and
+ * from native C++ types.
+ *
+ * See proton::encoder and proton::decoder for details of the conversion rules.
+ * Assigning to a proton::value follows the encoder rules, converting from a
+ * proton::value (or calling proton::value::get) follows the decoder rules.
+ */
 class value : public comparable<value> {
   public:
     PN_CPP_EXTERN value();
     PN_CPP_EXTERN value(const value& x);
+    PN_CPP_EXTERN value(const data&);
+
     template <class T> value(const T& x) : data_(data::create()) { *data_ = x; }
 
     PN_CPP_EXTERN value& operator=(const value& x);
@@ -44,23 +56,26 @@ class value : public comparable<value> {
     PN_CPP_EXTERN void clear();
     PN_CPP_EXTERN bool empty() const;
 
-    /** Encoder to encode complex data into this value.
-     * Note if you enocde more than one value, all but the first will be ignored.
-     */
+    // FIXME aconway 2015-11-06: rename encode/decode
+
+    /** Encoder to encode complex data into this value. Note this clears the value. */
     PN_CPP_EXTERN class encoder& encoder();
 
-    /** Decoder to decode complex data from this value */
-    PN_CPP_EXTERN class decoder& decoder();
+    /** Decoder to decode complex data from this value. Note this rewinds the decoder. */
+    PN_CPP_EXTERN class decoder& decoder() const;
 
     /** Type of the current value*/
     PN_CPP_EXTERN type_id type() const;
 
     /** Get the value. */
-    template<class T> void get(T &t) const { rewind() >> t; }
+    template<class T> void get(T &t) const { decoder() >> t; }
 
     /** Get the value. */
     template<class T> T get() const { T t; get(t); return t; }
 
+    /** Automatic conversion */
+    template<class T> operator T() const { return get<T>(); }
+
     PN_CPP_EXTERN bool operator==(const value& x) const;
     PN_CPP_EXTERN bool operator<(const value& x) const;
 
@@ -69,9 +84,6 @@ class value : public comparable<value> {
   friend PN_CPP_EXTERN std::ostream& operator<<(std::ostream& o, const value& dv);
 
   private:
-    value(const data&);
-    class decoder& rewind() const { data_->decoder().rewind(); return data_->decoder(); }
-
     pn_unique_ptr<data> data_;
   friend class message;
 };

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/01e136cc/proton-c/bindings/cpp/src/decoder.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/decoder.cpp b/proton-c/bindings/cpp/src/decoder.cpp
index d148b12..1fe13a2 100644
--- a/proton-c/bindings/cpp/src/decoder.cpp
+++ b/proton-c/bindings/cpp/src/decoder.cpp
@@ -147,16 +147,19 @@ decoder& operator>>(decoder& d, finish) { pn_data_exit(pn_cast(&d)); return d; }
 
 decoder& operator>>(decoder& d, skip) { pn_data_next(pn_cast(&d)); return d; }
 
+decoder& operator>>(decoder& d, assert_type a) { bad_type(a.type, d.type()); return d; }
+
 decoder& operator>>(decoder& d, rewind) { d.rewind(); return d; }
 
-decoder& operator>>(decoder& d, data& v) {
-    if (pn_cast(&d) == pn_cast(&v)) throw decode_error("extract into self");
-    v.clear();
+decoder& operator>>(decoder& d, value& v) {
+    pn_data_t *ddata = pn_cast(&d);
+    pn_data_t *vdata = pn_cast(&v.encoder());
+    if (ddata == vdata) throw decode_error("extract into self");
     {
-        narrow n(pn_cast(&d));
-        check(pn_data_appendn(pn_cast(&v), pn_cast(&d), 1));
+        narrow n(ddata);
+        check(pn_data_appendn(vdata, ddata, 1));
     }
-    if (!pn_data_next(pn_cast(&d))) throw decode_error("no more data");
+    if (!pn_data_next(ddata)) throw decode_error("no more data");
     return d;
 }
 
@@ -340,4 +343,12 @@ decoder& operator>>(decoder& d, std::string& value) {
     return d;
 }
 
+void assert_map_scope(const decoder::scope& s) {
+    if (s.type != MAP)
+        throw decode_error("cannot decode "+type_name(s.type)+" as map");
+    if (s.size % 2 != 0)
+        throw decode_error("odd number of elements in map");
+}
+
+
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/01e136cc/proton-c/bindings/cpp/src/encoder.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/encoder.cpp b/proton-c/bindings/cpp/src/encoder.cpp
index 0230e88..c8e6928 100644
--- a/proton-c/bindings/cpp/src/encoder.cpp
+++ b/proton-c/bindings/cpp/src/encoder.cpp
@@ -130,9 +130,11 @@ encoder& operator<<(encoder& e, amqp_string value) { return insert(e, pn_cast(&e
 encoder& operator<<(encoder& e, amqp_symbol value) { return insert(e, pn_cast(&e), value, pn_data_put_symbol); }
 encoder& operator<<(encoder& e, amqp_binary value) { return insert(e, pn_cast(&e), value, pn_data_put_binary); }
 
-encoder& operator<<(encoder& e, const data& v) {
-    if (pn_cast(&e) == pn_cast(&v)) throw encode_error("cannot insert into self");
-    check(pn_data_append(pn_cast(&e), pn_cast(&v)), pn_cast(&e));
+encoder& operator<<(encoder& e, const value& v) {
+    pn_data_t *edata = pn_cast(&e);
+    pn_data_t *vdata = pn_cast(&v.decoder());
+    if (edata == vdata) throw encode_error("cannot insert into self");
+    check(pn_data_append(edata, vdata), edata);
     return e;
 }
 

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/01e136cc/proton-c/bindings/cpp/src/interop_test.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/interop_test.cpp b/proton-c/bindings/cpp/src/interop_test.cpp
index ac2701f..0bac03c 100644
--- a/proton-c/bindings/cpp/src/interop_test.cpp
+++ b/proton-c/bindings/cpp/src/interop_test.cpp
@@ -39,7 +39,11 @@ string read(string filename) {
     return string(istreambuf_iterator<char>(ifs), istreambuf_iterator<char>());
 }
 
-template <class T> T get(decoder& d) { return d.get_as<T, type_id_of<T>::value>(); }
+template <class T> T get(decoder& d) {
+    T v;
+    d >> assert_type(type_id_of<T>::value) >> v;
+    return v;
+}
 
 template <class T> std::string str(const T& value) {
     ostringstream oss;

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/01e136cc/proton-c/bindings/cpp/src/message.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/message.cpp b/proton-c/bindings/cpp/src/message.cpp
index 63f6520..7ebb821 100644
--- a/proton-c/bindings/cpp/src/message.cpp
+++ b/proton-c/bindings/cpp/src/message.cpp
@@ -161,7 +161,7 @@ std::string message::reply_to_group_id() const {
     return s ? std::string(s) : std::string();
 }
 
-void message::body(const data& v) { body() = v; }
+void message::body(const value& v) { body() = v; }
 
 const data& message::body() const {
     return *data::cast(pn_message_body(message_));

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/01e136cc/proton-c/bindings/cpp/src/value.cpp
----------------------------------------------------------------------
diff --git a/proton-c/bindings/cpp/src/value.cpp b/proton-c/bindings/cpp/src/value.cpp
index 6b4c402..7059d69 100644
--- a/proton-c/bindings/cpp/src/value.cpp
+++ b/proton-c/bindings/cpp/src/value.cpp
@@ -40,18 +40,16 @@ void value::clear() { data_->clear(); }
 
 bool value::empty() const { return data_->empty(); }
 
-class encoder& value::encoder() { return data_->encoder(); }
+class encoder& value::encoder() { clear(); return data_->encoder(); }
 
-class decoder& value::decoder() { return data_->decoder(); }
+class decoder& value::decoder() const { data_->decoder().rewind(); return data_->decoder(); }
 
-type_id value::type() const { return rewind().type(); }
+type_id value::type() const { return decoder().type(); }
 
 bool value::operator==(const value& x) const { return *data_ == *x.data_; }
 
 bool value::operator<(const value& x) const { return *data_ < *x.data_; }
 
-
-
 std::ostream& operator<<(std::ostream& o, const value& v) {
     // pn_inspect prints strings with quotes which is not normal in C++.
     switch (v.type()) {
@@ -63,12 +61,4 @@ std::ostream& operator<<(std::ostream& o, const value& v) {
     }
 }
 
-class encoder& operator<<(class encoder& e, const value& v) {
-    return e << *v.data_;
-}
-
-class decoder& operator>>(class decoder& d, value& v) {
-    return d >> *v.data_;
-}
-
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org