SkillExecutionHandle.cpp
Go to the documentation of this file.
1/**
2 * This file is part of ArmarX.
3 *
4 * ArmarX is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * ArmarX is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * @author Fabian Reister ( fabian dot reister at kit dot edu )
17 * @date 2025
18 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
19 * GNU General Public License
20 */
21
23
24#include <memory>
25#include <optional>
26#include <utility>
27#include <vector>
28
29#include <range/v3/algorithm/all_of.hpp>
30#include <range/v3/range/conversion.hpp>
31#include <range/v3/view/filter.hpp>
32#include <range/v3/view/indirect.hpp>
33#include <range/v3/view/map.hpp>
34#include <range/v3/view/transform.hpp>
35#include <range/v3/view/zip.hpp>
36
41
46
47namespace armarx::skills
48{
49
50
52 {
53 ARMARX_VERBOSE << "Destroying SkillExecutionHandle for subskill "
54 << proxy_->getSkillId().toString();
55
56 if (not isJoined_)
57 {
58 // The following commented out code uses getExecutionStatus() which is very inefficient.
59 // Hence, we don't use this at the moment.
60 // if (not getExecutionStatus()->hasBeenTerminated())
61 {
62 ARMARX_INFO << "Joining skill " << QUOTED(proxy_->getSkillId().toString())
63 << " on handle destruction.";
64 const auto status = join();
65 ARMARX_INFO << "Joined skill " << QUOTED(proxy_->getSkillId().toString()) << ".";
66
68 {
69 ARMARX_ERROR << "Skill execution " << QUOTED(proxy_->getSkillId().toString())
70 << " failed";
71 }
72 }
73 }
74 }
75
78 proxy_(std::move(proxy)), executionId_(std::move(executionId))
79 {
81 }
82
83 std::optional<TerminatedSkillStatusUpdate>
85 {
86 ARMARX_INFO << "Joining subskill " << QUOTED(proxy_->getSkillId().toString());
87
88 std::optional<TerminatedSkillStatusUpdate> result = proxy_->join(executionId_);
89 isJoined_ = true;
90
91 return result;
92 }
93
94 bool
96 {
97 ARMARX_INFO << "Aborting subskill " << QUOTED(proxy_->getSkillId().toString());
98
99 return proxy_->abortSkillAsync(executionId_);
100 }
101
102 std::optional<SkillStatusUpdate>
104 {
105 // NOTE: proxy_->getExecutionStatus is very inefficient and can take up to 500ms.
106 // Hence, it should not be used at the moment.
107
108 return proxy_->getExecutionStatus(executionId_);
109 }
110
111 namespace util
112 {
113
114 JoinAllResult::
115 operator bool() const
116 {
117 return ranges::all_of(
118 ranges::views::values(updates),
119 [](const std::optional<armarx::skills::TerminatedSkillStatusUpdate>& update)
120 { return skills::skillExecutionSucceeded(update); });
121 }
122
123 std::vector<armarx::skills::SkillExecutionID>
125 {
126 const auto failed = [this](const armarx::skills::SkillExecutionID& executionId)
127 { return armarx::skills::skillExecutionFailed(updates.at(executionId)); };
128
129 return ranges::views::keys(updates) | ranges::views::filter(failed) | ranges::to_vector;
130 }
131
132 std::vector<armarx::skills::SkillID>
134 {
135 const auto failed = [this](const armarx::skills::SkillExecutionID& executionId)
136 { return armarx::skills::skillExecutionFailed(updates.at(executionId)); };
137
138 const auto getSkillID = [](const armarx::skills::SkillExecutionID& executionId)
139 { return executionId.skillId; };
140
141 return ranges::views::keys(updates) | ranges::views::filter(failed) |
142 ranges::views::transform(getSkillID) | ranges::to_vector;
143 }
144
146 joinAll(const std::vector<armarx::skills::SkillExecutionHandle*>& handles)
147 {
148 const auto join = [](armarx::skills::SkillExecutionHandle& handle)
149 { return handle.join(); };
150
151 const auto getExecutionID = [](const armarx::skills::SkillExecutionHandle& handle)
152 { return handle.executionId(); };
153
154 const auto executionIDs = handles | ranges::views::indirect |
155 ranges::views::transform(getExecutionID) | ranges::to_vector;
156 const auto updates = handles | ranges::views::indirect |
157 ranges::views::transform(join) | ranges::to_vector;
158
159 return JoinAllResult{ranges::views::zip(executionIDs, updates) |
160 ranges::to<JoinAllResult::UpdatesMap>()};
161 }
162
163 JoinAllResult
164 joinAll(const std::vector<std::unique_ptr<armarx::skills::SkillExecutionHandle>>& handles)
165 {
166 const std::vector<armarx::skills::SkillExecutionHandle*> rawHandles =
167 handles | ranges::views::transform([](auto& p) { return p.get(); }) |
168 ranges::to_vector;
169
170 return static_cast<JoinAllResult (*)(const std::vector<SkillExecutionHandle*>&)>(
171 joinAll)(rawHandles);
172 }
173
174 JoinAllResult
175 joinAll(const std::vector<std::shared_ptr<armarx::skills::SkillExecutionHandle>>& handles)
176 {
177 const std::vector<armarx::skills::SkillExecutionHandle*> rawHandles =
178 handles | ranges::views::transform([](auto& p) { return p.get(); }) |
179 ranges::to_vector;
180
181 return static_cast<JoinAllResult (*)(const std::vector<SkillExecutionHandle*>&)>(
182 joinAll)(rawHandles);
183 }
184
185
186 } // namespace util
187
190 {
191 return executionId_;
192 }
193} // namespace armarx::skills
#define QUOTED(x)
RAII handle for a running subskill.
bool abortAsync()
Request an asynchronous abort of the subskill.
std::optional< TerminatedSkillStatusUpdate > join()
Block until the subskill terminates and return its status.
~SkillExecutionHandle()
Destructor requests cleanup of the subskill.
SkillExecutionHandle(SkillProxyPtr proxy, skills::SkillExecutionID executionId)
Construct a handle for an executing subskill.
const skills::SkillExecutionID & executionId() const
std::optional< SkillStatusUpdate > getExecutionStatus()
Get the current execution status of the subskill.
#define ARMARX_CHECK_NOT_NULL(ptr)
This macro evaluates whether ptr is not null and if it turns out to be false it will throw an Express...
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:196
#define ARMARX_VERBOSE
The logging level for verbose information.
Definition Logging.h:187
JoinAllResult joinAll(const std::vector< armarx::skills::SkillExecutionHandle * > &handles)
This file is part of ArmarX.
bool skillExecutionSucceeded(const std::optional< armarx::skills::TerminatedSkillStatusUpdate > &update)
std::unique_ptr< class SkillProxy > SkillProxyPtr
bool skillExecutionFailed(const std::optional< armarx::skills::TerminatedSkillStatusUpdate > &update)
std::vector< armarx::skills::SkillID > failedSkillIDs() const
std::vector< armarx::skills::SkillExecutionID > failedSkillExecutionIDs() const