Exemple #1
0
def ttree_Branch(space, w_self, args_w):
    """Pythonized version of TTree::Branch(): takes proxy objects and by-passes
    the CINT-manual layer."""

    from pypy.module.cppyy import interp_cppyy
    tree_class = interp_cppyy.scope_byname(space, "TTree")

    # sigs to modify (and by-pass CINT):
    #  1. (const char*, const char*, T**,               Int_t=32000, Int_t=99)
    #  2. (const char*, T**,                            Int_t=32000, Int_t=99)
    argc = len(args_w)

    # basic error handling of wrong arguments is best left to the original call,
    # so that error messages etc. remain consistent in appearance: the following
    # block may raise TypeError or IndexError to break out anytime

    try:
        if argc < 2 or 5 < argc:
            raise TypeError("wrong number of arguments")

        tree = space.interp_w(interp_cppyy.W_CPPInstance, w_self, can_be_None=True)
        if (tree is None) or (tree.cppclass != tree_class):
            raise TypeError("not a TTree")

        # first argument must always always be cont char*
        branchname = space.str_w(args_w[0])

        # if args_w[1] is a classname, then case 1, else case 2
        try:
            classname = space.str_w(args_w[1])
            addr_idx  = 2
            w_address = args_w[addr_idx]
        except (OperationError, TypeError):
            addr_idx  = 1
            w_address = args_w[addr_idx]

        bufsize, splitlevel = 32000, 99
        if addr_idx+1 < argc: bufsize = space.c_int_w(args_w[addr_idx+1])
        if addr_idx+2 < argc: splitlevel = space.c_int_w(args_w[addr_idx+2])

        # now retrieve the W_CPPInstance and build other stub arguments
        space = tree.space    # holds the class cache in State
        cppinstance = space.interp_w(interp_cppyy.W_CPPInstance, w_address)
        address = rffi.cast(rffi.VOIDP, cppinstance.get_rawobject())
        klassname = cppinstance.cppclass.full_name()
        vtree = rffi.cast(rffi.VOIDP, tree.get_rawobject())

        # call the helper stub to by-pass CINT
        vbranch = _ttree_Branch(vtree, branchname, klassname, address, bufsize, splitlevel)
        branch_class = interp_cppyy.scope_byname(space, "TBranch")
        w_branch = interp_cppyy.wrap_cppobject(space, vbranch, branch_class)
        return w_branch
    except (OperationError, TypeError, IndexError):
        pass

    # return control back to the original, unpythonized overload
    ol = tree_class.get_overload("Branch")
    return ol.call(w_self, args_w)
Exemple #2
0
 def test01_class_query(self, space):
     # NOTE: this test needs to run before test_pythonify.py
     dct = interp_cppyy.load_dictionary(space, test_dct)
     w_cppyyclass = interp_cppyy.scope_byname(space, "example01")
     w_cppyyclass2 = interp_cppyy.scope_byname(space, "example01")
     assert space.is_w(w_cppyyclass, w_cppyyclass2)
     adddouble = w_cppyyclass.methods["staticAddToDouble"]
     func, = adddouble.functions
     assert func.executor is None
     func._setup(None)  # creates executor
     assert isinstance(func.executor, executor._executors['double'])
     assert func.arg_defs == [("double", "")]
Exemple #3
0
 def test01_class_query(self):
     # NOTE: this test needs to run before test_pythonify.py
     dct = interp_cppyy.load_dictionary(space, test_dct)
     w_cppyyclass = interp_cppyy.scope_byname(space, "example01")
     w_cppyyclass2 = interp_cppyy.scope_byname(space, "example01")
     assert space.is_w(w_cppyyclass, w_cppyyclass2)
     adddouble = w_cppyyclass.methods["staticAddToDouble"]
     func, = adddouble.functions
     assert func.executor is None
     func._setup(None)     # creates executor
     assert isinstance(func.executor, executor.DoubleExecutor)
     assert func.arg_defs == [("double", "")]
