bindings: Manually adding some python bindings

The following features are supported:
- Run basic scenarios using python.
- Iterate over FIB/PIT/CS(nfd) entries

There is a chance that there are memory leaks in the implementation, due
to extensive hacking.

Refs: #2341
diff --git a/bindings/modulegen__gcc_ILP32.py b/bindings/modulegen__gcc_ILP32.py
index 09c4b4f..a684069 100644
--- a/bindings/modulegen__gcc_ILP32.py
+++ b/bindings/modulegen__gcc_ILP32.py
@@ -1,9 +1,12 @@
 from pybindgen import Module, FileCodeSink, param, retval, cppclass, typehandlers
 
+from pybindgen.typehandlers.smart_ptr import StdSharedPtr
+
+from ns3_ptr import Ns3PtrMemoryPolicy
+
 import pybindgen.settings
 import warnings
 
-
 import sys
 
 def module_init():
@@ -11,10 +14,293 @@
     return root_module
 
 def register_types(module):
-    return
+    module.add_class('ObjectBase', allow_subclassing=True, import_from_module='ns.core')
+    module.add_class('SimpleRefCount', automatic_type_narrowing=True, import_from_module='ns.core',
+                     template_parameters=['ns3::Object', 'ns3::ObjectBase', 'ns3::ObjectDeleter'],
+                     parent=module['ns3::ObjectBase'],
+                     memory_policy=cppclass.ReferenceCountingMethodsPolicy(incref_method='Ref', decref_method='Unref', peekref_method='GetReferenceCount'))
+    module.add_class('Object', import_from_module='ns.core', parent=module['ns3::SimpleRefCount< ns3::Object, ns3::ObjectBase, ns3::ObjectDeleter >'])
+
+    module.add_class('TypeId', import_from_module='ns.core')
+    module.add_class('AttributeValue', import_from_module='ns.core')
+
+    module.add_class('NodeContainer', import_from_module='ns.network')
+    module.add_class('Node', import_from_module='ns.network', parent=module['ns3::Object'])
+    module.add_class('ApplicationContainer', import_from_module='ns.network')
+
+    def reg_ndn(module):
+        module.add_class('StackHelper')
+        module.add_class('FibHelper')
+        module.add_class('StrategyChoiceHelper')
+        module.add_class('AppHelper')
+        module.add_class('GlobalRoutingHelper')
+
+        module.add_class('L3Protocol', parent=module.get_root()['ns3::Object'])
+
+        module.add_class('Name')
+        module.add_class('Interest')
+        module.add_class('Data')
+        module.add_class('Face', memory_policy=StdSharedPtr('ns3::ndn::Face'))
+        module.add_class('FaceContainer', memory_policy=Ns3PtrMemoryPolicy('::ns3::ndn::FaceContainer'))
+
+        def reg_name(module):
+            module.add_class('Component')
+        reg_name(module.add_cpp_namespace('name'))
+
+        def reg_nfd(module):
+            module.add_class('Forwarder', memory_policy=StdSharedPtr('::ns3::ndn::nfd::Forwarder'), is_singleton=True)
+            module.add_class('Fib')
+            module.add_class('Pit')
+            module.add_class('Cs')
+
+            def reg_fib(module):
+                module.add_class('Entry')#, memory_policy=StdSharedPtr('ns3::ndn::nfd::fib::Entry'))
+                module.add_class('NextHop')
+                module.add_class('NextHopList')
+            reg_fib(module.add_cpp_namespace('fib'))
+
+            def reg_pit(module):
+                module.add_class('Entry')#, memory_policy=StdSharedPtr('ns3::ndn::nfd::pit::Entry'))
+            reg_pit(module.add_cpp_namespace('pit'))
+
+            def reg_cs(module):
+                module.add_class('Entry')#, memory_policy=StdSharedPtr('ns3::ndn::nfd::cs::Entry'))
+            reg_cs(module.add_cpp_namespace('cs'))
+
+        reg_nfd(module.add_cpp_namespace('nfd'))
+    reg_ndn(module.add_cpp_namespace('ndn'))
 
 def register_methods(root_module):
