Skip to content

Commit 7b95a8a

Browse files
committed
cherry picking from BehaviorTree#708
1 parent bdd41b2 commit 7b95a8a

File tree

5 files changed

+266
-10
lines changed

5 files changed

+266
-10
lines changed

include/behaviortree_cpp/scripting/operators.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,15 +103,15 @@ struct ExprUnaryArithmetic : ExprBase
103103
auto rhs_v = rhs->evaluate(env);
104104
if (rhs_v.isNumber())
105105
{
106-
double rv = rhs_v.cast<double>();
106+
const double rv = rhs_v.cast<double>();
107107
switch (op)
108108
{
109109
case negate:
110110
return Any(-rv);
111111
case complement:
112-
return Any(double(~static_cast<int64_t>(rv)));
112+
return Any(static_cast<double>(~static_cast<int64_t>(rv)));
113113
case logical_not:
114-
return Any(double(!static_cast<bool>(rv)));
114+
return Any(static_cast<double>(!static_cast<bool>(rv)));
115115
}
116116
}
117117
else if (rhs_v.isString())
@@ -252,7 +252,7 @@ struct ExprBinaryArithmetic : ExprBase
252252
}
253253
}
254254
}
255-
else if (rhs_v.isType<SimpleString>() && lhs_v.isType<SimpleString>() && op == plus)
255+
else if (rhs_v.isString() && lhs_v.isString() && op == plus)
256256
{
257257
return Any(lhs_v.cast<std::string>() + rhs_v.cast<std::string>());
258258
}

include/behaviortree_cpp/utils/safe_any.hpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,11 @@ class Any
133133
return _any.type() == typeid(SafeAny::SimpleString);
134134
}
135135

136+
// check is the original type is equal to T
136137
template <typename T>
137138
[[nodiscard]] bool isType() const
138139
{
139-
return _any.type() == typeid(T);
140+
return _original_type == typeid(T);
140141
}
141142

142143
// copy the value (casting into dst). We preserve the destination type.
@@ -170,11 +171,13 @@ class Any
170171
return linb::any_cast<T>(&_any);
171172
}
172173

174+
// This is the original type
173175
[[nodiscard]] const std::type_index& type() const noexcept
174176
{
175177
return _original_type;
176178
}
177179

180+
// This is the type we casted to, internally
178181
[[nodiscard]] const std::type_info& castedType() const noexcept
179182
{
180183
return _any.type();
@@ -210,7 +213,7 @@ class Any
210213
std::string errorMsg() const
211214
{
212215
return StrCat("[Any::convert]: no known safe conversion between [",
213-
demangle( _any.type() ), "] and [", demangle( typeid(T) ),"]");
216+
demangle( type() ), "] and [", demangle( typeid(T) ),"]");
214217
}
215218
};
216219

@@ -296,7 +299,7 @@ inline void Any::copyInto(Any &dst)
296299

297300
const auto& dst_type = dst.castedType();
298301

299-
if ((type() == dst_type) || (isString() && dst.isString()) )
302+
if ((castedType() == dst_type) || (isString() && dst.isString()) )
300303
{
301304
dst._any = _any;
302305
}
@@ -446,7 +449,7 @@ nonstd::expected<T, std::string> Any::tryCast() const
446449
throw std::runtime_error("Any::cast failed because it is empty");
447450
}
448451

449-
if (_any.type() == typeid(T))
452+
if (castedType() == typeid(T))
450453
{
451454
return linb::any_cast<T>(_any);
452455
}