Exemple #4
0
def tf1_tf1(space, w_self, args_w):
    """Pythonized version of TF1 constructor:
    takes functions and callable objects, and allows a callback into them."""

    from pypy.module.cppyy import interp_cppyy
    tf1_class = interp_cppyy.scope_byname(space, "TF1")

    # expected signature:
    #  1. (char* name, pyfunc, double xmin, double xmax, int npar = 0)
    argc = len(args_w)

    try:
        if argc < 4 or 5 < argc:
            raise TypeError("wrong number of arguments")

        # first argument must be a name
        funcname = space.str_w(args_w[0])

        # last (optional) argument is number of parameters
        npar = 0
        if argc == 5: npar = space.int_w(args_w[4])

        # second argument must be a callable python object
        w_callable = args_w[1]
        if not space.is_true(space.callable(w_callable)):
            raise TypeError("2nd argument is not a valid python callable")

        # generate a pointer to function
        from pypy.module._cffi_backend import newtype, ctypefunc, func

        c_double  = newtype.new_primitive_type(space, 'double')
        c_doublep = newtype.new_pointer_type(space, c_double)

        # wrap the callable as the signature needs modifying
        w_ifunc = interp_cppyy.get_interface_func(space, w_callable, npar)

        w_cfunc = ctypefunc.W_CTypeFunc(space, [c_doublep, c_doublep], c_double, False)
        w_callback = func.callback(space, w_cfunc, w_ifunc, None)
        funcaddr = rffi.cast(rffi.ULONG, w_callback.get_closure())

        # so far, so good; leaves on issue: CINT is expecting a wrapper, but
        # we need the overload that takes a function pointer, which is not in
        # the dictionary, hence this helper:
        newinst = _create_tf1(space.str_w(args_w[0]), funcaddr,
                      space.float_w(args_w[2]), space.float_w(args_w[3]), npar)

        # w_self is a null-ptr bound as TF1 
        from pypy.module.cppyy.interp_cppyy import W_CPPInstance, memory_regulator
        cppself = space.interp_w(W_CPPInstance, w_self, can_be_None=False)
        cppself._rawobject = newinst
        memory_regulator.register(cppself)

        # tie all the life times to the TF1 instance
        space.setattr(w_self, space.wrap('_callback'), w_callback)

        # by definition for __init__
        return None

    except (OperationError, TypeError, IndexError), e:
        newargs_w = args_w[1:]     # drop class
def get_converter(space, name, default):
    # The matching of the name to a converter should follow:
    #   1) full, exact match
    #       1a) const-removed match
    #   2) match of decorated, unqualified type
    #   3) accept ref as pointer (for the stubs, const& can be
    #       by value, but that does not work for the ffi path)
    #   4) generalized cases (covers basically all user classes)
    #   5) void converter, which fails on use

    name = capi.c_resolve_name(space, name)

    #   1) full, exact match
    try:
        return _converters[name](space, default)
    except KeyError:
        pass

    #   1a) const-removed match
    try:
        return _converters[helper.remove_const(name)](space, default)
    except KeyError:
        pass

    #   2) match of decorated, unqualified type
    compound = helper.compound(name)
    clean_name = capi.c_resolve_name(space, helper.clean_type(name))
    try:
        # array_index may be negative to indicate no size or no size found
        array_size = helper.array_size(name)
        return _a_converters[clean_name + compound](space, array_size)
    except KeyError:
        pass

    #   3) TODO: accept ref as pointer

    #   4) generalized cases (covers basically all user classes)
    from pypy.module.cppyy import interp_cppyy
    cppclass = interp_cppyy.scope_byname(space, clean_name)
    if cppclass:
        # type check for the benefit of the annotator
        from pypy.module.cppyy.interp_cppyy import W_CPPClass
        cppclass = space.interp_w(W_CPPClass, cppclass, can_be_None=False)
        if compound == "*":
            return InstancePtrConverter(space, cppclass)
        elif compound == "&":
            return InstanceRefConverter(space, cppclass)
        elif compound == "**":
            return InstancePtrPtrConverter(space, cppclass)
        elif compound == "":
            return InstanceConverter(space, cppclass)
    elif capi.c_is_enum(space, clean_name):
        return _converters['unsigned'](space, default)

    #   5) void converter, which fails on use
    #
    # return a void converter here, so that the class can be build even
    # when some types are unknown; this overload will simply fail on use
    return VoidConverter(space, name)
