1 | /* |
2 | * Licensed to the Apache Software Foundation (ASF) under one |
3 | * or more contributor license agreements. See the NOTICE file |
4 | * distributed with this work for additional information |
5 | * regarding copyright ownership. The ASF licenses this file |
6 | * to you under the Apache License, Version 2.0 (the |
7 | * "License"); you may not use this file except in compliance |
8 | * with the License. You may obtain a copy of the License at |
9 | * |
10 | * http://www.apache.org/licenses/LICENSE-2.0 |
11 | * |
12 | * Unless required by applicable law or agreed to in writing, |
13 | * software distributed under the License is distributed on an |
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
15 | * KIND, either express or implied. See the License for the |
16 | * specific language governing permissions and limitations |
17 | * under the License. |
18 | */ |
19 | |
20 | /*! |
21 | * \file utils.h |
22 | * \brief Defines some common utility function.. |
23 | */ |
24 | #ifndef TVM_SUPPORT_UTILS_H_ |
25 | #define TVM_SUPPORT_UTILS_H_ |
26 | |
27 | #include <stdio.h> |
28 | #ifndef _WIN32 |
29 | #include <sys/types.h> |
30 | #ifndef __hexagon__ |
31 | #include <sys/wait.h> |
32 | #endif // __hexagon__ |
33 | #endif // _WIN32 |
34 | |
35 | #include <tvm/runtime/container/string.h> |
36 | |
37 | #include <algorithm> |
38 | #include <array> |
39 | #include <cctype> |
40 | #include <cstdlib> |
41 | #include <memory> |
42 | #include <sstream> |
43 | #include <string> |
44 | #include <vector> |
45 | |
46 | namespace tvm { |
47 | namespace support { |
48 | /*! |
49 | * \brief TVMPOpen wrapper of popen between windows / unix. |
50 | * \param command executed command |
51 | * \param type "r" is for reading or "w" for writing. |
52 | * \return normal standard stream |
53 | */ |
54 | #ifndef __hexagon__ |
55 | inline FILE* TVMPOpen(const char* command, const char* type) { |
56 | #if defined(_WIN32) |
57 | return _popen(command, type); |
58 | #else |
59 | return popen(command, type); |
60 | #endif |
61 | } |
62 | #endif // __hexagon__ |
63 | |
64 | /*! |
65 | * \brief TVMPClose wrapper of pclose between windows / linux |
66 | * \param stream the stream needed to be close. |
67 | * \return exit status |
68 | */ |
69 | #ifndef __hexagon__ |
70 | inline int TVMPClose(FILE* stream) { |
71 | #if defined(_WIN32) |
72 | return _pclose(stream); |
73 | #else |
74 | return pclose(stream); |
75 | #endif |
76 | } |
77 | #endif // __hexagon__ |
78 | |
79 | /*! |
80 | * \brief TVMWifexited wrapper of WIFEXITED between windows / linux |
81 | * \param status The status field that was filled in by the wait or waitpid function |
82 | * \return the exit code of the child process |
83 | */ |
84 | #ifndef __hexagon__ |
85 | inline int TVMWifexited(int status) { |
86 | #if defined(_WIN32) |
87 | return (status != 3); |
88 | #else |
89 | return WIFEXITED(status); |
90 | #endif |
91 | } |
92 | #endif // __hexagon__ |
93 | |
94 | /*! |
95 | * \brief TVMWexitstatus wrapper of WEXITSTATUS between windows / linux |
96 | * \param status The status field that was filled in by the wait or waitpid function. |
97 | * \return the child process exited normally or not |
98 | */ |
99 | #ifndef __hexagon__ |
100 | inline int TVMWexitstatus(int status) { |
101 | #if defined(_WIN32) |
102 | return status; |
103 | #else |
104 | return WEXITSTATUS(status); |
105 | #endif |
106 | } |
107 | #endif // __hexagon__ |
108 | |
109 | /*! |
110 | * \brief IsNumber check whether string is a number. |
111 | * \param str input string |
112 | * \return result of operation. |
113 | */ |
114 | inline bool IsNumber(const std::string& str) { |
115 | return !str.empty() && |
116 | std::find_if(str.begin(), str.end(), [](char c) { return !std::isdigit(c); }) == str.end(); |
117 | } |
118 | |
119 | /*! |
120 | * \brief split Split the string based on delimiter |
121 | * \param str Input string |
122 | * \param delim The delimiter. |
123 | * \return vector of strings which are splitted. |
124 | */ |
125 | inline std::vector<std::string> Split(const std::string& str, char delim) { |
126 | std::string item; |
127 | std::istringstream is(str); |
128 | std::vector<std::string> ret; |
129 | while (std::getline(is, item, delim)) { |
130 | ret.push_back(item); |
131 | } |
132 | return ret; |
133 | } |
134 | |
135 | /*! |
136 | * \brief Check whether the string starts with a given prefix. |
137 | * \param str The given string. |
138 | * \param prefix The given prefix. |
139 | * \return Whether the prefix matched. |
140 | */ |
141 | inline bool StartsWith(const String& str, const char* prefix) { |
142 | size_t n = str.length(); |
143 | for (size_t i = 0; i < n; i++) { |
144 | if (prefix[i] == '\0') return true; |
145 | if (str.data()[i] != prefix[i]) return false; |
146 | } |
147 | // return true if the str is equal to the prefix |
148 | return prefix[n] == '\0'; |
149 | } |
150 | |
151 | /*! |
152 | * \brief EndsWith check whether the strings ends with |
153 | * \param value The full string |
154 | * \param end The end substring |
155 | * \return bool The result. |
156 | */ |
157 | inline bool EndsWith(std::string const& value, std::string const& end) { |
158 | if (end.size() <= value.size()) { |
159 | return std::equal(end.rbegin(), end.rend(), value.rbegin()); |
160 | } |
161 | return false; |
162 | } |
163 | |
164 | /*! |
165 | * \brief Execute the command |
166 | * \param cmd The command we want to execute |
167 | * \param err_msg The error message if we have |
168 | * \return executed output status |
169 | */ |
170 | #ifndef __hexagon__ |
171 | inline int Execute(std::string cmd, std::string* err_msg) { |
172 | std::array<char, 128> buffer; |
173 | std::string result; |
174 | cmd += " 2>&1" ; |
175 | FILE* fd = TVMPOpen(cmd.c_str(), "r" ); |
176 | while (fgets(buffer.data(), buffer.size(), fd) != nullptr) { |
177 | *err_msg += buffer.data(); |
178 | } |
179 | int status = TVMPClose(fd); |
180 | if (TVMWifexited(status)) { |
181 | return TVMWexitstatus(status); |
182 | } |
183 | return 255; |
184 | } |
185 | #endif // __hexagon__ |
186 | |
187 | /*! |
188 | * \brief hash an object and combines uint64_t key with previous keys |
189 | * |
190 | * This hash function is stable across platforms. |
191 | * |
192 | * \param key The left operand. |
193 | * \param value The right operand. |
194 | * \return the combined result. |
195 | */ |
196 | template <typename T, std::enable_if_t<std::is_convertible<T, uint64_t>::value, bool> = true> |
197 | inline uint64_t HashCombine(uint64_t key, const T& value) { |
198 | // XXX: do not use std::hash in this function. This hash must be stable |
199 | // across different platforms and std::hash is implementation dependent. |
200 | return key ^ (uint64_t(value) + 0x9e3779b9 + (key << 6) + (key >> 2)); |
201 | } |
202 | |
203 | /*! |
204 | * \brief Return whether a boolean flag is set as an environment variable. |
205 | * |
206 | * Returns true if the environment variable is set to a non-zero |
207 | * integer, or to a non-empty string that is not an integer. |
208 | * |
209 | * Returns false if the environment variable is unset, if the |
210 | * environment variable is set to the integer zero, or if the |
211 | * environment variable is an empty string. |
212 | */ |
213 | inline bool BoolEnvironmentVar(const char* varname) { |
214 | const char* var = std::getenv(varname); |
215 | if (!var) { |
216 | return false; |
217 | } |
218 | |
219 | int x = 0; |
220 | std::istringstream is(var); |
221 | if (is >> x) { |
222 | return x; |
223 | } |
224 | |
225 | return *var; |
226 | } |
227 | |
228 | } // namespace support |
229 | } // namespace tvm |
230 | #endif // TVM_SUPPORT_UTILS_H_ |
231 | |