ClassesWithModels.cpp
// ClassesWithModels.cpp
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2011
@import "Ceda/cxObject/PrintReflectedType.h"
@import "Ceda/cxObject/PrintReflectedVariable.h"
@import "Ceda/cxObject/IObjectVisitor.h"
@import "ValidateSerialisation.h"
@import "ExampleUtils.h"
#include <math.h>
/*
Modifiers in << >>
------------------
ser Read/Write to archive can be reflected
default = true
os Generate operator<<() for xostream in terms of MyClass::Write()
A class has "access to a model" if any of the following are true
- it is a pure model
- it references a pure model
- it embeds an anonymous model
In that case by default operator<<() is generated
default = false
ar Generate operator<<(),operator>>() for Archive in terms of MyClass::Serialise()
default = false
extern Class definition is provided elsewhere, and therefore this definition
should be elided.
This is used to reflect pre-existing classes, such as the Guid datatype
which is predefined in cxUtils.
default = false
passbyvalue Allow pass by value in ABI
This sets the bit flag EReflectedClassBits::RCF_ALLOW_PASS_BY_VALUE
when the class is reflected
default = false
returnbyvalue Allow return by value in ABI
This sets the bit flag EReflectedClassBits::RCF_ALLOW_RETURN_BY_VALUE
when the class is reflected
default = false
multiline Auto generated function to write model to an xostream uses the
multiline format
default = false
Multiline
---------
<<multiline>> is supported on models to make xcpp generate a multiline version of operator<<()
which writes it to an xostream. This is appropriate for complicated models
E.g.
$model Point { float32 x; float32 y; };
// required
#include "Ceda/cxUtils/ScopeWriter.h"
$model X <<multiline>>
{
int32 a;
int32 b[2][2];
Point c[];
};
E.g. a value of X may be written to an xostream like this
X
{
a = 10
b = [[0,0],[22,-11]]
c = [Point(1,2),Point(0,0) ,Point(4,-1)]
}
Note that the textual output is meant to be compatible with the parser format used by
cxCedaScript, irrespective of whether multiline output is used.
Currently variants upset that assumption because the output isn't 'tagged' for anonymous types
declared in a variant. E.g. a variant may output 123 instead of int32(123). The current
plan is to fix this eventually by making cxCedaScript smarter at parsing variants.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////
// EmbeddedModels1
/*
A model can be embedded into a $class/$struct. The model actually appears as a member named
_model_ and this allows for direct access to the model.
Xcpp generates access methods on the model which allow for certain system provided functionality.
Such access to the model does the following:
- read access invokes the DGS read barriers
- write access invokes the DGS write barriers
- mutative functions invoke the callbacks needed to support
- Operational Transformation
- Marking objects as dirty as required for cxPersistStore
- Allocation of oids to pref'd objects
Serialisation of the RSN
------------------------
The generated serialise functions for a $class/$struct with an embedded model begin by serialising
the Release Sequence Number (RSN) of the target in which the $class/$struct is defined.
This provides a basis for schema evolution of the embedded model, plus any other models that are
serialised as well.
void C::Serialise(ceda::Archive& _ar) const
{
ceda::WriteDataSourceRsn(_ar,ceda::s_localRsn);
_model_.Serialise(_ar);
}
void C::Deserialise(ceda::InputArchive& _ar)
{
ceda::ReadDataSourceRsn(_ar,0);
_model_.Deserialise(_ar);
}
*/
namespace EmbeddedModels1
{
// $class/$struct can use an anonymous model
$struct C :
model
{
int32 x;
}
{
/*
Shows how direct access to the model is supported
*/
void MakesDirectAccess()
{
_model_.x = 10;
}
};
void Run()
{
ceda::TraceGroup g("EmbeddedModels1");
/*
Idealy the size of a $class/$struct would match the size of the embedded model. However
the current implementation takes up an extra 4 bytes (on Win32 x86 builds) because of
the way it utilises a union of 'attribute' structs used to hook into the read/write
accesses to the members. This is actually wasted space.
output
Size of C = 8 bytes
*/
Tracer() << "Size of C = " << sizeof(C) << " bytes\n";
/*
A $class/$struct with an embedded model has operator<<() to an xostream written, just as
for pure models.
output
c = C(0)
*/
C c;
Tracer() << "c = " << c << '\n';
/*
The read of c.x in the RHS expression invokes the DGS read barrier (i.e.
ceda::DataSourceReadBarrier())
The assignment to c.x invokes the DGS write barrier (i.e. ceda::DataSourceWriteBarrier())
These DGS read/writer barriers have no effect here, but in other situations allow for the
members of the model to behave as independent nodes of the DGS
output
c = C(1)
*/
c.x = c.x + 1;
Tracer() << "c = " << c << '\n';
/*
read() is available on each member of the model, and for a member of type T,
it invokes the DGS read barrier and returns the member as a const T&.
output
c.x.read() = 1
*/
Tracer() << "c.x.read() = " << c.x.read() << '\n';
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// ClassRefsModel
/*
A $class/$struct can reference a model by name
*/
namespace ClassRefsModel
{
$model Point
{
int32 X;
int32 Y;
};
$struct C : model Point
{
};
void Run()
{
ceda::TraceGroup g("ClassRefsModel");
/*
output:
Size of C = 12 bytes
*/
Tracer() << "Size of C = " << sizeof(C) << " bytes\n";
C c;
c.X = c.X + 1;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// ModelsEmbeddedInMixins
namespace ModelsEmbeddedInMixins
{
$mixin M :
model
{
float64 N;
}
{
};
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// Syntax
namespace Syntax
{
struct Base1 {};
struct Base2 {};
struct Base3 { Base3(int x,int y) {} };
struct Base4 {};
$model+ SomeModel {};
$mixin MyMixin1 {};
$mixin MyMixin2 {};
/*
Base1, Base2, and SomeModel are fed into the mixin chain (which can be very handy but it assumes
Base1, Base2 have default constructors). Base3 and Base4 are instead direct base classes of C3
and may not have default constructors
*/
$class+ C3 isa ceda::IObject : ceda::EmptyBase,Base1,Base2 model SomeModel mixin [MyMixin1 MyMixin2] Base3,Base4 : [1,2,3,foo(x)]
{
C3() : Base3(0,0) {}
};
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// Paths on members of transient models are supported
namespace PathsOnTransientModels
{
$struct Foo << register >> isa ceda::IObject :
model
{
ptr< ceda::IObject > X;
ceda::xvector< ceda::string16 > Y;
}
{
void DoSomething()
{
ceda::FieldPath p1 = X.path();
ceda::FieldPath p2 = Y.path();
}
};
}
namespace ClassesWithModels
{
void Run()
{
EmbeddedModels1::Run();
ClassRefsModel::Run();
}
}