Exemple #6
0
def get_converter(space, name, default):
    # The matching of the name to a converter should follow:
    #   1) full, exact match
    #       1a) const-removed match
    #   2) match of decorated, unqualified type
    #   3) accept ref as pointer (for the stubs, const& can be
    #       by value, but that does not work for the ffi path)
    #   4) generalized cases (covers basically all user classes)
    #   5) void converter, which fails on use

    name = capi.c_resolve_name(space, name)

    #   1) full, exact match
    try:
        return _converters[name](space, default)
    except KeyError:
        pass

    #   1a) const-removed match
    try:
        return _converters[helper.remove_const(name)](space, default)
    except KeyError:
        pass

    #   2) match of decorated, unqualified type
    compound = helper.compound(name)
    clean_name = capi.c_resolve_name(space, helper.clean_type(name))
    try:
        # array_index may be negative to indicate no size or no size found
        array_size = helper.array_size(name)
        return _a_converters[clean_name+compound](space, array_size)
    except KeyError:
        pass

    #   3) TODO: accept ref as pointer

    #   4) generalized cases (covers basically all user classes)
    from pypy.module.cppyy import interp_cppyy
    cppclass = interp_cppyy.scope_byname(space, clean_name)
    if cppclass:
        # type check for the benefit of the annotator
        from pypy.module.cppyy.interp_cppyy import W_CPPClass
        cppclass = space.interp_w(W_CPPClass, cppclass, can_be_None=False)
        if compound == "*":
            return InstancePtrConverter(space, cppclass)
        elif compound == "&":
            return InstanceRefConverter(space, cppclass)
        elif compound == "**":
            return InstancePtrPtrConverter(space, cppclass)
        elif compound == "":
            return InstanceConverter(space, cppclass)
    elif capi.c_is_enum(space, clean_name):
        return _converters['unsigned'](space, default)

    #   5) void converter, which fails on use
    #
    # return a void converter here, so that the class can be build even
    # when some types are unknown; this overload will simply fail on use
    return VoidConverter(space, name)
Exemple #7
0
def get_executor(space, name):
    # Matching of 'name' to an executor factory goes through up to four levels:
    #   1) full, qualified match
    #   2) drop '&': by-ref is pretty much the same as by-value, python-wise
    #   3) types/classes, either by ref/ptr or by value
    #   4) additional special cases
    #
    # If all fails, a default is used, which can be ignored at least until use.

    name = capi.c_resolve_name(space, name)

    #   1) full, qualified match
    try:
        return _executors[name](space, None)
    except KeyError:
        pass

    compound = helper.compound(name)
    clean_name = capi.c_resolve_name(space, helper.clean_type(name))

    #   1a) clean lookup
    try:
        return _executors[clean_name + compound](space, None)
    except KeyError:
        pass

    #   2) drop '&': by-ref is pretty much the same as by-value, python-wise
    if compound and compound[len(compound) - 1] == '&':
        # TODO: this does not actually work with Reflex (?)
        try:
            return _executors[clean_name](space, None)
        except KeyError:
            pass

    #   3) types/classes, either by ref/ptr or by value
    from pypy.module.cppyy import interp_cppyy
    cppclass = interp_cppyy.scope_byname(space, clean_name)
    if cppclass:
        # type check for the benefit of the annotator
        from pypy.module.cppyy.interp_cppyy import W_CPPClass
        cppclass = space.interp_w(W_CPPClass, cppclass, can_be_None=False)
        if compound == '':
            return InstanceExecutor(space, cppclass)
        elif compound == '*' or compound == '&':
            return InstancePtrExecutor(space, cppclass)
        elif compound == '**' or compound == '*&':
            return InstancePtrPtrExecutor(space, cppclass)
    elif capi.c_is_enum(space, clean_name):
        return _executors['unsigned int'](space, None)

    # 4) additional special cases
    if compound == '*':
        return _executors['void*'](
            space, None)  # allow at least passing of the pointer

    # currently used until proper lazy instantiation available in interp_cppyy
    return FunctionExecutor(space, None)