-    return
+    reg_other_modules(root_module)
+
+    def reg_stackhelper(cls):
+        cls.add_constructor([])
+
+        cls.add_method('Install', 'ns3::Ptr<ns3::ndn::FaceContainer>', [param('ns3::Ptr<ns3::Node>', 'node')], is_const=True)
+        cls.add_method('Install', 'ns3::Ptr<ns3::ndn::FaceContainer>', [param('std::string const&', 'nodeName')], is_const=True)
+        cls.add_method('Install', 'ns3::Ptr<ns3::ndn::FaceContainer>', [param('const ns3::NodeContainer&', 'c')], is_const=True)
+        cls.add_method('InstallAll', 'ns3::Ptr<ns3::ndn::FaceContainer>', [], is_const=True)
+
+        cls.add_method('SetDefaultRoutes', retval('void'), [param('bool', 'isEnabled', default_value='true')], is_const=True)
+        cls.add_method('SetStackAttributes',
+                       retval('void'),
+                       [param('const std::string&', 'attr1', default_value='""'), param('const std::string&', 'value1', default_value='""'),
+                        param('const std::string&', 'attr2', default_value='""'), param('const std::string&', 'value2', default_value='""'),
+                        param('const std::string&', 'attr3', default_value='""'), param('const std::string&', 'value3', default_value='""'),
+                        param('const std::string&', 'attr4', default_value='""'), param('const std::string&', 'value4', default_value='""')])
+
+        cls.add_method('setCsSize', retval('void'), [param('size_t', 'maxSize')])
+        cls.add_method('SetOldContentStore',
+                       retval('void'),
+                       [param('const std::string&', 'contentStoreClass'),
+                        param('const std::string&', 'attr1', default_value='""'), param('const std::string&', 'value1', default_value='""'),
+                        param('const std::string&', 'attr2', default_value='""'), param('const std::string&', 'value2', default_value='""'),
+                        param('const std::string&', 'attr3', default_value='""'), param('const std::string&', 'value3', default_value='""'),
+                        param('const std::string&', 'attr4', default_value='""'), param('const std::string&', 'value4', default_value='""')])
+    reg_stackhelper(root_module['ns3::ndn::StackHelper'])
+
+    def reg_fibhelper(cls):
+        cls.add_method('AddRoute', retval('void'), [
+            param('const std::string&', 'nodeName'), param('const std::string&', 'prefix'),
+            param('uint32_t', 'faceId'), param('int32_t', 'metric'),
+            ], is_const=True, is_static=True)
+        cls.add_method('AddRoute', retval('void'), [
+            param('ns3::Ptr<ns3::Node>', 'node'), param('const ns3::ndn::Name&', 'prefix'),
+            param('uint32_t', 'faceId'), param('int32_t', 'metric')
+            ], is_const=True, is_static=True)
+        cls.add_method('AddRoute', retval('void'), [
+            param('ns3::Ptr<ns3::Node>', 'node'), param('const ns3::ndn::Name&', 'prefix'),
+            param('std::shared_ptr<ns3::ndn::Face>', 'face'),
+            param('int32_t', 'metric'),
+            ], is_const=True, is_static=True)
+        cls.add_method('AddRoute', retval('void'), [
+            param('ns3::Ptr<ns3::Node>', 'node'), param('const ns3::ndn::Name&', 'prefix'),
+            param('ns3::Ptr<ns3::Node>', 'otherNode'),
+            param('int32_t', 'metric'),
+            ], is_const=True, is_static=True)
+        cls.add_method('AddRoute', retval('void'), [
+            param('const std::string&', 'nodeName'), param('const std::string&', 'prefix'),
+            param('const std::string&', 'otherNodeName'),
+            param('int32_t', 'metric'),
+            ], is_const=True, is_static=True)
+    reg_fibhelper(root_module['ns3::ndn::FibHelper'])
+
+    def reg_strategychoicehelper(cls):
+        cls.add_method('Install', retval('void'), [param('ns3::Ptr<ns3::Node>', 'node'),
+                                                   param('const const std::string&', 'name'),
+                                                   param('const const std::string&', 'strategy')], is_const=True, is_static=True)
+        cls.add_method('Install', retval('void'), [param('const ns3::NodeContainer&', 'c'),
+                                                   param('const const std::string&', 'name'),
+                                                   param('const const std::string&', 'strategy')], is_const=True, is_static=True)
+        cls.add_method('InstallAll', retval('void'), [param('const std::string&', 'name'),
+                                                      param('const std::string&', 'strategy')], is_const=True, is_static=True)
+    reg_strategychoicehelper(root_module['ns3::ndn::StrategyChoiceHelper'])
+
+    def reg_apphelper(cls):
+        cls.add_constructor([param('const std::string&', 'prefix')])
+        cls.add_method('SetPrefix', 'void', [param('const std::string&', 'prefix')])
+        cls.add_method('SetAttribute', 'void', [param('std::string', 'name'), param('const ns3::AttributeValue&', 'value')])
+        cls.add_method('Install', 'ns3::ApplicationContainer', [param('ns3::NodeContainer', 'c')])
+        cls.add_method('Install', 'ns3::ApplicationContainer', [param('ns3::Ptr<ns3::Node>', 'node')])
+        cls.add_method('Install', 'ns3::ApplicationContainer', [param('std::string', 'nodeName')])
+    reg_apphelper(root_module['ns3::ndn::AppHelper'])
+
+    def reg_GlobalRoutingHelper(cls):
+        cls.add_constructor([])
+        cls.add_method('Install', 'void', [param('ns3::Ptr<ns3::Node>', 'node')])
+        cls.add_method('Install', 'void', [param('const ns3::NodeContainer&', 'nodes')])
+        cls.add_method('InstallAll', 'void', [])
+        cls.add_method('AddOrigin', 'void', [param('const std::string&', 'prefix'), param('ns3::Ptr<ns3::Node>', 'node')])
+        cls.add_method('AddOrigin', 'void', [param('const std::string&', 'prefix'), param('const std::string&', 'nodeName')])
+        cls.add_method('AddOrigins', 'void', [param('const std::string&', 'prefix'), param('const ns3::NodeContainer&', 'nodes')])
+        cls.add_method('AddOriginsForAll', 'void', [])
+        cls.add_method('CalculateRoutes', 'void', [param('bool', 'invalidatedRoutes', default_value='true')])
+        cls.add_method('CalculateAllPossibleRoutes', 'void', [param('bool', 'invalidatedRoutes', default_value='true')])
+    reg_GlobalRoutingHelper(root_module['ns3::ndn::GlobalRoutingHelper'])
+
+    def reg_Name(root_module, cls):
+        cls.implicitly_converts_to(root_module['ns3::ndn::Interest'])
+        cls.add_output_stream_operator()
+        for op in ['==', '!=', '<', '<=', '>', '>=']:
+            cls.add_binary_comparison_operator(op)
+        cls.add_container_traits(retval('const ns3::ndn::name::Component&'),
+                                 begin_method='begin', end_method='end', iterator_type='const_iterator')
+
+        cls.add_constructor([])
+        cls.add_constructor([param('const ns3::ndn::Name&', 'other')])
+        cls.add_constructor([param('const std::string&', 'url')])
+        cls.add_method('append', 'ns3::ndn::Name &', [param('const ns3::ndn::name::Component&', 'comp')])
+        cls.add_method('get', 'const ns3::ndn::name::Component&', [param('int', 'index')], is_const=True)
+        cls.add_method('getPrefix', 'ns3::ndn::Name', [param('size_t', 'len')], is_const=True)
+        cls.add_method('size', 'size_t', [], is_const=True)
+        cls.add_method('toUri', retval('std::string'), [], is_const=True)
+    reg_Name(root_module, root_module['ns3::ndn::Name'])
+
+    def reg_NameComponent(cls):
+        cls.add_output_stream_operator()
+        for op in ['==', '!=', '<', '<=', '>', '>=']:
+            cls.add_binary_comparison_operator(op)
+
+        cls.add_constructor([param('const ns3::ndn::name::Component&', 'arg0')])
+        cls.add_constructor([])
+        cls.add_method('fromNumber', 'ns3::ndn::name::Component', [param('uint64_t', 'number')])
+        cls.add_method('fromNumberWithMarker', 'ns3::ndn::name::Component', [param('uint64_t', 'number'), param('unsigned char', 'marker')])
+        cls.add_method('fromEscapedString', 'ns3::ndn::name::Component', [param('const std::string&', 'uri')])
+    reg_NameComponent(root_module['ns3::ndn::name::Component'])
+
+    def reg_Interest(cls):
+        cls.add_output_stream_operator()
+
+        cls.add_constructor([param('const ns3::ndn::Interest&', 'interest')])
+        cls.add_constructor([])
+    reg_Interest(root_module['ns3::ndn::Interest'])
+
+    def reg_Data(cls):
+        cls.add_output_stream_operator()
+
+        cls.add_constructor([param('const ns3::ndn::Data&', 'data')])
+        cls.add_constructor([])
+    reg_Data(root_module['ns3::ndn::Data'])
+
+    #########################################################################################
+    ## Interface to NFD
+    #########################################################################################
+
+    def register_L3Protocol(cls):
+        cls.add_method('getL3Protocol', 'ns3::Ptr<ns3::ndn::L3Protocol>', [param('ns3::Ptr<ns3::Object>', 'node')], is_static=True)
+        cls.add_method('getForwarder', 'std::shared_ptr<ns3::ndn::nfd::Forwarder>', [])
+    register_L3Protocol(root_module['ns3::ndn::L3Protocol'])
+
+    def reg_Face(cls):
+        cls.add_output_stream_operator()
+        cls.add_method('getId', retval('int64_t'), [], is_const=True)
+    reg_Face(root_module['ns3::ndn::Face'])
+
+    def reg_NfdForwarder(cls):
+        cls.add_method('getFib', retval('const ns3::ndn::nfd::Fib&', caller_manages_return=False), [], is_const=True)
+        cls.add_method('getPit', retval('const ns3::ndn::nfd::Pit&', caller_manages_return=False), [], is_const=True)
+        cls.add_method('getCs', retval('const ns3::ndn::nfd::Cs&', caller_manages_return=False), [], is_const=True)
+    reg_NfdForwarder(root_module['ns3::ndn::nfd::Forwarder'])
+
+    #############
+    #### FIB ####
+    def reg_NfdFib(root_module, cls):
+        cls.add_method('size', retval('size_t'), [], is_const=True)
+        cls.add_container_traits(retval('const ns3::ndn::nfd::fib::Entry&', caller_manages_return=False),
+                                 begin_method='begin', end_method='end', iterator_type='const_iterator')
+
+        # The following is not supported
+        # cls.add_method('findLongestPrefixMatch', retval('std::shared_ptr<ns3::ndn::nfd::fib::Entry>'),
+        #                [param('const ns3::ndn::Name&', 'prefix')], is_const=True)
+        # cls.add_method('findExactMatch', retval('std::shared_ptr<ns3::ndn::nfd::fib::Entry>'),
+        #                [param('const ns3::ndn::Name&', 'prefix')], is_const=True)
+        # cls.add_method('findLongestPrefixMatch', retval('shared_ptr<ns3::ndn::nfd::fib::Entry>'),
+        #                [param('const pit::Entry&', 'pitEntry')], is_const=True)
+        # cls.add_method('findLongestPrefixMatch', retval('shared_ptr<ns3::ndn::nfd::fib::Entry>'),
+        #                [param('const measurements::Entry&', 'measurementsEntry')], is_const=True)
+
+        # cls.add_method('insert', retval('std::pair<std::shared_ptr<ns3::ndn::nfd::fib::Entry>, bool>'), [param('const ns3::ndn::Name&', 'prefix')])
+        cls.add_method('erase', retval('void'), [param('const ns3::ndn::Name&', 'prefix')])
+        cls.add_method('erase', retval('void'), [param('const ns3::ndn::nfd::fib::Entry&', 'entry')])
+        cls.add_method('removeNextHopFromAllEntries', retval('void'), [param('std::shared_ptr<ns3::ndn::Face>', 'face')])
+
+        def reg_Entry(cls):
+            cls.add_method('getPrefix', 'const ns3::ndn::Name&', [], is_const=True)
+            cls.add_method('getNextHops', retval('const ns3::ndn::nfd::fib::NextHopList&', caller_manages_return=False), [], is_const=True)
+            cls.add_method('hasNextHops', 'bool', [], is_const=True)
+        reg_Entry(root_module['ns3::ndn::nfd::fib::Entry'])
+
+        def reg_NextHop(cls):
+            cls.add_constructor([param('std::shared_ptr<ns3::ndn::Face>', 'face')])
+
+            cls.add_method('getFace', 'std::shared_ptr<ns3::ndn::Face>', [], is_const=True)
+            cls.add_method('setCost', 'void', [param('uint64_t', 'cost')])
+            cls.add_method('getCost', 'uint64_t', [], is_const=True)
+        reg_NextHop(root_module['ns3::ndn::nfd::fib::NextHop'])
+
+        def reg_NextHopList(cls):
+            cls.add_method('size', retval('size_t'), [], is_const=True)
+            cls.add_container_traits(retval('const ns3::ndn::nfd::fib::NextHop&', caller_manages_return=False),
+                                     begin_method='begin', end_method='end', iterator_type='const_iterator')
+        reg_NextHopList(root_module['ns3::ndn::nfd::fib::NextHopList'])
+    reg_NfdFib(root_module, root_module['ns3::ndn::nfd::Fib'])
+    #### FIB ####
+    #############
+
+    #############
+    #### PIT ####
+    def reg_NfdPit(root_module, cls):
+        cls.add_method('size', retval('size_t'), [], is_const=True)
+        cls.add_container_traits(retval('const ns3::ndn::nfd::pit::Entry&', caller_manages_return=False),
+                                 begin_method='begin', end_method='end', iterator_type='const_iterator')
+
+        def reg_Entry(cls):
+            cls.add_method('getInterest', retval('const ns3::ndn::Interest&'), [], is_const=True)
+            cls.add_method('getName', retval('const ns3::ndn::Name&'), [], is_const=True)
+        reg_Entry(root_module['ns3::ndn::nfd::pit::Entry'])
+    reg_NfdPit(root_module, root_module['ns3::ndn::nfd::Pit'])
+    #### PIT ####
+    #############
+
+    #############
+    #### CS ####
+    def reg_NfdCs(root_module, cls):
+        cls.add_method('size', retval('size_t'), [], is_const=True)
+        cls.add_container_traits(retval('const ns3::ndn::nfd::cs::Entry&', caller_manages_return=False),
+                                 begin_method='begin', end_method='end', iterator_type='const_iterator')
+
+        def reg_Entry(cls):
+            cls.add_method('getName', retval('const ns3::ndn::Name&'), [], is_const=True)
+        reg_Entry(root_module['ns3::ndn::nfd::cs::Entry'])
+    reg_NfdCs(root_module, root_module['ns3::ndn::nfd::Cs'])
+    #### CS ####
+    #############
+
+def reg_other_modules(root_module):
+    def reg_ApplicationContainer(cls):
+        cls.add_constructor([])
+        cls.add_constructor([param('ns3::ApplicationContainer', 'container')])
+    reg_ApplicationContainer(root_module['ns3::ApplicationContainer'])
 
 def register_functions(root_module):
     return
