1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
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 
16 #ifndef UTIL_STRING_UTIL_H
17 #define UTIL_STRING_UTIL_H
18 
19 #include <algorithm>
20 #include <cctype>
21 #include <cstdint>
22 #include <iterator>
23 
24 #include <base/containers/string_view.h>
25 #include <base/containers/vector.h>
26 #include <render/namespace.h>
27 
28 #include "util/log.h"
29 
RENDER_BEGIN_NAMESPACE()30 RENDER_BEGIN_NAMESPACE()
31 namespace StringUtil {
32 template<class T, size_t N>
33 constexpr size_t MaxStringLengthFromArray(T (&)[N])
34 {
35     return N - 1u;
36 }
37 
38 inline void CopyStringToArray(const BASE_NS::string_view source, char* target, size_t maxLength)
39 {
40     if (source.size() > maxLength) {
41         PLUGIN_LOG_W("CopyStringToArray: string (%zu) longer than %zu", source.size(), maxLength);
42     }
43     size_t const length = source.copy(target, maxLength);
44     target[length] = '\0';
45 }
46 
47 inline bool NotSpace(unsigned char ch)
48 {
49     return !std::isspace(static_cast<int>(ch));
50 }
51 
52 // trim from start (in place)
53 inline void LTrim(BASE_NS::string_view& string)
54 {
55     auto const count = size_t(std::find_if(string.begin(), string.end(), NotSpace) - string.begin());
56     string.remove_prefix(count);
57 }
58 
59 // trim from end (in place)
60 inline void RTrim(BASE_NS::string_view& string)
61 {
62     auto const count =
63         size_t(std::distance(std::find_if(string.rbegin(), string.rend(), NotSpace).base(), string.end()));
64     string.remove_suffix(count);
65 }
66 
67 // trim from both ends (in place)
68 inline size_t Trim(BASE_NS::string_view& string)
69 {
70     RTrim(string);
71     LTrim(string);
72     return string.length();
73 }
74 
75 inline BASE_NS::vector<BASE_NS::string_view> Split(
76     const BASE_NS::string_view string, const BASE_NS::string_view delims = "|")
77 {
78     BASE_NS::vector<BASE_NS::string_view> output;
79     auto left = string;
80 
81     while (!left.empty()) {
82         auto const pos = left.find_first_of(delims);
83 
84         auto found = left.substr(0, pos);
85         if (Trim(found) > 0) {
86             output.push_back(found);
87         }
88         if (pos != BASE_NS::string_view::npos) {
89             left.remove_prefix(pos + 1);
90         } else {
91             break;
92         }
93     }
94 
95     return output;
96 }
97 
98 // find and replace first instance of "find" with "replace" in "source"
99 inline bool FindAndReplaceOne(
100     BASE_NS::string& source, const BASE_NS::string_view find, const BASE_NS::string_view replace)
101 {
102     const auto p = source.find(find);
103     if (p != BASE_NS::string::npos) {
104         source.replace(source.begin() + static_cast<BASE_NS::string::difference_type>(p),
105             source.begin() + static_cast<BASE_NS::string::difference_type>(p + find.length()), replace);
106     }
107     return (p != BASE_NS::string::npos);
108 }
109 // find and replace all instances of "find" with "replace" in "source"
110 inline void FindAndReplaceAll(
111     BASE_NS::string& source, const BASE_NS::string_view find, const BASE_NS::string_view replace)
112 {
113     while (FindAndReplaceOne(source, find, replace))
114         ;
115 }
116 } // namespace StringUtil
117 RENDER_END_NAMESPACE()
118 
119 #endif // UTIL_STRING_UTIL_H
120