Procedure
The Procedure class represents instruction trees to be executed within the oac-tree and a workspace of globally accessible variables (see Variable). It provides methods to handle variables and instructions, and to manage the execution flow. A procedure can include multiple top-level instructions, where at most one is defined to be the root instruction that will be executed on procedure execution.
Architecture
The Procedure class is responsible for managing a collection of instruction trees. It contains a vector of top-level instructions, each represented by a derived class of the Instruction class. The class also includes an internal Workspace that holds variables and their values during the execution of instructions.
Usage
Creating a Procedure
To create a new procedure, instantiate an object of the Procedure class. Optionally, you can specify the filename if the procedure is loaded from a file:
Procedure my_procedure("example.procedure");
The optional filename argument shall be provided when the procedure is constructed from a file and it contains special include instructions pointing to other files via relative path names.
Managing Instructions
You can add, retrieve, and remove instructions in the procedure. The procedure allows managing instructions at the top level.
// Add a new instruction to the top level
auto my_instruction = GlobalInstructionRegistry().Create("MyInstruction");
my_procedure.PushInstruction(std::move(my_instruction));
// Retrieve the root instruction
Instruction* root = my_procedure.RootInstruction();
// Remove an instruction from a specific position
std::unique_ptr<Instruction> removed_instruction = my_procedure.TakeInstruction(0);
Managing Variables
The procedure can hold and manage variables using the internal workspace. Users can add, retrieve, and list variables associated with the procedure’s workspace.
Variables are registered in the global variable registry using their type names. In the code snippet below, it is assumed that class MyVariable : public Variable was provided and registered in the global variable registry under the name “MyVariable”.
// Add a new variable to the procedure's workspace
auto my_variable = GlobalVariableRegistry().Create("MyVariable");
my_procedure.AddVariable("var1", std::move(my_variable));
// Retrieve the value of a variable
sup::dto::AnyValue value;
if (my_procedure.GetVariableValue("var1", value)) {
// Successfully retrieved the value
}
// List all variable names in the procedure
std::vector<std::string> variable_names = my_procedure.VariableNames();
Execution Control
The procedure can be executed step-by-step using the ExecuteSingle method. This allows controlling the execution flow and validating the procedure at each step. The Setup method prepares the procedure for execution. The procedure can also be halted and reset.
// Setup the procedure before execution
my_procedure.Setup();
// Execute a single step of the procedure
UserInterface ui; // Assume UserInterface is properly implemented
my_procedure.ExecuteSingle(ui);
// Halt the procedure's execution
my_procedure.Halt();
// Tear down the procedure and wait for all asynchronous instructions to finish
my_procedure.Teardown(ui);
Procedure Status and Control
Users can retrieve the execution status of the root instruction to determine whether the procedure is still running, has completed, or encountered an error.
// Get the status of the root instruction
ExecutionStatus status = my_procedure.GetStatus();
Attributes
The procedure can have attributes associated with it. Attributes are key-value pairs that store additional information about the procedure.
// Add an attribute to the procedure
my_procedure.AddAttribute("version", "1.0");
// Retrieve the value of an attribute
std::string version = my_procedure.GetAttributeString("version");
Additional Notes
The Procedure class supports various additional features, such as setting up preamble information, registering types and plugins, and handling callbacks for variable updates. Users can refer to the specific class methods, presented in the following section, for more details on these advanced features.
Procedures can be serialized to XML files and restored back using helper functions from sequence_parser.h.
Class definition
Next is presented the definition of the Procedure class and its main methods.
-
class Procedure
Procedure contains a tree of instructions.
A Procedure object contains a full instruction tree and a workspace
Note
The client of the Procedure, i.e. the object responsible for its creation and destruction, needs to ensure that the Procedure is correctly set up before executing it (by calling the Setup method on it). Likewise, the client needs to call Reset on the Procedure before destroying the UserInterface class. Reset will block until all threads have terminated.
Public Functions
-
explicit Procedure(const std::string &filename = "")
Constructor.
- Parameters:
filename – Filename of this procedure or empty if not created from file.
-
std::string GetFilename() const
Get the filename of this procedure (if loaded from file).
This filename is used for external includes with relative pathnames.
- Returns:
Filename of this procedure.
-
Instruction *RootInstruction()
Get root instruction.
- Returns:
Root instruction.
-
const Instruction *RootInstruction() const
Get root instruction (const version).
- Returns:
Root instruction.
-
std::vector<const Instruction*> GetTopInstructions() const
Get top-level instructions.
- Returns:
List of top-level instructions.
-
ProcedureContext GetContext() const
Get the procedure’s context, like its filename and the main ProcedureStore.
- Returns:
ProcedureContext structure.
-
int GetInstructionCount() const
Get number of top-level instructions.
- Returns:
Number of instructions
-
void PushInstruction(std::unique_ptr<Instruction> &&instruction)
Push Instruction at top level.
- Parameters:
instruction – Instruction to push.
- Throws:
InvalidOperationException – when trying to pass an empty unique_ptr.
-
bool InsertInstruction(std::unique_ptr<Instruction> &&instruction, int index)
Inserts Instruction at the specified position.
- Parameters:
instruction – Instruction to be inserted
index – Position in the vector where instruction is inserted.
- Returns:
true on successful insertion.
-
std::unique_ptr<Instruction> TakeInstruction(int index)
Removes Instruction from the specified position.
- Parameters:
index – Position in the vector from where instruction is removed.
- Returns:
Removed instruction
-
std::vector<std::string> VariableNames() const
List all variable names.
- Returns:
Variable name list.
-
bool GetVariableValue(std::string name, sup::dto::AnyValue &value) const
Get variable value.
- Parameters:
name – Variable name
value – AnyValue to where the variable will be retrieved.
- Returns:
true on successful retrieval.
-
void Setup()
Setup the procedure.
-
void ExecuteSingle(UserInterface &ui)
Execute single step of procedure.
- Parameters:
ui – UserInterface to use for instruction input/output.
-
void Halt()
Halt the procedure’s execution.
Note
This is mainly used for interrupting all instructions that are running in a separate thread.
-
void Reset(UserInterface &ui)
Reset the procedure to its initial state after setup.
All workspaces are torn down and setup again; instructions receive a reset command. The procedure can be started afterwards in a fresh state.
- Parameters:
ui – UserInterface to use for instruction status updates.
-
ExecutionStatus GetStatus() const
Retrieve status of root sequence.
- Returns:
Current execution status of the root instruction.
-
bool HasAttribute(const std::string &name) const
Indicate presence of attribute with given name.
- Parameters:
name – Attribute name.
- Returns:
true when present.
-
std::string GetAttributeString(const std::string &name) const
Get attribute with given name.
- Parameters:
name – Attribute name.
- Returns:
Attribute value.
-
bool AddAttribute(const std::string &name, const std::string &value)
Set attribute with given name and value.
- Parameters:
name – Attribute name.
value – Attribute value.
- Returns:
true when successful.
-
bool AddAttributes(const StringAttributeList &str_attributes)
Add all attributes from a given map.
- Parameters:
str_attributes – List of attributes.
- Returns:
true when successful.
-
template<typename T>
inline T GetAttributeValue(const std::string &attr_name) const Get attribute value with given name and type.
- Parameters:
attr_name – Attribute name.
- Throws:
RuntimeException – when attribute with given name was not found or its value could not be converted to the requested type.
- Returns:
Attribute value of requested type.
-
const Workspace &GetWorkspace() const
Returns pointer to internal workspace.
- Returns:
workspace.
-
Workspace &GetWorkspace()
Returns pointer to internal workspace.
- Returns:
workspace.
-
const ProcedurePreamble &GetPreamble() const
Returns procedure’s preamble.
- Returns:
ProcedurePreamble object reference.
-
ProcedurePreamble &GetPreamble()
Returns procedure’s preamble.
- Returns:
ProcedurePreamble object reference.
-
bool RegisterType(const sup::dto::AnyType &anytype)
Register an AnyType instance under its own name.
- Parameters:
anytype – AnyType instance to register.
- Returns:
true on successful registration.
-
const sup::dto::AnyTypeRegistry &GetTypeRegistry() const
Get the current type registry.
- Returns:
Reference to type registry.
-
bool RegisterGenericCallback(const GenericCallback &cb, void *listener)
Add a generic callback for variable updates.
Note
Users are responsible for ensuring the callback outlives the underlying workspace or to unregister it using ScopeGuard object.
- Parameters:
cb – Callback function object.
listener – Pointer to object that listens to updates.
- Returns:
true if adding the callback was successful.
-
void SetupPreamble()
Register types and load plugins defined in the preamble.
-
explicit Procedure(const std::string &filename = "")