1 | /** |
2 | * Copyright 2021 Alibaba, Inc. and its affiliates. All Rights Reserved. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | |
16 | * \author jiliang.ljl |
17 | * \date Feb 2021 |
18 | * \brief Impl details of AiLego Utility String Helper |
19 | */ |
20 | |
21 | #ifndef __AILEGO_UTILITY_STRING_HELPER_IMPL_H__ |
22 | #define __AILEGO_UTILITY_STRING_HELPER_IMPL_H__ |
23 | |
24 | #include <cstring> |
25 | #include <string> |
26 | #include <vector> |
27 | |
28 | namespace ailego { |
29 | namespace details { |
30 | |
31 | //! Convert string to integers or floating point numbers |
32 | template <typename T> |
33 | static T CStringToType(const char *begin, char **endptr) { |
34 | static_assert( |
35 | std::is_same<T, int32_t>::value || std::is_same<T, int16_t>::value || |
36 | std::is_same<T, int8_t>::value || std::is_same<T, int64_t>::value || |
37 | std::is_same<T, uint64_t>::value || |
38 | std::is_same<T, uint32_t>::value || |
39 | std::is_same<T, uint16_t>::value || std::is_same<T, uint8_t>::value || |
40 | std::is_same<T, float>::value || std::is_same<T, double>::value, |
41 | "type not supported" ); |
42 | if (std::is_same<T, int32_t>::value || std::is_same<T, int16_t>::value || |
43 | std::is_same<T, int8_t>::value) { |
44 | return static_cast<T>(strtol(begin, endptr, 0)); |
45 | } else if (std::is_same<T, int64_t>::value) { |
46 | return static_cast<T>(strtoll(begin, endptr, 0)); |
47 | } else if (std::is_same<T, uint32_t>::value || |
48 | std::is_same<T, uint16_t>::value || |
49 | std::is_same<T, uint8_t>::value) { |
50 | return static_cast<T>(strtoul(begin, endptr, 0)); |
51 | } else if (std::is_same<T, uint64_t>::value) { |
52 | return static_cast<T>(strtoull(begin, endptr, 0)); |
53 | } else if (std::is_same<T, float>::value) { |
54 | return static_cast<T>(strtof(begin, endptr)); |
55 | } else { |
56 | return static_cast<T>(strtod(begin, endptr)); |
57 | } |
58 | } |
59 | |
60 | //! Convert [begin, end) to T |
61 | //! If [end, ) contains valid T symbol, extra overhead will be incurred by |
62 | //! constructing std::string |
63 | template <typename T> |
64 | struct StringToType { |
65 | T operator()(const char *begin, const char *end) { |
66 | char *eptr = nullptr; |
67 | auto v = CStringToType<T>(begin, &eptr); |
68 | if (eptr > end) { |
69 | // NOTE: [begin, end) is not 0 terminated |
70 | // If delimiter contains valid T symbol, eptr might point to location |
71 | // after end. |
72 | // We create string here, which is guaranteed to be 0 terminated. |
73 | std::string s{begin, end}; |
74 | return CStringToType<T>(s.c_str(), &eptr); |
75 | } |
76 | return v; |
77 | } |
78 | }; |
79 | |
80 | //! Specialization for std::string |
81 | template <> |
82 | struct StringToType<std::string> { |
83 | std::string operator()(const char *begin, const char *end) { |
84 | return {begin, end}; |
85 | } |
86 | }; |
87 | |
88 | //! Return delimiter length. |
89 | template <typename T> |
90 | struct DelimiterLen { |
91 | size_t operator()(T delimiter); |
92 | }; |
93 | |
94 | //! Return delimiter length for char. |
95 | template <> |
96 | struct DelimiterLen<char> { |
97 | size_t operator()(char) { |
98 | return 1; |
99 | } |
100 | }; |
101 | |
102 | //! Return delimiter length for const char*. |
103 | template <> |
104 | struct DelimiterLen<const char *> { |
105 | size_t operator()(const char *delimiter) { |
106 | return delimiter == nullptr ? 0 : std::strlen(delimiter); |
107 | } |
108 | }; |
109 | |
110 | //! Return delimiter length for std::string. |
111 | template <> |
112 | struct DelimiterLen<const std::string &> { |
113 | size_t operator()(const std::string &delimiter) { |
114 | return delimiter.size(); |
115 | } |
116 | }; |
117 | |
118 | //! Split implementation. |
119 | template <typename D, typename T, |
120 | typename = typename std::enable_if< |
121 | std::is_same<char, D>::value || |
122 | std::is_same<const std::string &, D>::value || |
123 | std::is_same<const char *, D>::value, |
124 | D>::type> |
125 | static void SplitImpl(const std::string &str, D delim, std::vector<T> *out) { |
126 | StringToType<T> func; |
127 | out->clear(); |
128 | |
129 | auto s = str.data(); |
130 | size_t delimiter_len = DelimiterLen<D>()(delim); |
131 | if (delimiter_len != 0) { |
132 | size_t a = 0, b = str.find(delim); |
133 | while (b != std::string::npos) { |
134 | out->push_back(func(s + a, s + b)); |
135 | a = b + delimiter_len; |
136 | b = str.find(delim, a); |
137 | } |
138 | out->push_back(func(s + a, s + str.length())); |
139 | } else { |
140 | out->push_back(func(s + 0, s + str.length())); |
141 | } |
142 | } |
143 | |
144 | } // namespace details |
145 | } // namespace ailego |
146 | |
147 | #endif |
148 | |