Skip to content

Commit 5d4933d

Browse files
authored
add tests for copy and move operations of the Handle class (#2011)
1 parent e574645 commit 5d4933d

File tree

2 files changed

+141
-40
lines changed

2 files changed

+141
-40
lines changed

hardware_interface/include/hardware_interface/handle.hpp

+38-40
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#ifndef HARDWARE_INTERFACE__HANDLE_HPP_
1616
#define HARDWARE_INTERFACE__HANDLE_HPP_
1717

18+
#include <algorithm>
1819
#include <limits>
1920
#include <memory>
2021
#include <mutex>
@@ -29,7 +30,7 @@
2930
namespace hardware_interface
3031
{
3132

32-
using HANDLE_DATATYPE = std::variant<double>;
33+
using HANDLE_DATATYPE = std::variant<std::monostate, double>;
3334

3435
/// A handle used to get and set a value on a given interface.
3536
class Handle
@@ -72,55 +73,22 @@ class Handle
7273
{
7374
}
7475

75-
Handle(const Handle & other) noexcept
76-
{
77-
std::unique_lock<std::shared_mutex> lock(other.handle_mutex_);
78-
std::unique_lock<std::shared_mutex> lock_this(handle_mutex_);
79-
prefix_name_ = other.prefix_name_;
80-
interface_name_ = other.interface_name_;
81-
handle_name_ = other.handle_name_;
82-
value_ = other.value_;
83-
value_ptr_ = other.value_ptr_;
84-
}
85-
86-
Handle(Handle && other) noexcept
87-
{
88-
std::unique_lock<std::shared_mutex> lock(other.handle_mutex_);
89-
std::unique_lock<std::shared_mutex> lock_this(handle_mutex_);
90-
prefix_name_ = std::move(other.prefix_name_);
91-
interface_name_ = std::move(other.interface_name_);
92-
handle_name_ = std::move(other.handle_name_);
93-
value_ = std::move(other.value_);
94-
value_ptr_ = std::move(other.value_ptr_);
95-
}
76+
Handle(const Handle & other) noexcept { copy(other); }
9677

9778
Handle & operator=(const Handle & other)
9879
{
9980
if (this != &other)
10081
{
101-
std::unique_lock<std::shared_mutex> lock(other.handle_mutex_);
102-
std::unique_lock<std::shared_mutex> lock_this(handle_mutex_);
103-
prefix_name_ = other.prefix_name_;
104-
interface_name_ = other.interface_name_;
105-
handle_name_ = other.handle_name_;
106-
value_ = other.value_;
107-
value_ptr_ = other.value_ptr_;
82+
copy(other);
10883
}
10984
return *this;
11085
}
11186

87+
Handle(Handle && other) noexcept { swap(*this, other); }
88+
11289
Handle & operator=(Handle && other)
11390
{
114-
if (this != &other)
115-
{
116-
std::unique_lock<std::shared_mutex> lock(other.handle_mutex_);
117-
std::unique_lock<std::shared_mutex> lock_this(handle_mutex_);
118-
prefix_name_ = std::move(other.prefix_name_);
119-
interface_name_ = std::move(other.interface_name_);
120-
handle_name_ = std::move(other.handle_name_);
121-
value_ = std::move(other.value_);
122-
value_ptr_ = std::move(other.value_ptr_);
123-
}
91+
swap(*this, other);
12492
return *this;
12593
}
12694

@@ -187,11 +155,41 @@ class Handle
187155
// END
188156
}
189157

158+
private:
159+
void copy(const Handle & other) noexcept
160+
{
161+
std::unique_lock<std::shared_mutex> lock(other.handle_mutex_);
162+
std::unique_lock<std::shared_mutex> lock_this(handle_mutex_);
163+
prefix_name_ = other.prefix_name_;
164+
interface_name_ = other.interface_name_;
165+
handle_name_ = other.handle_name_;
166+
value_ = other.value_;
167+
if (std::holds_alternative<std::monostate>(value_))
168+
{
169+
value_ptr_ = other.value_ptr_;
170+
}
171+
else
172+
{
173+
value_ptr_ = std::get_if<double>(&value_);
174+
}
175+
}
176+
177+
void swap(Handle & first, Handle & second) noexcept
178+
{
179+
std::unique_lock<std::shared_mutex> lock(first.handle_mutex_);
180+
std::unique_lock<std::shared_mutex> lock_this(second.handle_mutex_);
181+
std::swap(first.prefix_name_, second.prefix_name_);
182+
std::swap(first.interface_name_, second.interface_name_);
183+
std::swap(first.handle_name_, second.handle_name_);
184+
std::swap(first.value_, second.value_);
185+
std::swap(first.value_ptr_, second.value_ptr_);
186+
}
187+
190188
protected:
191189
std::string prefix_name_;
192190
std::string interface_name_;
193191
std::string handle_name_;
194-
HANDLE_DATATYPE value_;
192+
HANDLE_DATATYPE value_ = std::monostate{};
195193
// BEGIN (Handle export change): for backward compatibility
196194
// TODO(Manuel) redeclare as HANDLE_DATATYPE * value_ptr_ if old functionality is removed
197195
double * value_ptr_;

hardware_interface/test/test_handle.cpp

+103
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,106 @@ TEST(TestHandle, interface_description_command_interface_name_getters_work)
9595
EXPECT_EQ(handle.get_interface_name(), POSITION_INTERFACE);
9696
EXPECT_EQ(handle.get_prefix_name(), JOINT_NAME_1);
9797
}
98+
99+
TEST(TestHandle, copy_constructor)
100+
{
101+
{
102+
double value = 1.337;
103+
hardware_interface::Handle handle{JOINT_NAME, FOO_INTERFACE, &value};
104+
hardware_interface::Handle copy(handle);
105+
EXPECT_DOUBLE_EQ(copy.get_value(), value);
106+
EXPECT_DOUBLE_EQ(handle.get_value(), value);
107+
EXPECT_NO_THROW(copy.set_value(0.0));
108+
EXPECT_DOUBLE_EQ(copy.get_value(), 0.0);
109+
EXPECT_DOUBLE_EQ(handle.get_value(), 0.0);
110+
}
111+
{
112+
double value = 1.337;
113+
InterfaceInfo info;
114+
info.name = FOO_INTERFACE;
115+
info.data_type = "double";
116+
InterfaceDescription itf_descr{JOINT_NAME, info};
117+
hardware_interface::Handle handle{itf_descr};
118+
EXPECT_TRUE(std::isnan(handle.get_value()));
119+
handle.set_value(value);
120+
hardware_interface::Handle copy(handle);
121+
EXPECT_EQ(copy.get_name(), handle.get_name());
122+
EXPECT_EQ(copy.get_interface_name(), handle.get_interface_name());
123+
EXPECT_EQ(copy.get_prefix_name(), handle.get_prefix_name());
124+
EXPECT_DOUBLE_EQ(copy.get_value(), value);
125+
EXPECT_DOUBLE_EQ(handle.get_value(), value);
126+
EXPECT_NO_THROW(copy.set_value(0.0));
127+
EXPECT_DOUBLE_EQ(copy.get_value(), 0.0);
128+
EXPECT_DOUBLE_EQ(handle.get_value(), value);
129+
EXPECT_NO_THROW(copy.set_value(0.52));
130+
EXPECT_DOUBLE_EQ(copy.get_value(), 0.52);
131+
EXPECT_DOUBLE_EQ(handle.get_value(), value);
132+
}
133+
}
134+
135+
TEST(TesHandle, move_constructor)
136+
{
137+
double value = 1.337;
138+
hardware_interface::Handle handle{JOINT_NAME, FOO_INTERFACE, &value};
139+
hardware_interface::Handle moved{std::move(handle)};
140+
EXPECT_DOUBLE_EQ(moved.get_value(), value);
141+
EXPECT_NO_THROW(moved.set_value(0.0));
142+
EXPECT_DOUBLE_EQ(moved.get_value(), 0.0);
143+
}
144+
145+
TEST(TestHandle, copy_assignment)
146+
{
147+
{
148+
double value_1 = 1.337;
149+
double value_2 = 2.337;
150+
hardware_interface::Handle handle{JOINT_NAME, FOO_INTERFACE, &value_1};
151+
hardware_interface::Handle copy{JOINT_NAME, "random", &value_2};
152+
EXPECT_DOUBLE_EQ(copy.get_value(), value_2);
153+
EXPECT_DOUBLE_EQ(handle.get_value(), value_1);
154+
copy = handle;
155+
EXPECT_DOUBLE_EQ(copy.get_value(), value_1);
156+
EXPECT_DOUBLE_EQ(handle.get_value(), value_1);
157+
EXPECT_NO_THROW(copy.set_value(0.0));
158+
EXPECT_DOUBLE_EQ(copy.get_value(), 0.0);
159+
EXPECT_DOUBLE_EQ(handle.get_value(), 0.0);
160+
EXPECT_DOUBLE_EQ(value_1, 0.0);
161+
EXPECT_DOUBLE_EQ(value_2, 2.337);
162+
}
163+
164+
{
165+
double value = 1.337;
166+
InterfaceInfo info;
167+
info.name = FOO_INTERFACE;
168+
info.data_type = "double";
169+
InterfaceDescription itf_descr{JOINT_NAME, info};
170+
hardware_interface::Handle handle{itf_descr};
171+
EXPECT_TRUE(std::isnan(handle.get_value()));
172+
handle.set_value(value);
173+
hardware_interface::Handle copy = handle;
174+
EXPECT_EQ(copy.get_name(), handle.get_name());
175+
EXPECT_EQ(copy.get_interface_name(), handle.get_interface_name());
176+
EXPECT_EQ(copy.get_prefix_name(), handle.get_prefix_name());
177+
EXPECT_DOUBLE_EQ(copy.get_value(), value);
178+
EXPECT_DOUBLE_EQ(handle.get_value(), value);
179+
EXPECT_NO_THROW(copy.set_value(0.0));
180+
EXPECT_DOUBLE_EQ(copy.get_value(), 0.0);
181+
EXPECT_DOUBLE_EQ(handle.get_value(), value);
182+
EXPECT_NO_THROW(copy.set_value(0.52));
183+
EXPECT_DOUBLE_EQ(copy.get_value(), 0.52);
184+
EXPECT_DOUBLE_EQ(handle.get_value(), value);
185+
}
186+
}
187+
188+
TEST(TestHandle, move_assignment)
189+
{
190+
double value = 1.337;
191+
double value_2 = 2.337;
192+
hardware_interface::Handle handle{JOINT_NAME, FOO_INTERFACE, &value};
193+
hardware_interface::Handle moved{JOINT_NAME, "random", &value_2};
194+
EXPECT_DOUBLE_EQ(moved.get_value(), value_2);
195+
EXPECT_DOUBLE_EQ(handle.get_value(), value);
196+
moved = std::move(handle);
197+
EXPECT_DOUBLE_EQ(moved.get_value(), value);
198+
EXPECT_NO_THROW(moved.set_value(0.0));
199+
EXPECT_DOUBLE_EQ(moved.get_value(), 0.0);
200+
}

0 commit comments

Comments
 (0)