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
28namespace ailego {
29namespace details {
30
31//! Convert string to integers or floating point numbers
32template <typename T>
33static 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
63template <typename T>
64struct 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
81template <>
82struct StringToType<std::string> {
83 std::string operator()(const char *begin, const char *end) {
84 return {begin, end};
85 }
86};
87
88//! Return delimiter length.
89template <typename T>
90struct DelimiterLen {
91 size_t operator()(T delimiter);
92};
93
94//! Return delimiter length for char.
95template <>
96struct DelimiterLen<char> {
97 size_t operator()(char) {
98 return 1;
99 }
100};
101
102//! Return delimiter length for const char*.
103template <>
104struct 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.
111template <>
112struct DelimiterLen<const std::string &> {
113 size_t operator()(const std::string &delimiter) {
114 return delimiter.size();
115 }
116};
117
118//! Split implementation.
119template <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>
125static 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