Exemple #8
0
def get_executor(space, name):
    # Matching of 'name' to an executor factory goes through up to four levels:
    #   1) full, qualified match
    #   2) drop '&': by-ref is pretty much the same as by-value, python-wise
    #   3) types/classes, either by ref/ptr or by value
    #   4) additional special cases
    #
    # If all fails, a default is used, which can be ignored at least until use.

    name = capi.c_resolve_name(space, name)

    #   1) full, qualified match
    try:
        return _executors[name](space, None)
    except KeyError:
        pass

    compound = helper.compound(name)
    clean_name = capi.c_resolve_name(space, helper.clean_type(name))

    #   1a) clean lookup
    try:
        return _executors[clean_name+compound](space, None)
    except KeyError:
        pass

    #   2) drop '&': by-ref is pretty much the same as by-value, python-wise
    if compound and compound[len(compound)-1] == '&':
        # TODO: this does not actually work with Reflex (?)
        try:
            return _executors[clean_name](space, None)
        except KeyError:
            pass

    #   3) types/classes, either by ref/ptr or by value
    from pypy.module.cppyy import interp_cppyy
    cppclass = interp_cppyy.scope_byname(space, clean_name)
    if cppclass:
        # type check for the benefit of the annotator
        from pypy.module.cppyy.interp_cppyy import W_CPPClass
        cppclass = space.interp_w(W_CPPClass, cppclass, can_be_None=False)
        if compound == '':
            return InstanceExecutor(space, cppclass)
        elif compound == '*' or compound == '&':
            return InstancePtrExecutor(space, cppclass)
        elif compound == '**' or compound == '*&':
            return InstancePtrPtrExecutor(space, cppclass)
    elif capi.c_is_enum(space, clean_name):
        return _executors['unsigned int'](space, None)

    # 4) additional special cases
    if compound == '*':
        return _executors['void*'](space, None)  # allow at least passing of the pointer

    # currently used until proper lazy instantiation available in interp_cppyy
    return FunctionExecutor(space, None)
Exemple #9
0
 def f():
     lib = interp_cppyy.load_dictionary(space, "./example01Dict.so")
     cls  = interp_cppyy.scope_byname(space, "example01")
     inst = cls.get_overload("example01").call(None, [FakeInt(0)])
     cppmethod = cls.get_overload(method_name)
     assert isinstance(inst, interp_cppyy.W_CPPInstance)
     i = 10
     while i > 0:
         drv.jit_merge_point(inst=inst, cppmethod=cppmethod, i=i)
         cppmethod.call(inst, [FakeInt(i)])
         i -= 1
     return 7
Exemple #10
0
 def f():
     lib = interp_cppyy.load_dictionary(space, "./example01Dict.so")
     cls  = interp_cppyy.scope_byname(space, "example01")
     inst = cls.get_overload("example01").call(None, [FakeInt(0)])
     cppmethod = cls.get_overload(method_name)
     assert isinstance(inst, interp_cppyy.W_CPPInstance)
     i = 10
     while i > 0:
         drv.jit_merge_point(inst=inst, cppmethod=cppmethod, i=i)
         cppmethod.call(inst, [FakeInt(i)])
         i -= 1
     return 7