tests/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ set(BT_TESTS
55
src/action_test_node.cpp
66
src/condition_test_node.cpp
77

8+
gtest_any.cpp
89
gtest_blackboard.cpp
910
gtest_coroutines.cpp
1011
gtest_decorator.cpp
@@ -58,7 +59,8 @@ else()
5859
enable_testing()
5960

6061
add_executable(${BTCPP_LIBRARY}_test ${BT_TESTS}
61-
gtest_enums.cpp)
62+
gtest_enums.cpp
63+
gtest_any.cpp)
6264
target_link_libraries(${PROJECT_NAME}_test
6365
${TEST_DEPENDECIES}
6466
Threads::Threads

tests/gtest_any.cpp

Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
/* Copyright (C) 2023 Gaël Écorchard, KM Robotics s.r.o. - All Rights Reserved
2+
*
3+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
4+
* to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
5+
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7+
*
8+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
9+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
10+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
11+
*/
12+
13+
#include <charconv> // std::{from_chars,from_chars_result},
14+
#include <string>
15+
#include <system_error> // std::errc.
16+
17+
#include <gtest/gtest.h>
18+
19+
#include <behaviortree_cpp/utils/safe_any.hpp>
20+
21+
using namespace BT;
22+
23+
TEST(Any, Empty)
24+
{
25+
{
26+
Any a;
27+
EXPECT_TRUE(a.empty());
28+
}
29+
30+
{
31+
Any a(42);
32+
EXPECT_FALSE(a.empty());
33+
}
34+
}
35+
36+
TEST(Any, IsType)
37+
{
38+
// Boolean.
39+
{
40+
Any a(true);
41+
EXPECT_TRUE(a.isType<bool>());
42+
EXPECT_FALSE(a.isType<int>());
43+
EXPECT_FALSE(a.isType<unsigned int>());
44+
EXPECT_FALSE(a.isType<double>());
45+
EXPECT_FALSE(a.isType<std::string>());
46+
}
47+
48+
// Signed int.
49+
{
50+
Any a(42);
51+
EXPECT_FALSE(a.isType<bool>());
52+
EXPECT_TRUE(a.isType<int>());
53+
EXPECT_FALSE(a.isType<unsigned int>());
54+
EXPECT_FALSE(a.isType<double>());
55+
EXPECT_FALSE(a.isType<std::string>());
56+
}
57+
58+
// unsigned int.
59+
{
60+
Any a(42u);
61+
EXPECT_FALSE(a.isType<bool>());
62+
EXPECT_FALSE(a.isType<int>());
63+
EXPECT_TRUE(a.isType<unsigned int>());
64+
EXPECT_FALSE(a.isType<double>());
65+
EXPECT_FALSE(a.isType<std::string>());
66+
}
67+
68+
// Double.
69+
{
70+
Any a(42.0);
71+
EXPECT_FALSE(a.isType<bool>());
72+
EXPECT_FALSE(a.isType<int>());
73+
EXPECT_FALSE(a.isType<unsigned int>());
74+
EXPECT_TRUE(a.isType<double>());
75+
EXPECT_FALSE(a.isType<std::string>());
76+
}
77+
78+
// String.
79+
{
80+
Any a(std::string{"forty-two"});
81+
EXPECT_FALSE(a.isType<bool>());
82+
EXPECT_FALSE(a.isType<int>());
83+
EXPECT_FALSE(a.isType<unsigned int>());
84+
EXPECT_FALSE(a.isType<double>());
85+
EXPECT_TRUE(a.isType<std::string>());
86+
}
87+
}
88+
89+
TEST(Any, Cast)
90+
{
91+
// Boolean.
92+
{
93+
Any a(true);
94+
EXPECT_TRUE(a.cast<bool>());
95+
EXPECT_EQ(typeid(a.cast<bool>()), typeid(bool));
96+
EXPECT_EQ(a.cast<int>(), 1);
97+
EXPECT_EQ(a.cast<bool>(), 1.0);
98+
EXPECT_EQ(a.cast<std::string>(), "1");
99+
100+
Any b(false);
101+
EXPECT_FALSE(b.cast<bool>());
102+
EXPECT_EQ(typeid(b.cast<bool>()), typeid(bool));
103+
EXPECT_EQ(b.cast<int>(), 0);
104+
EXPECT_EQ(b.cast<double>(), 0.0);
105+
EXPECT_EQ(b.cast<std::string>(), "0");
106+
}
107+
108+
// Signed int.
109+
{
110+
Any a(42);
111+
EXPECT_ANY_THROW(auto res = a.cast<bool>());
112+
EXPECT_EQ(a.cast<int>(), 42);
113+
EXPECT_EQ(a.cast<double>(), 42.0);
114+
EXPECT_EQ(a.cast<std::string>(), "42");
115+
116+
Any b(-43);
117+
EXPECT_ANY_THROW(auto res = b.cast<bool>());
118+
EXPECT_EQ(b.cast<int>(), -43);
119+
EXPECT_EQ(b.cast<double>(), -43.0);
120+
EXPECT_EQ(b.cast<std::string>(), "-43");
121+
122+
Any c(0);
123+
EXPECT_FALSE(c.cast<bool>());
124+
EXPECT_EQ(typeid(c.cast<bool>()), typeid(bool));
125+
EXPECT_EQ(c.cast<int>(), 0);
126+
EXPECT_EQ(c.cast<double>(), 0.0);
127+
EXPECT_EQ(c.cast<std::string>(), "0");
128+
129+
Any d(1);
130+
EXPECT_TRUE(d.cast<bool>());
131+
EXPECT_EQ(typeid(d.cast<bool>()), typeid(bool));
132+
EXPECT_EQ(d.cast<int>(), 1);
133+
EXPECT_EQ(d.cast<double>(), 1.0);
134+
EXPECT_EQ(d.cast<std::string>(), "1");
135+
}
136+
137+
// unsigned int.
138+
{
139+
Any a(43u);
140+
EXPECT_ANY_THROW(auto res = a.cast<bool>());
141+
EXPECT_EQ(a.cast<unsigned int>(), 43u);
142+
EXPECT_EQ(a.cast<int>(), 43);
143+
EXPECT_EQ(a.cast<double>(), 43.0);
144+
EXPECT_EQ(a.cast<std::string>(), "43");
145+
146+
Any b(0u);
147+
EXPECT_FALSE(b.cast<bool>());
148+
EXPECT_EQ(typeid(b.cast<bool>()), typeid(bool));
149+
EXPECT_EQ(b.cast<unsigned int>(), 0u);
150+
EXPECT_EQ(b.cast<int>(), 0);
151+
EXPECT_EQ(b.cast<double>(), 0.0);
152+
EXPECT_EQ(b.cast<std::string>(), "0");
153+
154+
Any c(1u);
155+
EXPECT_TRUE(c.cast<bool>());
156+
EXPECT_EQ(typeid(c.cast<bool>()), typeid(bool));
157+
EXPECT_EQ(c.cast<unsigned int>(), 1u);
158+
EXPECT_EQ(c.cast<int>(), 1);
159+
EXPECT_EQ(c.cast<double>(), 1.0);
160+
EXPECT_EQ(c.cast<std::string>(), "1");
161+
}
162+
163+
// Double.
164+
{
165+
Any a(44.0);
166+
EXPECT_TRUE(a.cast<bool>());
167+
EXPECT_EQ(typeid(a.cast<bool>()), typeid(bool));
168+
EXPECT_EQ(a.cast<int>(), 44);
169+
EXPECT_EQ(a.cast<double>(), 44.0);
170+
#if __cpp_lib_to_chars >= 201611L
171+
const std::string a_str = a.cast<std::string>();
172+
double a_val;
173+
const auto res = std::from_chars(a_str.data(), a_str.data() + a_str.size(), a_val, std::chars_format::general);
174+
EXPECT_TRUE(res.ec == std::errc{});
175+
EXPECT_DOUBLE_EQ(a_val, 44.0);
176+
#endif
177+
178+
Any b(44.1);
179+
EXPECT_TRUE(b.cast<bool>());
180+
EXPECT_EQ(typeid(b.cast<bool>()), typeid(bool));
181+
// EXPECT_EQ(b.cast<int>(), 44);?
182+
EXPECT_ANY_THROW(auto res = b.cast<int>());
183+
EXPECT_EQ(b.cast<double>(), 44.1);
184+
#if __cpp_lib_to_chars >= 201611L
185+
const std::string b_str = b.cast<std::string>();
186+
double b_val;
187+
const auto res2 = std::from_chars(b_str.data(), b_str.data() + b_str.size(), b_val, std::chars_format::general);
188+
EXPECT_TRUE(res2.ec == std::errc{});
189+
EXPECT_DOUBLE_EQ(b_val, 44.1);
190+
#endif
191+
192+
Any c(44.9);
193+
EXPECT_TRUE(c.cast<bool>());
194+
// EXPECT_EQ(c.cast<int>(), 44);?
195+
EXPECT_ANY_THROW(auto res = c.cast<int>());
196+
EXPECT_EQ(c.cast<double>(), 44.9);
197+
198+
Any d(-45.0);
199+
EXPECT_TRUE(c.cast<bool>());
200+
// EXPECT_EQ(c.cast<int>(), -45);?
201+
EXPECT_ANY_THROW(auto res = c.cast<int>());
202+
203+
Any e(0.0);
204+
EXPECT_FALSE(e.cast<bool>());
205+
EXPECT_EQ(e.cast<int>(), 0);
206+
}
207+
208+
// String.
209+
{
210+
Any a(std::string{"fifty"});
211+
EXPECT_ANY_THROW(auto res = a.cast<bool>());
212+
EXPECT_ANY_THROW(auto res = a.cast<int>());
213+
EXPECT_ANY_THROW(auto res = a.cast<double>());
214+
EXPECT_EQ(a.cast<std::string>(), "fifty");
215+
216+
Any b(std::string{"true"});
217+
// EXPECT_TRUE(b.cast<bool>());?
218+
EXPECT_ANY_THROW(auto res = b.cast<bool>());
219+
220+
Any c(std::string{"false"});
221+
// EXPECT_FALSE(c.cast<bool>());?
222+
EXPECT_ANY_THROW(auto res = c.cast<bool>());
223+
224+
Any d(std::string{"0"});
225+
// EXPECT_FALSE(d.cast<bool>());?
226+
EXPECT_EQ(d.cast<int>(), 0);
227+
EXPECT_EQ(d.cast<double>(), 0.0);
228+
229+
Any e(std::string{"1"});
230+
// EXPECT_TRUE(e.cast<bool>());?
231+
EXPECT_EQ(e.cast<int>(), 1);
232+
EXPECT_EQ(e.cast<double>(), 1.0);
233+
234+
Any f(std::string{"51"});
235+
EXPECT_ANY_THROW(auto res = f.cast<bool>());
236+
EXPECT_EQ(f.cast<int>(), 51);
237+
EXPECT_EQ(f.cast<double>(), 51.0);
238+
239+
Any g(std::string{"51.1"});
240+
EXPECT_ANY_THROW(auto res = g.cast<bool>());
241+
EXPECT_EQ(g.cast<int>(), 51);
242+
EXPECT_DOUBLE_EQ(g.cast<double>(), 51.1);
243+
}
244+
245+
{
246+
std::vector<int> v{1, 2, 3};
247+
Any a(v);
248+
EXPECT_EQ(a.cast<std::vector<int>>(), v);
249+
}
250+
}

tests/script_parser_test.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ TEST(ParserTest, Equations)
152152
EXPECT_EQ(GetResult("y | x").cast<double>(), (5 | 3));
153153
EXPECT_EQ(GetResult("y ^ x").cast<double>(), (5 ^ 3));
154154

155-
EXPECT_ANY_THROW(GetResult("y ^ 5.1").cast<double>());
155+
EXPECT_ANY_THROW(auto res = GetResult("y ^ 5.1").cast<double>());
156156

157157
// test string variables
158158
EXPECT_EQ(GetResult("A:='hello'; B:=' '; C:='world'; A+B+C").cast<std::string>(),
@@ -216,6 +216,7 @@ TEST(ParserTest, Equations)
216216
EXPECT_EQ(variables->get<int>("v1"), 1);
217217
EXPECT_EQ(variables->get<int>("v2"), 0);
218218

219+
EXPECT_EQ(GetResult(" v2 = true ").cast<int>(), 1);
219220
EXPECT_EQ(GetResult(" v2 = !false ").cast<int>(), 1);
220221
EXPECT_EQ(GetResult(" v2 = !v2 ").cast<int>(), 0);
221222

0 commit comments

Comments
 (0)