@@ -29,4 +315,3 @@
 
 if __name__ == '__main__':
     main()
-
diff --git a/bindings/modulegen__gcc_LP64.py b/bindings/modulegen__gcc_LP64.py
index 09c4b4f..a684069 100644
--- a/bindings/modulegen__gcc_LP64.py
+++ b/bindings/modulegen__gcc_LP64.py
@@ -1,9 +1,12 @@
 from pybindgen import Module, FileCodeSink, param, retval, cppclass, typehandlers
 
+from pybindgen.typehandlers.smart_ptr import StdSharedPtr
+
+from ns3_ptr import Ns3PtrMemoryPolicy
+
 import pybindgen.settings
 import warnings
 
-
 import sys
 
 def module_init():
@@ -11,10 +14,293 @@
     return root_module
 
 def register_types(module):
-    return
+    module.add_class('ObjectBase', allow_subclassing=True, import_from_module='ns.core')
+    module.add_class('SimpleRefCount', automatic_type_narrowing=True, import_from_module='ns.core',
+                     template_parameters=['ns3::Object', 'ns3::ObjectBase', 'ns3::ObjectDeleter'],
+                     parent=module['ns3::ObjectBase'],
+                     memory_policy=cppclass.ReferenceCountingMethodsPolicy(incref_method='Ref', decref_method='Unref', peekref_method='GetReferenceCount'))
+    module.add_class('Object', import_from_module='ns.core', parent=module['ns3::SimpleRefCount< ns3::Object, ns3::ObjectBase, ns3::ObjectDeleter >'])
+
+    module.add_class('TypeId', import_from_module='ns.core')
+    module.add_class('AttributeValue', import_from_module='ns.core')
+
+    module.add_class('NodeContainer', import_from_module='ns.network')
+    module.add_class('Node', import_from_module='ns.network', parent=module['ns3::Object'])
+    module.add_class('ApplicationContainer', import_from_module='ns.network')
+
+    def reg_ndn(module):
+        module.add_class('StackHelper')
+        module.add_class('FibHelper')
+        module.add_class('StrategyChoiceHelper')
+        module.add_class('AppHelper')
+        module.add_class('GlobalRoutingHelper')
+
+        module.add_class('L3Protocol', parent=module.get_root()['ns3::Object'])
+
+        module.add_class('Name')
+        module.add_class('Interest')
+        module.add_class('Data')
+        module.add_class('Face', memory_policy=StdSharedPtr('ns3::ndn::Face'))
+        module.add_class('FaceContainer', memory_policy=Ns3PtrMemoryPolicy('::ns3::ndn::FaceContainer'))
+
+        def reg_name(module):
+            module.add_class('Component')
+        reg_name(module.add_cpp_namespace('name'))
+
+        def reg_nfd(module):
+            module.add_class('Forwarder', memory_policy=StdSharedPtr('::ns3::ndn::nfd::Forwarder'), is_singleton=True)
+            module.add_class('Fib')
+            module.add_class('Pit')
+            module.add_class('Cs')
+
+            def reg_fib(module):
+                module.add_class('Entry')#, memory_policy=StdSharedPtr('ns3::ndn::nfd::fib::Entry'))
+                module.add_class('NextHop')
+                module.add_class('NextHopList')
+            reg_fib(module.add_cpp_namespace('fib'))
+
+            def reg_pit(module):
+                module.add_class('Entry')#, memory_policy=StdSharedPtr('ns3::ndn::nfd::pit::Entry'))
+            reg_pit(module.add_cpp_namespace('pit'))
+
+            def reg_cs(module):
+                module.add_class('Entry')#, memory_policy=StdSharedPtr('ns3::ndn::nfd::cs::Entry'))
+            reg_cs(module.add_cpp_namespace('cs'))
+
+        reg_nfd(module.add_cpp_namespace('nfd'))
+    reg_ndn(module.add_cpp_namespace('ndn'))
 
 def register_methods(root_module):