Exemple #11
0
 def __init__(self, space, extra):
     from pypy.module.cppyy import interp_cppyy
     cppclass = interp_cppyy.scope_byname(space, "TString")
     InstanceConverter.__init__(self, space, cppclass)
Exemple #12
0
def ttree_getattr(space, w_self, args_w):
    """Specialized __getattr__ for TTree's that allows switching on/off the
    reading of individual branchs."""

    from pypy.module.cppyy import interp_cppyy
    tree = space.interp_w(interp_cppyy.W_CPPInstance, w_self)

    space = tree.space            # holds the class cache in State

    # prevent recursion
    attr = space.str_w(args_w[0])
    if attr and attr[0] == '_':
        raise OperationError(space.w_AttributeError, args_w[0])

    # try the saved cdata (for builtin types)
    try:
        w_cdata = space.getattr(w_self, space.wrap('_'+attr))
        from pypy.module._cffi_backend import cdataobj
        cdata = space.interp_w(cdataobj.W_CData, w_cdata, can_be_None=False)
        return cdata.convert_to_object()
    except OperationError:
        pass

    # setup branch as a data member and enable it for reading
    w_branch = space.call_method(w_self, "GetBranch", args_w[0])
    if not space.is_true(w_branch):
        raise OperationError(space.w_AttributeError, args_w[0])
    activate_branch(space, w_branch)

    # figure out from where we're reading
    entry = space.int_w(space.call_method(w_self, "GetReadEntry"))
    if entry == -1:
        entry = 0

    # setup cache structure
    w_klassname = space.call_method(w_branch, "GetClassName")
    if space.is_true(w_klassname):
        # some instance
        klass = interp_cppyy.scope_byname(space, space.str_w(w_klassname))
        w_obj = klass.construct()
        space.call_method(w_branch, "SetObject", w_obj)
        space.call_method(w_branch, "GetEntry", space.wrap(entry))
        space.setattr(w_self, args_w[0], w_obj)
        return w_obj
    else:
        # builtin data
        w_leaf = space.call_method(w_self, "GetLeaf", args_w[0])
        space.call_method(w_branch, "GetEntry", space.wrap(entry))

        # location
        w_address = space.call_method(w_leaf, "GetValuePointer")
        buf = space.buffer_w(w_address)
        from pypy.module._rawffi import buffer
        assert isinstance(buf, buffer.RawFFIBuffer)
        address = rffi.cast(rffi.CCHARP, buf.datainstance.ll_buffer)

        # placeholder
        w_typename = space.call_method(w_leaf, "GetTypeName" )
        from pypy.module.cppyy import capi
        typename = capi.c_resolve_name(space, space.str_w(w_typename))
        if typename == 'bool': typename = '_Bool'
        w_address = space.call_method(w_leaf, "GetValuePointer")
        from pypy.module._cffi_backend import cdataobj, newtype
        cdata = cdataobj.W_CData(space, address, newtype.new_primitive_type(space, typename))

        # cache result
        space.setattr(w_self, space.wrap('_'+attr), space.wrap(cdata))
        return space.getattr(w_self, args_w[0])
Exemple #13
0
 def __init__(self, space, cppclass):
     from pypy.module.cppyy import interp_cppyy
     cppclass = interp_cppyy.scope_byname(space, capi.std_string_name)
     InstancePtrExecutor.__init__(self, space, cppclass)
