Pointers.cpp
// Pointers.cpp
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2007
#include "Ceda/cxUtils/TracerUtils.h"
@import "Ceda/cxPython/cxPython.h"
///////////////////////////////////////////////////////////////////////////////////////////////////
/*
Pointers
--------
Pointer values are wrapped in PyObjects, allowing pointers to be passed around from within
Python.
Type checking is performed at run time. In the example below the int32* return value cannot be
passed into a function taking a float64*.
*/
namespace Pointers1
{
$function+ ceda::int32* ReturnPtr()
{
static ceda::int32 x = 10;
return &x;
}
$function+ void PassPtr(ceda::int32* x)
{
Tracer() << "PassPtr : *x = " << *x << '\n';
}
$function+ void PassFloat64Ptr(ceda::float64* x)
{
}
void Run()
{
ceda::TraceGroup g("Pointers example 1");
Tracer() << "ReturnPtr() = " << ReturnPtr() << "\n\n";
PyRun_SimpleString(
@strx
(
ns = rootnamespace.Pointers1
# The pointer return value is wrapped in a PyObject.
p = ns.ReturnPtr()
# prints the value of the pointer. Eg '004262F4' on 32 bit platform
print 'p = ' + `p`
# Pointers of a compatible type can be passed into functions
ns.PassPtr( p )
# Causes TypeError at run time : Cannot assign float64* from int32*
try:
ns.PassFloat64Ptr( p )
except TypeError as e:
print("Caught " + type(e).__name__ + ": " + str(e))
));
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
/*
Within Python a pointer to a signed integer can be reinterpreted as a pointer to an unsigned
integer of the same size and vice versa.
*/
namespace Pointers2
{
$function+ ceda::int32* ReturnPtr()
{
static ceda::int32 x = -1;
return &x;
}
$function+ void PassPtr(ceda::uint32* x)
{
Tracer() << "PassPtr : *x = " << *x << '\n';
}
void Run()
{
ceda::TraceGroup g("Pointers to signed/unsigned integers");
PyRun_SimpleString(
@strx
(
ns = rootnamespace.Pointers2
ns.PassPtr( ns.ReturnPtr() )
));
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
/*
Null Pointers are always represented using Py_None.
Note therefore that null pointers carry no type information. In the example below, Python happily
allow the null int8* to be passed into a function taking a float64*
*/
namespace Pointers3
{
$function+ ceda::int8* ReturnNull()
{
return NULL;
}
$function+ void PassPtr(ceda::float64* p)
{
Tracer() << "PassPtr : p = " << (void*) p << '\n';
}
void Run()
{
ceda::TraceGroup g("Null pointers");
PyRun_SimpleString(
@strx
(
ns = rootnamespace.Pointers3
p = ns.ReturnNull()
if p:
print 'p is not null'
else:
print 'p is null'
ns.PassPtr( p )
ns.PassPtr( None )
));
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
/*
Class pointers
--------------
A reflected class may be returned by value or pointer without having any impact on the syntax
used for accessing reflected member variables or methods or accessing implemented interfaces.
*/
namespace Pointers4
{
$struct+ X
{
X(ceda::int32 v=0) : val(v) {}
$ceda::int32 val;
};
$function+ X ReturnX()
{
return X(100);
}
$function+ X* ReturnXPtr()
{
static X x(200);
return &x;
}
$function+ void IncVal(X* px)
{
++px->val;
}
void Run()
{
ceda::TraceGroup g("Class/struct pointers");
PyRun_SimpleString(
@strx
(
ns = rootnamespace.Pointers4
@def m(x) =
{
print @str(x.val = ) + `x.val`
x.val = x.val + 10
ns.IncVal(x)
print @str(x.val = ) + `x.val`
}
x1 = ns.ReturnX()
m(x1)
x2 = ns.ReturnXPtr()
m(x2)
));
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
/*
References
----------
Generally speaking references are treated like pointers. The main difference is that Py_None
cannot be passed to a function taking a reference. This error is trapped at run time.
*/
namespace Pointers5
{
$function+ ceda::int32& ReturnRef()
{
static ceda::int32 x = 10;
return x;
}
$function+ void Inc(ceda::int32& x)
{
++x;
}
void Run()
{
ceda::TraceGroup g("References");
PyRun_SimpleString(
@strx
(
ns = rootnamespace.Pointers5
ns.Inc(ns.ReturnRef())
# TypeError : Cant initialise reference int32& from None
# ns.Inc(None)
));
Tracer() << "x = " << ReturnRef() << '\n';
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
/*
Implicit indirections
---------------------
Indirections are implicitly performed on pointers in order to coerce into references or values
Output:
Return Val Pass Val : 1
Return Ptr Pass Val : 2
Return Ref Pass Val : 3
Return Const Val Pass Val : 4
Return Const Ptr Pass Val : 5
Return Const Ref Pass Val : 6
Return Val Pass ConstVal : 1
Return Ptr Pass ConstVal : 2
Return Ref Pass ConstVal : 3
Return Const Val Pass ConstVal : 4
Return Const Ptr Pass ConstVal : 5
Return Const Ref Pass ConstVal : 6
Return Val Pass ConstPtr : 1
Return Ptr Pass ConstPtr : 2
Return Ref Pass ConstPtr : 3
Return Const Val Pass ConstPtr : 4
Return Const Ptr Pass ConstPtr : 5
Return Const Ref Pass ConstPtr : 6
Return Val Pass ConstRef : 1
Return Ptr Pass ConstRef : 2
Return Ref Pass ConstRef : 3
Return Const Val Pass ConstRef : 4
Return Const Ptr Pass ConstRef : 5
Return Const Ref Pass ConstRef : 6
Return Ptr Pass Ptr : 2
Return Ref Pass Ptr : 3
Return Ptr Pass Ref : 2
Return Ref Pass Ref : 3
*/
namespace Pointers6
{
$function+ void PassVal(ceda::int32 v)
{
Tracer() << "Pass Val : " << v << '\n';
}
$function+ void PassPtr(ceda::int32* v)
{
Tracer() << "Pass Ptr : " << *v << '\n';
}
$function+ void PassRef(ceda::int32& v)
{
Tracer() << "Pass Ref : " << v << '\n';
}
$function+ void PassConstVal(const ceda::int32 v)
{
Tracer() << "Pass ConstVal : " << v << '\n';
}
$function+ void PassConstPtr(const ceda::int32* v)
{
Tracer() << "Pass ConstPtr : " << *v << '\n';
}
$function+ void PassConstRef(const ceda::int32& v)
{
Tracer() << "Pass ConstRef : " << v << '\n';
}
$function+ ceda::int32 ReturnVal()
{
Tracer() << "Return Val ";
return 1;
}
$function+ ceda::int32* ReturnPtr()
{
Tracer() << "Return Ptr ";
static ceda::int32 s = 2;
return &s;
}
$function+ ceda::int32& ReturnRef()
{
Tracer() << "Return Ref ";
static ceda::int32 s = 3;
return s;
}
$function+ const ceda::int32 ReturnConstVal()
{
Tracer() << "Return Const Val";
return 4;
}
$function+ const ceda::int32* ReturnConstPtr()
{
Tracer() << "Return Const Ptr";
static ceda::int32 s = 5;
return &s;
}
$function+ const ceda::int32& ReturnConstRef()
{
Tracer() << "Return Const Ref";
static ceda::int32 s = 6;
return s;
}
void Run()
{
ceda::TraceGroup g("Implicit indirections");
PyRun_SimpleString(
@strx
(
ns = rootnamespace.Pointers6
ns.PassVal(ns.ReturnVal())
ns.PassVal(ns.ReturnPtr())
ns.PassVal(ns.ReturnRef())
ns.PassVal(ns.ReturnConstVal())
ns.PassVal(ns.ReturnConstPtr())
ns.PassVal(ns.ReturnConstRef())
ns.PassConstVal(ns.ReturnVal())
ns.PassConstVal(ns.ReturnPtr())
ns.PassConstVal(ns.ReturnRef())
ns.PassConstVal(ns.ReturnConstVal())
ns.PassConstVal(ns.ReturnConstPtr())
ns.PassConstVal(ns.ReturnConstRef())
ns.PassConstPtr(ns.ReturnVal())
ns.PassConstPtr(ns.ReturnPtr())
ns.PassConstPtr(ns.ReturnRef())
ns.PassConstPtr(ns.ReturnConstVal())
ns.PassConstPtr(ns.ReturnConstPtr())
ns.PassConstPtr(ns.ReturnConstRef())
ns.PassConstRef(ns.ReturnVal())
ns.PassConstRef(ns.ReturnPtr())
ns.PassConstRef(ns.ReturnRef())
ns.PassConstRef(ns.ReturnConstVal())
ns.PassConstRef(ns.ReturnConstPtr())
ns.PassConstRef(ns.ReturnConstRef())
ns.PassPtr(ns.ReturnPtr())
ns.PassPtr(ns.ReturnRef())
ns.PassRef(ns.ReturnPtr())
ns.PassRef(ns.ReturnRef())
# Error. Const cast
#ns.PassPtr(ns.ReturnConstPtr())
#ns.PassRef(ns.ReturnConstPtr())
#ns.PassPtr(ns.ReturnConstRef())
#ns.PassRef(ns.ReturnConstRef())
# Error. Cannot convert from value to mutable pointer
#ns.PassPtr(ns.ReturnVal())
#ns.PassPtr(ns.ReturnConstVal())
#ns.PassRef(ns.ReturnVal())
#ns.PassRef(ns.ReturnConstVal())
));
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
namespace Pointers
{
void Run()
{
Pointers1::Run();
Pointers2::Run();
Pointers3::Run();
Pointers4::Run();
Pointers5::Run();
Pointers6::Run();
}
}