Models.cpp
// Models.cpp
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2009
@import "Ceda/cxPython/cxPython.h"
@import "Ceda/cxWorkingSetIpc/WorkingSetIPC.h"
@import "Ceda/cxOperation/IWorkingSetMachine.h"
@import "Ceda/cxPersistStore/IPersistStore.h"
@import "Ceda/cxPersistStore/pref.h"
@import "Ceda/cxObject/Object.h"
@import "Ceda/cxObject/IObjectVisitor.h"
@import "Ceda/cxObject/WCSpace.h"
@import "Ceda/cxObject/PrintReflectedVariable.h"
#include "Ceda/cxUtils/TracerUtils.h"
namespace MVectorsInModels
{
$model+ V
{
ceda::int32 v1[2][3];
ceda::int32 v2;
};
$struct+ X isa ceda::IPersistable :
model
{
V vs[3];
bool b;
ceda::int8 i8;
ceda::int16 i16;
ceda::int32 i32;
ceda::int64 i64;
ceda::uint8 ui8;
ceda::uint16 ui16;
ceda::uint32 ui32;
ceda::uint64 ui64;
ceda::float32 f32;
ceda::float64 f64;
ceda::xvector<ceda::int32> U;
ceda::xvector<ceda::pref<ceda::IObject> > L;
}
{
};
$function+ X* AsX(ceda::ptr<ceda::IObject> obj)
{
return ceda::tryqccast<X>(obj);
}
void Run()
{
ceda::TraceGroup g("MVectors in models example 2");
PyRun_SimpleString(
@strx
(
import time
ns = rootnamespace.MVectorsInModels
X = ns.X
class Txn(object):
def __init__(self, cspace):
self.cspace = cspace
def __enter__(self):
self.cspace.Lock(ceda.ECSpaceLockMode.Transaction)
def __exit__(self, etype, value, tb):
if etype is not None: # an exception has occurred
traceback.print_exception(etype, value, tb)
# We do not allow transactions to be automatically committed when exceptions are
# raised, it is too easy for an invalid state to be committed to the database
# The safest thing to do is to exit the process without comitting the transaction.
sys.exit(-1)
self.cspace.Unlock()
# Open the store
try:
# todo - write a portable function to get a temp folder in all platforms
path = 'models.ced'
print `dir(ceda.EOpenMode)`
s = ceda.LssSettings()
s.flushTimeMilliSec = 500
s = ceda.PersistStoreSettings()
s.lssSettings.flushTimeMilliSec = 500
print 's = ' + `s`
print 'Opening store ' + path
pstore = ceda.OpenPersistStore(path, ceda.EOpenMode.OM_CREATE_ALWAYS, s)
except RuntimeError, e:
print e
raise e
# Open a PSpace
print 'Opening pspace'
pspace = ceda.OpenPSpace(pstore, "MyPSpace", ceda.EOpenMode.OM_CREATE_ALWAYS, None)
if pspace is not None:
print 'pspace non null, value is ' + str(pspace)
cspace = pspace.GetCSpace()
if cspace is not None:
print 'cspace non null, value is ' + str(cspace)
else:
raise RuntimeError('cspace is null')
else:
raise RuntimeError('pspace is null')
ceda.SetThreadPSpace(pspace)
ceda.SetThreadCSpace(cspace)
cs = ceda.GetThreadCSpace()
# Create two working sets
print 'Opening two working sets'
with Txn(cs):
ws1 = ceda.OpenWorkingSetMachine("WS1", True)
ws2 = ceda.OpenWorkingSetMachine("WS2", False)
# Create server and client
with Txn(cs):
protocolId = ceda.MakeWsipcSessionProtocolId("exPython2", 1)
print('protocolId = {}'.format(protocolId))
port = 3000
sessionSettings = ceda.TcpMsgSessionSettings()
print('Creating server listening on port ' + str(port))
reuse_addr = True
ep = ceda.CreateWsipcEndPoint(ws1, protocolId, ceda.WsipcHostInfo())
server = ceda.CreateTcpMsgServer(ceda.EProtocol.TCP_IPv4, port, reuse_addr, ep, sessionSettings)
hostname = "127.0.0.1"
print('Creating client connecting to ' + str(hostname) + ':' + str(port))
ep = ceda.CreateWsipcEndPoint(ws2, protocolId, ceda.WsipcHostInfo())
client = ceda.CreateTcpMsgClient(hostname, str(port), ep, sessionSettings)
# Bootstrap an X under the UT root
with Txn(cs):
r = ws1.GetUTRoot()
# Illustrate bottom up construction of a data model
x = X.new()
x.b = True
x.i8 = 8
x.i16 = 16
x.i32 = 32
x.i64 = 64
x.ui8 = 8
x.ui16 = 16
x.ui32 = 32
x.ui64 = 64
x.f32 = 32.2
x.f64 = 64.2
#x.vs[1].v1[0][2] = 100
x.vs[1].v2 = 200
x.U.extend(range(10,15)*2)
x.U.remove(11)
y = X.new()
#y.vs[2].v1[1][1] = 10
y.vs[1].v2 = 20
y.L.insert(0,X.new())
y.L.insert(1,X.new())
x.L.insert(0,y)
#todo: UTRoot is now a map, but maps arent reflected
#r.insert(0,x)
#r.Map["x"] = x
ceda.SetUTRootEntry(r, "x", x)
# Wait long enough for convergence
time.sleep(0.1)
print 'Showing result on ws2\n'
with Txn(cs):
r2 = ws2.GetUTRoot()
#todo: UTRoot is now a map
#x = r.at(0).self
z = ceda.GetUTRootEntry(r2, 'x')
print 'z = ' + `z`
with Txn(cs):
a = ceda.GetUTRootEntry(r, 'x')
rc = a.GetReflectedClass()
b = ns.AsX(a)
#print 'b = ' + `b`
print 'dir(b) = ' + `dir(b)`
print 'b.i32 = ' + `b.i32`
# TODO work out why this doesnt work
#with Txn(cs):
# z = ceda.GetUTRootEntry(r2, 'x')
# print 'z = ' + `z`
ceda.CloseTcpMsgServer(server)
ceda.CloseTcpMsgClient(client)
with Txn(cs):
ws1.Close()
ws2.Close()
pspace.Close()
pstore.Close()
));
}
}
/*
TODO: 20 May 2009. This crashes with heap coruption because currently the xvector<T> implementation of
operational transform assumes that T is a Plain Old Data (POD) type.
*/
namespace VectorsOfStringsInModels
{
$struct+ X isa ceda::IPersistable :
model
{
ceda::string8 s;
ceda::xvector<ceda::string8> L;
}
{
};
void Run()
{
ceda::TraceGroup g("Vectors of strings in models");
ceda::CSpaceCreator cspace;
ceda::CSpaceLock lock;
PyRun_SimpleString(
@strx
(
import time
ns = rootnamespace.VectorsOfStringsInModels
X = ns.X
x = X.new()
x.s = 'hello'
x.L.insert(0, "hello")
print 'x = ' + `x`
));
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
/*
Lachlan's example
*/
namespace Tbu
{
$model+ Point
{
ceda::int32 x;
ceda::int32 y;
};
$model+ FreestandingModel
{
ceda::float32 val;
ceda::float32 array2d[2][2];
Point X[2][3][3];
float32 array1d[2];
Point px;
};
$struct+ Ds isa ceda::IPersistable :
model
{
FreestandingModel m;
}
{
$void SetFsm( const FreestandingModel& fsm )
{
_model_.m = fsm;
}
};
$function+ void FsmByRef(FreestandingModel& fsm)
{
fsm.val = 100;
}
$function+ void FsmByVal(FreestandingModel fsm)
{
fsm.val = 101;
}
void Run()
{
ceda::TraceGroup g("Tbu example");
ceda::CSpaceCreator cspace;
PyRun_SimpleString(
@strx
(
cspace = rootnamespace.ceda.GetThreadCSpace()
cspace.Lock( 1 )
fsm = rootnamespace.Tbu.FreestandingModel()
rootnamespace.Tbu.FsmByRef(fsm)
print `fsm`
rootnamespace.Tbu.FsmByVal(fsm)
print `fsm`
# Can assign a value to a member of a freestanding model
fsm.val = 50
# Can assign a value to an array member of a freestanding model
fsm.array1d[0] = 30;
fsm.array2d[0][0] = 31;
fsm.array2d[0][1] = 21;
print 'len = ' + `len(fsm.array2d[0])`
print 'fsm.array2d[0][1] = ' + `fsm.array2d[0][1]`
print 'fsm.array2d = ' + `fsm.array2d`
p = rootnamespace.Tbu.Point()
p.x = 1000
p.y = 2000
fsm.px = p
print `fsm`
ds = rootnamespace.Tbu.Ds.new()
# ERROR 2: Cant assign model to a datasource member (is this to be expected?)
# source/Ceda/cxPython/src/WrapModelStructVar.cpp(354): **** Assertion failure : cxAssert(0)
#ds.m = fsm
# This works (but is ugly)...
ds.SetFsm(fsm)
# ERROR 3: Cant call a function taking a reference to the model type, when passing
# a member of a datasource.
# TypeError: Cannot assign Tbu::FreestandingModel* from non pointer type
#rootnamespace.Tbu.FsmByRef(ds.m)
# ERROR 4: Cant call a function taking the model type BY VALUE, when passing
# a member of a datasource.
# TypeError: Type mismatch - cannot convert to type Tbu::FreestandingModel
#rootnamespace.Tbu.FsmByVal(ds.m)
cspace.Unlock()
));
}
} // Tbu
/*
todos for python
----------------
- Allow for python to run the message loop, and yet still be used by the application
- Support wrapping of maps, sets, variants
- Reflection functions allow for default values for parameters.
- In general allow for name=value syntax when make function calls
- Use an extensible approach to coercions
- Support open variants
- Support construction of non-model members
- Python code can implement an interface or a functor, and therefore be called from C++
- Does python offer any counterpart to RAII?
*/
namespace Models
{
void Run()
{
MVectorsInModels::Run();
VectorsOfStringsInModels::Run();
Tbu::Run();
}
}