Exemple #14
0
def tf1_tf1(space, w_self, args_w):
    """Pythonized version of TF1 constructor:
    takes functions and callable objects, and allows a callback into them."""

    from pypy.module.cppyy import interp_cppyy
    tf1_class = interp_cppyy.scope_byname(space, "TF1")

    # expected signature:
    #  1. (char* name, pyfunc, double xmin, double xmax, int npar = 0)
    argc = len(args_w)

    try:
        if argc < 4 or 5 < argc:
            raise TypeError("wrong number of arguments")

        # first argument must be a name
        funcname = space.str_w(args_w[0])

        # last (optional) argument is number of parameters
        npar = 0
        if argc == 5: npar = space.int_w(args_w[4])

        # second argument must be a callable python object
        w_callable = args_w[1]
        if not space.is_true(space.callable(w_callable)):
            raise TypeError("2nd argument is not a valid python callable")

        # generate a pointer to function
        from pypy.module._cffi_backend import newtype, ctypefunc, func

        c_double = newtype.new_primitive_type(space, 'double')
        c_doublep = newtype.new_pointer_type(space, c_double)

        # wrap the callable as the signature needs modifying
        w_ifunc = interp_cppyy.get_interface_func(space, w_callable, npar)

        w_cfunc = ctypefunc.W_CTypeFunc(space, [c_doublep, c_doublep],
                                        c_double, False)
        w_callback = func.callback(space, w_cfunc, w_ifunc, None)
        funcaddr = rffi.cast(rffi.ULONG, w_callback.get_closure())

        # so far, so good; leaves on issue: CINT is expecting a wrapper, but
        # we need the overload that takes a function pointer, which is not in
        # the dictionary, hence this helper:
        newinst = _create_tf1(space.str_w(args_w[0]), funcaddr,
                              space.float_w(args_w[2]),
                              space.float_w(args_w[3]), npar)

        # w_self is a null-ptr bound as TF1
        from pypy.module.cppyy.interp_cppyy import W_CPPInstance, memory_regulator
        cppself = space.interp_w(W_CPPInstance, w_self, can_be_None=False)
        cppself._rawobject = newinst
        memory_regulator.register(cppself)

        # tie all the life times to the TF1 instance
        space.setattr(w_self, space.wrap('_callback'), w_callback)

        # by definition for __init__
        return None

    except (OperationError, TypeError, IndexError), e:
        newargs_w = args_w[1:]  # drop class
 def __init__(self, space, extra):
     from pypy.module.cppyy import interp_cppyy
     cppclass = interp_cppyy.scope_byname(space, "TString")
     InstanceConverter.__init__(self, space, cppclass)
Exemple #16
0
def ttree_Branch(space, w_self, args_w):
    """Pythonized version of TTree::Branch(): takes proxy objects and by-passes
    the CINT-manual layer."""

    from pypy.module.cppyy import interp_cppyy
    tree_class = interp_cppyy.scope_byname(space, "TTree")

    # sigs to modify (and by-pass CINT):
    #  1. (const char*, const char*, T**,               Int_t=32000, Int_t=99)
    #  2. (const char*, T**,                            Int_t=32000, Int_t=99)
    argc = len(args_w)

    # basic error handling of wrong arguments is best left to the original call,
    # so that error messages etc. remain consistent in appearance: the following
    # block may raise TypeError or IndexError to break out anytime

    try:
        if argc < 2 or 5 < argc:
            raise TypeError("wrong number of arguments")

        tree = space.interp_w(interp_cppyy.W_CPPInstance,
                              w_self,
                              can_be_None=True)
        if (tree is None) or (tree.cppclass != tree_class):
            raise TypeError("not a TTree")

        # first argument must always always be cont char*
        branchname = space.str_w(args_w[0])

        # if args_w[1] is a classname, then case 1, else case 2
        try:
            classname = space.str_w(args_w[1])
            addr_idx = 2
            w_address = args_w[addr_idx]
        except (OperationError, TypeError):
            addr_idx = 1
            w_address = args_w[addr_idx]

        bufsize, splitlevel = 32000, 99
        if addr_idx + 1 < argc: bufsize = space.c_int_w(args_w[addr_idx + 1])
        if addr_idx + 2 < argc:
            splitlevel = space.c_int_w(args_w[addr_idx + 2])

        # now retrieve the W_CPPInstance and build other stub arguments
        space = tree.space  # holds the class cache in State
        cppinstance = space.interp_w(interp_cppyy.W_CPPInstance, w_address)
        address = rffi.cast(rffi.VOIDP, cppinstance.get_rawobject())
        klassname = cppinstance.cppclass.full_name()
        vtree = rffi.cast(rffi.VOIDP, tree.get_rawobject())

        # call the helper stub to by-pass CINT
        vbranch = _ttree_Branch(vtree, branchname, klassname, address, bufsize,
                                splitlevel)
        branch_class = interp_cppyy.scope_byname(space, "TBranch")
        w_branch = interp_cppyy.wrap_cppobject(space, vbranch, branch_class)
        return w_branch
    except (OperationError, TypeError, IndexError):
        pass

    # return control back to the original, unpythonized overload
    ol = tree_class.get_overload("Branch")
    return ol.call(w_self, args_w)
 def __init__(self, space, extra):
     from pypy.module.cppyy import interp_cppyy
     cppclass = interp_cppyy.scope_byname(space, capi.std_string_name)
     InstancePtrConverter.__init__(self, space, cppclass)
