ros2_control - jazzy
Loading...
Searching...
No Matches
lexical_casts.hpp
1// Copyright 2023 ros2_control Development Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#ifndef HARDWARE_INTERFACE__LEXICAL_CASTS_HPP_
16#define HARDWARE_INTERFACE__LEXICAL_CASTS_HPP_
17
18#include <regex>
19#include <sstream>
20#include <stdexcept>
21#include <string>
22#include <type_traits>
23#include <vector>
24
25namespace hardware_interface
26{
27
33double stod(const std::string & s);
34
35bool parse_bool(const std::string & bool_string);
36
37template <typename T>
38std::vector<T> parse_array(const std::string & array_string)
39{
40 // Use regex to check for a flat array: starts with [, ends with ], no nested brackets
41 const std::regex array_regex(R"(^\[\s*([^\[\]]*\s*(,\s*[^\[\]]+\s*)*)?\]$)");
42 if (!std::regex_match(array_string, array_regex))
43 {
44 throw std::invalid_argument(
45 "String must be a flat array: starts with '[' and ends with ']', no nested arrays");
46 }
47
48 // Use regex for the expression that either empty or contains only spaces
49 const std::regex empty_or_spaces_regex(R"(^\[\s*\]$)");
50 if (std::regex_match(array_string, empty_or_spaces_regex))
51 {
52 return {}; // Return empty array if input is "[]"
53 }
54
55 // Use regex to find cases of comma-separated but only whitespaces or no spaces between them like
56 // "[,]" "[a,b,,c]"
57 const std::regex comma_separated_regex(R"(^\[\s*([^,\s]+(\s*,\s*[^,\s]+)*)?\s*\]$)");
58 if (!std::regex_match(array_string, comma_separated_regex))
59 {
60 throw std::invalid_argument(
61 "String must be a flat array with comma-separated values and no spaces between them");
62 }
63
64 std::vector<T> result = {};
65 if (array_string == "[]")
66 {
67 return result; // Return empty array if input is "[]"
68 }
69
70 // regex for comma separated values and no spaces between them or just content like "[a,b,c]" or
71 // "[a]" or "[a, b, c]"
72 const std::regex value_regex(R"([^\s,\[\]]+)");
73 auto begin = std::sregex_iterator(array_string.begin(), array_string.end(), value_regex);
74 auto end = std::sregex_iterator();
75
76 for (auto it = begin; it != end; ++it)
77 {
78 const std::string value_str = it->str(); // Get the first capturing group
79 if constexpr (std::is_same_v<T, std::string>)
80 {
81 result.push_back(value_str);
82 }
83 else if constexpr (std::is_same_v<T, bool>)
84 {
85 result.push_back(parse_bool(value_str));
86 }
87 else if constexpr (std::is_floating_point_v<T> || std::is_integral_v<T>)
88 {
89 try
90 {
91 const T value = static_cast<T>(hardware_interface::stod(value_str));
92 result.push_back(value);
93 }
94 catch (const std::exception &)
95 {
96 throw std::invalid_argument(
97 "Failed converting string to floating point or integer: " + value_str);
98 }
99 }
100 else
101 {
102 throw std::invalid_argument("Unsupported type for parsing: " + std::string(typeid(T).name()));
103 }
104 }
105 return result;
106}
107
108std::vector<std::string> parse_string_array(const std::string & string_array_string);
109
110} // namespace hardware_interface
111
112#endif // HARDWARE_INTERFACE__LEXICAL_CASTS_HPP_
Definition actuator.hpp:22
double stod(const std::string &s)
Helper function to convert a std::string to double in a locale-independent way.
Definition lexical_casts.cpp:56