Skip to content
Snippets Groups Projects
Forked from Software / ArmarX / RobotAPI
941 commits behind the upstream repository.

Visitors

Visitors are a useful tool to define specific methods for specific types without specifying the switch(): case: ... again and again. Further, recursive visitors offer a convenient way to iterate through the tree-like structure of any Aron object. (Please note that right now the implementation does not check for cycles!). Again, we will only look at data visitors since the implementation of type visitors is more or less similar.

Non-recursive Visitors

First, there are "normal" visitors. They are used to get rid of the big switch-case statement when getting an Aron object with unknown type. Further, these visitors can be used to convert an Aron object from one representation into another (see Aron/Conversion). The Visitor Base-class offers the following pure virtual methods which you have to implement:

    virtual data::Descriptor getDescriptor(Input&) = 0;
    virtual void visitDict(Input&) {};
    virtual void visitList(Input&) {};
    virtual void visitNDArray(Input&) {};
    virtual void visitInt(Input&) {};
    virtual void visitLong(Input&) {};
    virtual void visitFloat(Input&) {};
    virtual void visitDouble(Input&) {};
    virtual void visitBool(Input&) {};
    virtual void visitString(Input&) {};
    virtual void visitUnknown(Input&) { throw error::AronException(__PRETTY_FUNCTION__, "Unknown type in visitor."); }

Input is a template parameter, defining the Input-type (e.g. const armarx::aron::data::VariantPtr for a VariantVisitor Implementation).

The method getDescriptor(Input&) is used for the switch case interally.

As you can see the VariantVisitor always gets a generic variant as input in each function. This means that, although the Visitor guarantees that the input is correct, you have to cast the class to the correct type. For widely used Visitors, the Aron library offers convenience implementations (e.g. for Variants and for nlohmann::json inputs). The convenience class for Variants additionally adds overloads where the input is already casted correctly (you can decide which method you want to override).

To use a Visitor, you have to use the function

    void visit(VisitorImplementation& v, typename VisitorImplementation::Input& o);

which takes the visitor and the input as arguments and does the switch-case.

Recursive Vistors

Recursive visitors are similar to normal vistors but they continue "visiting" until the object is fully visited. For containers (e.g. dicts, lists) they offer two methods each:

        virtual void visitDictOnEnter(Input& element) {};
        virtual void visitDictOnExit(Input& element) {};
        virtual void visitListOnEnter(Input& element) {};
        virtual void visitListOnExit(Input& element) {};

The *OnEnter method is called before iterating over all children of the container. The *OnExit is called after the iteration.

Further, in order to get the elements of a container, you must implement the methods:

        virtual MapElements getDictElements(Input&) = 0;
        virtual ListElements getListElements(Input&) = 0;

Again, Input can be any aron object (e.g. Variant or nlohmann::json).

As for normal visitors, the Aron library offers convenience implementations for Variants and nlohmann::json inputs.

To use the RecursiveVisitor, you have to use the function

    void visitRecursive(RecursiveVisitorImplementation& v, typename RecursiveVisitorImplementation::Input& o);

Example

Assume you want to count how many objects of each kind you have in a Variant.

    #include <RobotAPI/libraries/aron/core/data/visitor/variant/VariantVisitor.h>
    class CountingRecursiveVisitor : public RecursiveConstVariantVisitor
    {
    public:
        int dicts = 0;
        int lists = 0;
        int ndarrays = 0;
        int ints = 0;
        int floats = 0;
        int longs = 0;
        int doubles = 0;
        int strings = 0;
        int bools = 0;
    public:
        void visitAronVariantOnEnter(const data::DictPtr&) override { dicts++; }
        void visitAronVariantOnEnter(const data::ListPtr&) override { lists++; }
        void visitAronVariant(const data::NDArrayPtr&) override     { ndarrays++; }
        void visitAronVariant(const data::IntPtr&) override         { ints++; }
        void visitAronVariant(const data::LongPtr&) override        { longs++; }
        void visitAronVariant(const data::FloatPtr&) override       { floats++; }
        void visitAronVariant(const data::DoublePtr&) override      { doubles++; }
        void visitAronVariant(const data::BoolPtr&) override        { strings++; }
        void visitAronVariant(const data::StringPtr&) override      { bools++; }
    };

    void countHowMany(const aron::data::VariantPtr& aron)
    {
        CountingRecursiveVisitor visitor;
        aron::data::visitRecursive(visitor, aron);

        std::cout << "The aron has " << visitor.dicts << " dicts." << std::endl;
    }

Typed Visitors

Lessons Learned