Exemple #18
0
def ttree_getattr(space, w_self, args_w):
    """Specialized __getattr__ for TTree's that allows switching on/off the
    reading of individual branchs."""

    from pypy.module.cppyy import interp_cppyy
    tree = space.interp_w(interp_cppyy.W_CPPInstance, w_self)

    space = tree.space  # holds the class cache in State

    # prevent recursion
    attr = space.str_w(args_w[0])
    if attr and attr[0] == '_':
        raise OperationError(space.w_AttributeError, args_w[0])

    # try the saved cdata (for builtin types)
    try:
        w_cdata = space.getattr(w_self, space.wrap('_' + attr))
        from pypy.module._cffi_backend import cdataobj
        cdata = space.interp_w(cdataobj.W_CData, w_cdata, can_be_None=False)
        return cdata.convert_to_object()
    except OperationError:
        pass

    # setup branch as a data member and enable it for reading
    w_branch = space.call_method(w_self, "GetBranch", args_w[0])
    if not space.is_true(w_branch):
        raise OperationError(space.w_AttributeError, args_w[0])
    activate_branch(space, w_branch)

    # figure out from where we're reading
    entry = space.r_longlong_w(space.call_method(w_self, "GetReadEntry"))
    if entry == -1:
        entry = 0

    # setup cache structure
    w_klassname = space.call_method(w_branch, "GetClassName")
    if space.is_true(w_klassname):
        # some instance
        klass = interp_cppyy.scope_byname(space, space.str_w(w_klassname))
        w_obj = klass.construct()
        # 0x10000 = kDeleteObject; reset because we own the object
        space.call_method(w_branch, "ResetBit", space.wrap(0x10000))
        space.call_method(w_branch, "SetObject", w_obj)
        space.call_method(w_branch, "GetEntry", space.wrap(entry))
        space.setattr(w_self, args_w[0], w_obj)
        return w_obj
    else:
        # builtin data
        w_leaf = space.call_method(w_self, "GetLeaf", args_w[0])
        space.call_method(w_branch, "GetEntry", space.wrap(entry))

        # location
        w_address = space.call_method(w_leaf, "GetValuePointer")
        buf = space.getarg_w('s*', w_address)
        from pypy.module._rawffi import buffer
        assert isinstance(buf, buffer.RawFFIBuffer)
        address = rffi.cast(rffi.CCHARP, buf.datainstance.ll_buffer)

        # placeholder
        w_typename = space.call_method(w_leaf, "GetTypeName")
        from pypy.module.cppyy import capi
        typename = capi.c_resolve_name(space, space.str_w(w_typename))
        if typename == 'bool': typename = '_Bool'
        w_address = space.call_method(w_leaf, "GetValuePointer")
        from pypy.module._cffi_backend import cdataobj, newtype
        cdata = cdataobj.W_CData(space, address,
                                 newtype.new_primitive_type(space, typename))

        # cache result
        space.setattr(w_self, space.wrap('_' + attr), space.wrap(cdata))
        return space.getattr(w_self, args_w[0])