-    return
+    reg_other_modules(root_module)
+
+    def reg_stackhelper(cls):
+        cls.add_constructor([])
+
+        cls.add_method('Install', 'ns3::Ptr<ns3::ndn::FaceContainer>', [param('ns3::Ptr<ns3::Node>', 'node')], is_const=True)
+        cls.add_method('Install', 'ns3::Ptr<ns3::ndn::FaceContainer>', [param('std::string const&', 'nodeName')], is_const=True)
+        cls.add_method('Install', 'ns3::Ptr<ns3::ndn::FaceContainer>', [param('const ns3::NodeContainer&', 'c')], is_const=True)
+        cls.add_method('InstallAll', 'ns3::Ptr<ns3::ndn::FaceContainer>', [], is_const=True)
+
+        cls.add_method('SetDefaultRoutes', retval('void'), [param('bool', 'isEnabled', default_value='true')], is_const=True)
+        cls.add_method('SetStackAttributes',
+                       retval('void'),
+                       [param('const std::string&', 'attr1', default_value='""'), param('const std::string&', 'value1', default_value='""'),
+                        param('const std::string&', 'attr2', default_value='""'), param('const std::string&', 'value2', default_value='""'),
+                        param('const std::string&', 'attr3', default_value='""'), param('const std::string&', 'value3', default_value='""'),
+                        param('const std::string&', 'attr4', default_value='""'), param('const std::string&', 'value4', default_value='""')])
+
+        cls.add_method('setCsSize', retval('void'), [param('size_t', 'maxSize')])
+        cls.add_method('SetOldContentStore',
+                       retval('void'),
+                       [param('const std::string&', 'contentStoreClass'),
+                        param('const std::string&', 'attr1', default_value='""'), param('const std::string&', 'value1', default_value='""'),
+                        param('const std::string&', 'attr2', default_value='""'), param('const std::string&', 'value2', default_value='""'),
+                        param('const std::string&', 'attr3', default_value='""'), param('const std::string&', 'value3', default_value='""'),
+                        param('const std::string&', 'attr4', default_value='""'), param('const std::string&', 'value4', default_value='""')])
+    reg_stackhelper(root_module['ns3::ndn::StackHelper'])
+
+    def reg_fibhelper(cls):
+        cls.add_method('AddRoute', retval('void'), [
+            param('const std::string&', 'nodeName'), param('const std::string&', 'prefix'),
+            param('uint32_t', 'faceId'), param('int32_t', 'metric'),
+            ], is_const=True, is_static=True)
+        cls.add_method('AddRoute', retval('void'), [
+            param('ns3::Ptr<ns3::Node>', 'node'), param('const ns3::ndn::Name&', 'prefix'),
+            param('uint32_t', 'faceId'), param('int32_t', 'metric')
+            ], is_const=True, is_static=True)
+        cls.add_method('AddRoute', retval('void'), [
+            param('ns3::Ptr<ns3::Node>', 'node'), param('const ns3::ndn::Name&', 'prefix'),
+            param('std::shared_ptr<ns3::ndn::Face>', 'face'),
+            param('int32_t', 'metric'),
+            ], is_const=True, is_static=True)
+        cls.add_method('AddRoute', retval('void'), [
+            param('ns3::Ptr<ns3::Node>', 'node'), param('const ns3::ndn::Name&', 'prefix'),
+            param('ns3::Ptr<ns3::Node>', 'otherNode'),
+            param('int32_t', 'metric'),
+            ], is_const=True, is_static=True)
+        cls.add_method('AddRoute', retval('void'), [
+            param('const std::string&', 'nodeName'), param('const std::string&', 'prefix'),
+            param('const std::string&', 'otherNodeName'),
+            param('int32_t', 'metric'),
+            ], is_const=True, is_static=True)
+    reg_fibhelper(root_module['ns3::ndn::FibHelper'])
+
+    def reg_strategychoicehelper(cls):
+        cls.add_method('Install', retval('void'), [param('ns3::Ptr<ns3::Node>', 'node'),
+                                                   param('const const std::string&', 'name'),
+                                                   param('const const std::string&', 'strategy')], is_const=True, is_static=True)
+        cls.add_method('Install', retval('void'), [param('const ns3::NodeContainer&', 'c'),
+                                                   param('const const std::string&', 'name'),
+                                                   param('const const std::string&', 'strategy')], is_const=True, is_static=True)
+        cls.add_method('InstallAll', retval('void'), [param('const std::string&', 'name'),
+                                                      param('const std::string&', 'strategy')], is_const=True, is_static=True)
+    reg_strategychoicehelper(root_module['ns3::ndn::StrategyChoiceHelper'])
+
+    def reg_apphelper(cls):
+        cls.add_constructor([param('const std::string&', 'prefix')])
+        cls.add_method('SetPrefix', 'void', [param('const std::string&', 'prefix')])
+        cls.add_method('SetAttribute', 'void', [param('std::string', 'name'), param('const ns3::AttributeValue&', 'value')])
+        cls.add_method('Install', 'ns3::ApplicationContainer', [param('ns3::NodeContainer', 'c')])
+        cls.add_method('Install', 'ns3::ApplicationContainer', [param('ns3::Ptr<ns3::Node>', 'node')])
+        cls.add_method('Install', 'ns3::ApplicationContainer', [param('std::string', 'nodeName')])
+    reg_apphelper(root_module['ns3::ndn::AppHelper'])
+
+    def reg_GlobalRoutingHelper(cls):
+        cls.add_constructor([])
+        cls.add_method('Install', 'void', [param('ns3::Ptr<ns3::Node>', 'node')])
+        cls.add_method('Install', 'void', [param('const ns3::NodeContainer&', 'nodes')])
+        cls.add_method('InstallAll', 'void', [])
+        cls.add_method('AddOrigin', 'void', [param('const std::string&', 'prefix'), param('ns3::Ptr<ns3::Node>', 'node')])
+        cls.add_method('AddOrigin', 'void', [param('const std::string&', 'prefix'), param('const std::string&', 'nodeName')])
+        cls.add_method('AddOrigins', 'void', [param('const std::string&', 'prefix'), param('const ns3::NodeContainer&', 'nodes')])
+        cls.add_method('AddOriginsForAll', 'void', [])
+        cls.add_method('CalculateRoutes', 'void', [param('bool', 'invalidatedRoutes', default_value='true')])
+        cls.add_method('CalculateAllPossibleRoutes', 'void', [param('bool', 'invalidatedRoutes', default_value='true')])
+    reg_GlobalRoutingHelper(root_module['ns3::ndn::GlobalRoutingHelper'])
+
+    def reg_Name(root_module, cls):
+        cls.implicitly_converts_to(root_module['ns3::ndn::Interest'])
+        cls.add_output_stream_operator()
+        for op in ['==', '!=', '<', '<=', '>', '>=']:
+            cls.add_binary_comparison_operator(op)
+        cls.add_container_traits(retval('const ns3::ndn::name::Component&'),
+                                 begin_method='begin', end_method='end', iterator_type='const_iterator')
+
+        cls.add_constructor([])
+        cls.add_constructor([param('const ns3::ndn::Name&', 'other')])
+        cls.add_constructor([param('const std::string&', 'url')])
+        cls.add_method('append', 'ns3::ndn::Name &', [param('const ns3::ndn::name::Component&', 'comp')])
+        cls.add_method('get', 'const ns3::ndn::name::Component&', [param('int', 'index')], is_const=True)
+        cls.add_method('getPrefix', 'ns3::ndn::Name', [param('size_t', 'len')], is_const=True)
+        cls.add_method('size', 'size_t', [], is_const=True)
+        cls.add_method('toUri', retval('std::string'), [], is_const=True)
+    reg_Name(root_module, root_module['ns3::ndn::Name'])
+
+    def reg_NameComponent(cls):
+        cls.add_output_stream_operator()
+        for op in ['==', '!=', '<', '<=', '>', '>=']:
+            cls.add_binary_comparison_operator(op)
+
+        cls.add_constructor([param('const ns3::ndn::name::Component&', 'arg0')])
+        cls.add_constructor([])
+        cls.add_method('fromNumber', 'ns3::ndn::name::Component', [param('uint64_t', 'number')])
+        cls.add_method('fromNumberWithMarker', 'ns3::ndn::name::Component', [param('uint64_t', 'number'), param('unsigned char', 'marker')])
+        cls.add_method('fromEscapedString', 'ns3::ndn::name::Component', [param('const std::string&', 'uri')])
+    reg_NameComponent(root_module['ns3::ndn::name::Component'])
+
+    def reg_Interest(cls):
+        cls.add_output_stream_operator()
+
+        cls.add_constructor([param('const ns3::ndn::Interest&', 'interest')])
+        cls.add_constructor([])
+    reg_Interest(root_module['ns3::ndn::Interest'])
+
+    def reg_Data(cls):
+        cls.add_output_stream_operator()
+
+        cls.add_constructor([param('const ns3::ndn::Data&', 'data')])
+        cls.add_constructor([])
+    reg_Data(root_module['ns3::ndn::Data'])
+
+    #########################################################################################
+    ## Interface to NFD
+    #########################################################################################
+
+    def register_L3Protocol(cls):
+        cls.add_method('getL3Protocol', 'ns3::Ptr<ns3::ndn::L3Protocol>', [param('ns3::Ptr<ns3::Object>', 'node')], is_static=True)
+        cls.add_method('getForwarder', 'std::shared_ptr<ns3::ndn::nfd::Forwarder>', [])
+    register_L3Protocol(root_module['ns3::ndn::L3Protocol'])
+
+    def reg_Face(cls):
+        cls.add_output_stream_operator()
+        cls.add_method('getId', retval('int64_t'), [], is_const=True)
+    reg_Face(root_module['ns3::ndn::Face'])
+
+    def reg_NfdForwarder(cls):
+        cls.add_method('getFib', retval('const ns3::ndn::nfd::Fib&', caller_manages_return=False), [], is_const=True)
+        cls.add_method('getPit', retval('const ns3::ndn::nfd::Pit&', caller_manages_return=False), [], is_const=True)
+        cls.add_method('getCs', retval('const ns3::ndn::nfd::Cs&', caller_manages_return=False), [], is_const=True)
+    reg_NfdForwarder(root_module['ns3::ndn::nfd::Forwarder'])
+
+    #############
+    #### FIB ####
+    def reg_NfdFib(root_module, cls):
+        cls.add_method('size', retval('size_t'), [], is_const=True)
+        cls.add_container_traits(retval('const ns3::ndn::nfd::fib::Entry&', caller_manages_return=False),
+                                 begin_method='begin', end_method='end', iterator_type='const_iterator')
+
+        # The following is not supported
+        # cls.add_method('findLongestPrefixMatch', retval('std::shared_ptr<ns3::ndn::nfd::fib::Entry>'),
+        #                [param('const ns3::ndn::Name&', 'prefix')], is_const=True)
+        # cls.add_method('findExactMatch', retval('std::shared_ptr<ns3::ndn::nfd::fib::Entry>'),
+        #                [param('const ns3::ndn::Name&', 'prefix')], is_const=True)
+        # cls.add_method('findLongestPrefixMatch', retval('shared_ptr<ns3::ndn::nfd::fib::Entry>'),
+        #                [param('const pit::Entry&', 'pitEntry')], is_const=True)
+        # cls.add_method('findLongestPrefixMatch', retval('shared_ptr<ns3::ndn::nfd::fib::Entry>'),
+        #                [param('const measurements::Entry&', 'measurementsEntry')], is_const=True)
+
+        # cls.add_method('insert', retval('std::pair<std::shared_ptr<ns3::ndn::nfd::fib::Entry>, bool>'), [param('const ns3::ndn::Name&', 'prefix')])
+        cls.add_method('erase', retval('void'), [param('const ns3::ndn::Name&', 'prefix')])
+        cls.add_method('erase', retval('void'), [param('const ns3::ndn::nfd::fib::Entry&', 'entry')])
+        cls.add_method('removeNextHopFromAllEntries', retval('void'), [param('std::shared_ptr<ns3::ndn::Face>', 'face')])
+
+        def reg_Entry(cls):
+            cls.add_method('getPrefix', 'const ns3::ndn::Name&', [], is_const=True)
+            cls.add_method('getNextHops', retval('const ns3::ndn::nfd::fib::NextHopList&', caller_manages_return=False), [], is_const=True)
+            cls.add_method('hasNextHops', 'bool', [], is_const=True)
+        reg_Entry(root_module['ns3::ndn::nfd::fib::Entry'])
+
+        def reg_NextHop(cls):
+            cls.add_constructor([param('std::shared_ptr<ns3::ndn::Face>', 'face')])
+
+            cls.add_method('getFace', 'std::shared_ptr<ns3::ndn::Face>', [], is_const=True)
+            cls.add_method('setCost', 'void', [param('uint64_t', 'cost')])
+            cls.add_method('getCost', 'uint64_t', [], is_const=True)
+        reg_NextHop(root_module['ns3::ndn::nfd::fib::NextHop'])
+
+        def reg_NextHopList(cls):
+            cls.add_method('size', retval('size_t'), [], is_const=True)
+            cls.add_container_traits(retval('const ns3::ndn::nfd::fib::NextHop&', caller_manages_return=False),
+                                     begin_method='begin', end_method='end', iterator_type='const_iterator')
+        reg_NextHopList(root_module['ns3::ndn::nfd::fib::NextHopList'])
+    reg_NfdFib(root_module, root_module['ns3::ndn::nfd::Fib'])
+    #### FIB ####
+    #############
+
+    #############
+    #### PIT ####
+    def reg_NfdPit(root_module, cls):
+        cls.add_method('size', retval('size_t'), [], is_const=True)
+        cls.add_container_traits(retval('const ns3::ndn::nfd::pit::Entry&', caller_manages_return=False),
+                                 begin_method='begin', end_method='end', iterator_type='const_iterator')
+
+        def reg_Entry(cls):
+            cls.add_method('getInterest', retval('const ns3::ndn::Interest&'), [], is_const=True)
+            cls.add_method('getName', retval('const ns3::ndn::Name&'), [], is_const=True)
+        reg_Entry(root_module['ns3::ndn::nfd::pit::Entry'])
+    reg_NfdPit(root_module, root_module['ns3::ndn::nfd::Pit'])
+    #### PIT ####
+    #############
+
+    #############
+    #### CS ####
+    def reg_NfdCs(root_module, cls):
+        cls.add_method('size', retval('size_t'), [], is_const=True)
+        cls.add_container_traits(retval('const ns3::ndn::nfd::cs::Entry&', caller_manages_return=False),
+                                 begin_method='begin', end_method='end', iterator_type='const_iterator')
+
+        def reg_Entry(cls):
+            cls.add_method('getName', retval('const ns3::ndn::Name&'), [], is_const=True)
+        reg_Entry(root_module['ns3::ndn::nfd::cs::Entry'])
+    reg_NfdCs(root_module, root_module['ns3::ndn::nfd::Cs'])
+    #### CS ####
+    #############
+
+def reg_other_modules(root_module):
+    def reg_ApplicationContainer(cls):
+        cls.add_constructor([])
+        cls.add_constructor([param('ns3::ApplicationContainer', 'container')])
+    reg_ApplicationContainer(root_module['ns3::ApplicationContainer'])
 
 def register_functions(root_module):
     return
