12 Xc++ code generation examples

$visit

The xc++ language provides a special mechanism for helping to implement the VisitObjects method of interface IObject


$interface+ IObject
{
    void VisitObjects(IObjectVisitor& v) const;
    ...
};

Before translation

$struct X isa ceda::IObject
{
    $visit
    {
        v << x;
    }

    ceda::ptr<ceda::IObject> x;
};

After translation

struct X : public ceda::IObjectBaseMixin<X,ceda::EmptyBase>
{
    void VisitObjects(ceda::IObjectVisitor& v) const;
    ...

    ceda::ptr<ceda::IObject> x;
};

void X::VisitObjects(ceda::IObjectVisitor& v) const
{
    BaseClass::VisitObjects(v);
    v << x;
}

Note that supporting $visit on a $mixin makes a lot of sense but it currently leads to compiler errors. This needs to be fixed.

$indep

Before translation

$struct X isa ceda::IObject
{
    $indep int x
        // called when the DGIndepNode is constructed
        create {}

        // called when the DGIndepNode is destructed
        destroy {}

        // allows for replacing the generated code to visit
        // the containing object and the indep variable
        visit {};
};

After translation

struct X : public ceda::IObjectBaseMixin<X,ceda::EmptyBase>
{
    ...

    void x_create(int& x) const {}
    void x_destroy(int& x) const {}
    void x_visit(ceda::IObjectVisitor& _v) const {}

    int _x_;

    struct Indepnode_x : ceda::DGIndepNode
    {
        typedef int value_type;
        Indepnode_x()
        {
            X* _self = ATTRIB_CAST(X,x);
            _self->x_create(_self->_x_);
        }
        ~Indepnode_x()
        {
            X* _self = ATTRIB_CAST(X,x);
            _self->x_destroy(_self->_x_);
        }
        virtual ceda::xstring Name() const { return "X::x"; }
        virtual void VisitContainingObject(ceda::IObjectVisitor& _v) const
        {
            X const* _self = CONST_ATTRIB_CAST(X,x);
            _self->x_visit(_v);
        }
        value_type const& read() const { ReadBarrier(); return CONST_ATTRIB_CAST(X,x)->_x_; }
        value_type& write() { OnChange(); return ATTRIB_CAST(X,x)->_x_; }
        operator value_type const&() const { return CONST_ATTRIB_CAST(X,x)->Getx(); }
        void operator=(value_type const& _v) { write() = _v; }
    } x;

    int const& Getx() const { x.ReadBarrier(); return _x_; }
    void Setx(int const& _v) { x.OnChange(); _x_ = _v; }

    void EvictDgsNodes() const
    {
        BaseClass::EvictDgsNodes();
        x.TryEvict(false);
    }
};

If no 'visit {...}' block was given then the generated VisitContainingObject method would be as follows:


    virtual void VisitContainingObject(ceda::IObjectVisitor& _v) const
    {
        X const* _self = CONST_ATTRIB_CAST(X,x);
        _v << _self->_x_;
        _v << _self;
    }

$dep

Before translation

$struct X isa ceda::IObject
{
    $visit
    {
        v << x;
    }

    $dep ceda::ptr<ceda::IObject> y
        evictable { return false; }
        evict {}
        create {}
        destroy {}
        invalidate {}
        visit {}
        calc { y = null; };

    ceda::ptr<ceda::IObject> x;
};

After translation

struct X : public ceda::IObjectBaseMixin<X,ceda::EmptyBase>
{
    typedef ceda::IObjectBaseMixin<X,ceda::EmptyBase> BaseClass;

    void VisitObjects(ceda::IObjectVisitor& v) const;

    bool y_evictable() const { return false; }
    void y_evict() const {}
    void y_create(ceda::ptr<ceda::IObject>& y) const {}
    void y_destroy(ceda::ptr<ceda::IObject>& y) const {}
    void y_invalidate() const {}
    void y_visit(ceda::IObjectVisitor& _v) const {}
    void y_calc(ceda::ptr<ceda::IObject>& y) const { y = null; }

    mutable ceda::ptr<ceda::IObject> _y_;

    struct Depnode_y : ceda::DGDepNode
    {
        typedef ceda::ptr<ceda::IObject> value_type;
        Depnode_y() : ceda::DGDepNode(true)
        {
            X const* _self = CONST_ATTRIB_CAST(X,y);
            _self->y_create(_self->_y_);
        }
        ~Depnode_y()
        {
            X const* _self = CONST_ATTRIB_CAST(X,y);
            _self->y_destroy(_self->_y_);
        }
        virtual ceda::xstring Name() const { return "X::y"; }
        virtual void VisitContainingObject(ceda::IObjectVisitor& _v) const
        {
            X const* _self = CONST_ATTRIB_CAST(X,y);
            _self->y_visit(_v);
        }
        virtual bool RecalcCache() const
        {
            X const* _self = CONST_ATTRIB_CAST(X,y);
            value_type _prev = _self->_y_;
            _self->y_calc(_self->_y_);
            return _prev != _self->_y_;
        }
        virtual bool IsEvictable() const
        {
            X const* _self = CONST_ATTRIB_CAST(X,y);
            return _self->y_evictable();
        }
        virtual void OnEvict() const
        {
            X const* _self = CONST_ATTRIB_CAST(X,y);
            _self->y_evict();
        }
        virtual void OnInvalidate() const
        {
            X const* _self = CONST_ATTRIB_CAST(X,y);
            _self->y_invalidate();
        }
        value_type const& read() const { return CONST_ATTRIB_CAST(X,y)->Gety(); }
        operator value_type const&() const { return CONST_ATTRIB_CAST(X,y)->Gety(); }
    } y;

    ceda::ptr<ceda::IObject> const& Gety() const { y.ReadBarrier(); return _y_; }

    ceda::ptr<ceda::IObject> x;

public:
    void EvictDgsNodes() const
    {
        BaseClass::EvictDgsNodes();
        y.TryEvict(false);
    }

    ceda::AnyInterface QueryInterface(const ceda::ReflectedInterface&);
    ceda::ReflectedClass const* GetReflectedClass() const;
};

ceda::AnyInterface X::QueryInterface(const ceda::ReflectedInterface& _ri)
{
    if (&_ri == &ceda::GetReflectedInterface<ceda::IObject >()) { ceda::ptr<ceda::IObject> p(this); return reinterpret_cast<ceda::AnyInterface&>(p); }
    return ceda::AnyInterface();
}
ceda::ReflectedClass const* X::GetReflectedClass() const
{
    return NULL;
}
void X::VisitObjects(ceda::IObjectVisitor& v) const
{
    BaseClass::VisitObjects(v);
    v << x;
}