-
Rainer Kartmann authoredRainer Kartmann authored
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.