@@ -29,4 +315,3 @@
 
 if __name__ == '__main__':
     main()
-
diff --git a/bindings/ns3_ptr.py b/bindings/ns3_ptr.py
new file mode 100644
index 0000000..b23cbaa
--- /dev/null
+++ b/bindings/ns3_ptr.py
@@ -0,0 +1,304 @@
+
+from pybindgen.typehandlers.base import Parameter, ReturnValue, \
+    join_ctype_and_name, CodeGenerationError, \
+    param_type_matcher, return_type_matcher, CodegenErrorBase, \
+    DeclarationsScope, CodeBlock, NotSupportedError, ForwardWrapperBase, ReverseWrapperBase, \
+    TypeConfigurationError
+
+from pybindgen.cppclass import ReferenceCountingMethodsPolicy, CppClass, CppClassParameterBase, CppClassReturnValueBase, common_shared_object_return
+
+class Ns3PtrMemoryPolicy(ReferenceCountingMethodsPolicy):
+    def __init__(self, class_name):
+        """
+        Create a memory policy for using ns3::Ptr<> to manage instances of this object.
+
+        :param class_name: the full name of the class, e.g. foo::Bar
+        """
+        super(Ns3PtrMemoryPolicy, self).__init__('Ref', 'Unref', 'GetReferenceCount')
+
+        self.class_name = class_name
+        self.pointer_template = 'ns3::Ptr< %s >'
+
+    def get_pointer_name(self, class_name):
+        return self.pointer_template % (class_name,)
+
+    def get_delete_code(self, cpp_class):
+        return "self->obj.~Ptr< %s >();" % (cpp_class.full_name,)
+
+    def get_pointer_type(self, class_full_name):
+        return self.get_pointer_name(class_full_name) + ' '
+
+    def get_pointer_to_void_name(self, object_name):
+        return "::ns3::PeekPointer(%s)" % object_name
+
+    def get_instance_creation_function(self):
+        return ns3_ptr_instance_creation_function
+
+    def get_pystruct_init_code(self, cpp_class, obj):
+        return "new(&%s->obj) %s;" % (obj, self.get_pointer_name(cpp_class.full_name),)
+
+    def register_ptr_parameter_and_return(self, cls, name):
+        class ThisClassNs3PtrParameter(CppClassNs3PtrParameter):
+            """Register this C++ class as pass-by-pointer parameter"""
+            CTYPES = []
+            cpp_class = cls
+        cls.ThisClassNs3PtrParameter = ThisClassNs3PtrParameter
+        try:
+            param_type_matcher.register(self.get_pointer_name(cls.full_name), cls.ThisClassNs3PtrParameter)
+        except ValueError:
+            pass
+
+        class ThisClassNs3PtrReturn(CppClassNs3PtrReturnValue):
+            """Register this C++ class as pointer return"""
+            CTYPES = []
+            cpp_class = cls
+        cls.ThisClassNs3PtrReturn = ThisClassNs3PtrReturn
+        try:
+            return_type_matcher.register(self.get_pointer_name(cls.full_name), cls.ThisClassNs3PtrReturn)
+        except ValueError:
+            pass
+
+    def register_ptr_alias_parameter_and_return(self, cls, alias):
+        alias_ptr = '::ns3::Ptr< %s >' % alias
+        cls.ThisClassNs3PtrParameter.CTYPES.append(alias_ptr)
+        try:
+            param_type_matcher.register(alias_ptr, cls.ThisClassNs3PtrParameter)
+        except ValueError: pass
+
+        cls.ThisClassNs3PtrReturn.CTYPES.append(alias_ptr)
+        try:
+            return_type_matcher.register(alias_ptr, cls.ThisClassNs3PtrReturn)
+        except ValueError: pass
+
+def ns3_ptr_instance_creation_function(cpp_class, code_block, lvalue,
+                                       parameters, construct_type_name):
+    """
+    ns3::Ptr "instance creation function"; it is called whenever a new
+    C++ class instance needs to be created
+
+    :param cpp_class: the CppClass object whose instance is to be created
+    :param code_block: CodeBlock object on which the instance creation code should be generated
+    :param lvalue: lvalue expression that should hold the result in the end
+    :param parameters: stringified list of parameters
+    :param construct_type_name: actual name of type to be constructed (it is
+                          not always the class name, sometimes it's
+                          the python helper class)
+    """
+    assert lvalue
+    assert not lvalue.startswith('None')
+    if cpp_class.incomplete_type:
+        raise CodeGenerationError("%s cannot be constructed (incomplete type)"
+                                  % cpp_class.full_name)
+    code_block.write_code(
+        "%s = ::ns3::Create<%s>(%s);" % (lvalue, construct_type_name, parameters))
+
+class CppClassNs3PtrParameter(CppClassParameterBase):
+    "Class* handlers"
+    CTYPES = []
+    cpp_class = None #cppclass.CppClass('dummy') # CppClass instance
+    DIRECTIONS = [Parameter.DIRECTION_IN,
+                  Parameter.DIRECTION_OUT,
+                  Parameter.DIRECTION_INOUT]
+    SUPPORTS_TRANSFORMATIONS = False
+
+    def __init__(self, ctype, name, direction=Parameter.DIRECTION_IN, is_const=False,
+                 null_ok=False, default_value=None):
+        super(CppClassNs3PtrParameter, self).__init__(
+            ctype, name, direction, is_const, default_value)
+        self.null_ok = null_ok
+
+
+    def convert_python_to_c(self, wrapper):
+        "parses python args to get C++ value"
+        assert isinstance(wrapper, ForwardWrapperBase)
+        assert isinstance(self.cpp_class, CppClass)
+
+        self.py_name = wrapper.declarations.declare_variable(
+            self.cpp_class.pystruct+'*', self.name,
+            initializer=(self.default_value and 'NULL' or None))
+
+        value_ptr = wrapper.declarations.declare_variable(
+            self.cpp_class.memory_policy.get_pointer_name(self.cpp_class.full_name), "%s_ptr" % self.name)
+
+        if self.null_ok:
+            num = wrapper.parse_params.add_parameter('O', ['&'+self.py_name], self.name, optional=bool(self.default_value))
+
+            wrapper.before_call.write_error_check(
+
+                "%s && ((PyObject *) %s != Py_None) && !PyObject_IsInstance((PyObject *) %s, (PyObject *) &%s)"
+                % (self.py_name, self.py_name, self.py_name, self.cpp_class.pytypestruct),
+
+                'PyErr_SetString(PyExc_TypeError, "Parameter %i must be of type %s");' % (num, self.cpp_class.name))
+
+            wrapper.before_call.write_code("if (%(PYNAME)s) {\n"
+                                           "    if ((PyObject *) %(PYNAME)s == Py_None)\n"
+                                           "        %(VALUE)s = NULL;\n"
+                                           "    else\n"
+                                           "        %(VALUE)s = %(PYNAME)s->obj;\n"
+                                           "} else {\n"
+                                           "    %(VALUE)s = NULL;\n"
+                                           "}" % dict(PYNAME=self.py_name, VALUE=value_ptr))
+
+        else:
+
+            wrapper.parse_params.add_parameter(
+                'O!', ['&'+self.cpp_class.pytypestruct, '&'+self.py_name], self.name, optional=bool(self.default_value))
+            wrapper.before_call.write_code("if (%s) { %s = %s->obj; }" % (self.py_name, value_ptr, self.py_name))
+
+        wrapper.call_params.append(value_ptr)
+
+
+
+    def convert_c_to_python(self, wrapper):
+        """foo"""
+
+        ## Value transformations
+        value = self.transformation.untransform(
+            self, wrapper.declarations, wrapper.after_call, self.value)
+
+        ## declare wrapper variable
+        py_name = wrapper.declarations.declare_variable(
+            self.cpp_class.pystruct+'*', 'py_'+self.cpp_class.name)
+        self.py_name = py_name
+
+        def write_create_new_wrapper():
+            """Code path that creates a new wrapper for the parameter"""
+
+            ## Find out what Python wrapper to use, in case
+            ## automatic_type_narrowing is active and we are not forced to
+            ## make a copy of the object
+            if self.cpp_class.automatic_type_narrowing:
+
+                typeid_map_name = self.cpp_class.get_type_narrowing_root().typeid_map_name
+                wrapper_type = wrapper.declarations.declare_variable(
+                    'PyTypeObject*', 'wrapper_type', '0')
+                wrapper.before_call.write_code(
+                    '%s = %s.lookup_wrapper(typeid(*%s), &%s);'
+                    % (wrapper_type, typeid_map_name, value, self.cpp_class.memory_policy.get_pointer_to_void_name(self.cpp_class.pytypestruct)))
+            else:
+                wrapper_type = '&'+self.cpp_class.pytypestruct
+
+            ## Create the Python wrapper object
+            self.cpp_class.write_allocate_pystruct(wrapper.before_call, py_name, wrapper_type)
+            self.py_name = py_name
+
+            wrapper.before_call.write_code("%s->flags = PYBINDGEN_WRAPPER_FLAG_NONE;" % py_name)
+
+            ## Assign the C++ value to the Python wrapper
+            wrapper.before_call.write_code("%s->obj = %s;" % (py_name, value))
+
+        if self.cpp_class.helper_class is None:
+            try:
+                self.cpp_class.wrapper_registry.write_lookup_wrapper(
+                    wrapper.before_call, self.cpp_class.pystruct, py_name, value)
+            except NotSupportedError:
+                write_create_new_wrapper()
+                self.cpp_class.wrapper_registry.write_register_new_wrapper(wrapper.before_call, py_name,
+                                                                           "%s->obj" % py_name)
+            else:
+                wrapper.before_call.write_code("if (%s == NULL)\n{" % py_name)
+                wrapper.before_call.indent()
+                write_create_new_wrapper()
+                self.cpp_class.wrapper_registry.write_register_new_wrapper(wrapper.before_call, py_name,
+                                                                           "%s->obj" % py_name)
+                wrapper.before_call.unindent()
+                wrapper.before_call.write_code('}')
+            wrapper.build_params.add_parameter("N", [py_name])
+        else:
+            wrapper.before_call.write_code("if (typeid(*(%s)).name() == typeid(%s).name())\n{"
+                                          % (value, self.cpp_class.helper_class.name))
+            wrapper.before_call.indent()
+
+            if self.type_traits.target_is_const:
+                wrapper.before_call.write_code(
+                    "%s = (%s*) (((%s*) ((%s*) %s))->m_pyself);"
+                    % (py_name, self.cpp_class.pystruct,
+                       self.cpp_class.helper_class.name, self.cpp_class.full_name, value))
+                wrapper.before_call.write_code("%s->obj =  (%s*) (%s);" %
+                                               (py_name, self.cpp_class.full_name, value))
+            else:
+                wrapper.before_call.write_code(
+                    "%s = (%s*) (((%s*) %s)->m_pyself);"
+                    % (py_name, self.cpp_class.pystruct,
+                       self.cpp_class.helper_class.name, value))
+                wrapper.before_call.write_code("%s->obj = %s;" % (py_name, value))
+            wrapper.before_call.write_code("Py_INCREF(%s);" % py_name)
+            wrapper.before_call.unindent()
+            wrapper.before_call.write_code("} else {")
+            wrapper.before_call.indent()
+
+            try:
+                self.cpp_class.wrapper_registry.write_lookup_wrapper(
+                    wrapper.before_call, self.cpp_class.pystruct, py_name, value)
+            except NotSupportedError:
+                write_create_new_wrapper()
+                self.cpp_class.wrapper_registry.write_register_new_wrapper(
+                    wrapper.before_call, py_name, "%s->obj" % py_name)
+            else:
+                wrapper.before_call.write_code("if (%s == NULL)\n{" % py_name)
+                wrapper.before_call.indent()
+                write_create_new_wrapper()
+                self.cpp_class.wrapper_registry.write_register_new_wrapper(wrapper.before_call, py_name,
+                                                                           "%s->obj" % py_name)
+                wrapper.before_call.unindent()
+                wrapper.before_call.write_code('}') # closes if (%s == NULL)
+
+            wrapper.before_call.unindent()
+            wrapper.before_call.write_code("}") # closes if (typeid(*(%s)) == typeid(%s))\n{
+            wrapper.build_params.add_parameter("N", [py_name])
+
+
+
+
+class CppClassNs3PtrReturnValue(CppClassReturnValueBase):
+    "Class* return handler"
+    CTYPES = []
+    SUPPORTS_TRANSFORMATIONS = True
+    cpp_class = None #cppclass.CppClass('dummy') # CppClass instance
+
+    def __init__(self, ctype, is_const=False):
+        super(CppClassNs3PtrReturnValue, self).__init__(ctype, is_const=is_const)
+
+    def get_c_error_return(self): # only used in reverse wrappers
+        """See ReturnValue.get_c_error_return"""
+        return "return NULL;"
+
+    def convert_c_to_python(self, wrapper):
+        """See ReturnValue.convert_c_to_python"""
+
+        ## Value transformations
+        value = self.transformation.untransform(
+            self, wrapper.declarations, wrapper.after_call, self.value)
+
+        # if value is NULL, return None
+        wrapper.after_call.write_code("if (!(%s)) {\n"
+                                      "    Py_INCREF(Py_None);\n"
+                                      "    return Py_None;\n"
+                                      "}" % value)
+
+        ## declare wrapper variable
+        py_name = wrapper.declarations.declare_variable(
+            self.cpp_class.pystruct+'*', 'py_'+self.cpp_class.name)
+        self.py_name = py_name
+
+        common_shared_object_return(value, py_name, self.cpp_class, wrapper.after_call,
+                                    self.type_traits, caller_owns_return=True,
+                                    reference_existing_object=False,
+                                    type_is_pointer=True)
+
+        # return the value
+        wrapper.build_params.add_parameter("N", [py_name], prepend=True)
+
+
+    def convert_python_to_c(self, wrapper):
+        """See ReturnValue.convert_python_to_c"""
+        name = wrapper.declarations.declare_variable(
+            self.cpp_class.pystruct+'*', "tmp_%s" % self.cpp_class.name)
+        wrapper.parse_params.add_parameter(
+            'O!', ['&'+self.cpp_class.pytypestruct, '&'+name])
+
+        value = self.transformation.transform(
+            self, wrapper.declarations, wrapper.after_call, "%s->obj" % name)
+
+        # caller gets a shared pointer
+        wrapper.after_call.write_code("%s = %s;" % (self.value, value))