blob: 8af274783196d447fd0e9e34e456d34a932b2de1 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/*!
* \file utils.h
* \brief Defines some common utility function..
*/
#ifndef TVM_SUPPORT_UTILS_H_
#define TVM_SUPPORT_UTILS_H_
#include <stdio.h>
#ifndef _WIN32
#include <sys/types.h>
#ifndef __hexagon__
#include <sys/wait.h>
#endif // __hexagon__
#endif // _WIN32
#include <tvm/ffi/string.h>
#include <algorithm>
#include <array>
#include <cctype>
#include <cstdlib>
#include <memory>
#include <sstream>
#include <string>
#include <vector>
namespace tvm {
namespace support {
/*!
* \brief TVMPOpen wrapper of popen between windows / unix.
* \param command executed command
* \param type "r" is for reading or "w" for writing.
* \return normal standard stream
*/
#ifndef __hexagon__
inline FILE* TVMPOpen(const char* command, const char* type) {
#if defined(_WIN32)
return _popen(command, type);
#else
return popen(command, type);
#endif
}
#endif // __hexagon__
/*!
* \brief TVMPClose wrapper of pclose between windows / linux
* \param stream the stream needed to be close.
* \return exit status
*/
#ifndef __hexagon__
inline int TVMPClose(FILE* stream) {
#if defined(_WIN32)
return _pclose(stream);
#else
return pclose(stream);
#endif
}
#endif // __hexagon__
/*!
* \brief TVMWifexited wrapper of WIFEXITED between windows / linux
* \param status The status field that was filled in by the wait or waitpid function
* \return the exit code of the child process
*/
#ifndef __hexagon__
inline int TVMWifexited(int status) {
#if defined(_WIN32)
return (status != 3);
#else
return WIFEXITED(status);
#endif
}
#endif // __hexagon__
/*!
* \brief TVMWexitstatus wrapper of WEXITSTATUS between windows / linux
* \param status The status field that was filled in by the wait or waitpid function.
* \return the child process exited normally or not
*/
#ifndef __hexagon__
inline int TVMWexitstatus(int status) {
#if defined(_WIN32)
return status;
#else
return WEXITSTATUS(status);
#endif
}
#endif // __hexagon__
/*!
* \brief IsNumber check whether string is a number.
* \param str input string
* \return result of operation.
*/
inline bool IsNumber(const std::string& str) {
return !str.empty() &&
std::find_if(str.begin(), str.end(), [](char c) { return !std::isdigit(c); }) == str.end();
}
/*!
* \brief split Split the string based on delimiter
* \param str Input string
* \param delim The delimiter.
* \return vector of strings which are splitted.
*/
inline std::vector<std::string> Split(const std::string& str, char delim) {
std::string item;
std::istringstream is(str);
std::vector<std::string> ret;
while (std::getline(is, item, delim)) {
ret.push_back(item);
}
return ret;
}
/*!
* \brief Check whether the string starts with a given prefix.
* \param str The given string.
* \param prefix The given prefix.
* \return Whether the prefix matched.
*/
inline bool StartsWith(const ffi::String& str, const char* prefix) {
const char* data = str.data();
const char* data_end = data + str.size();
for (; data != data_end; ++data, ++prefix) {
if (*prefix == '\0') return true;
if (*data != *prefix) return false;
}
// return true if the str is equal to the prefix
return *prefix == '\0';
}
/*!
* \brief EndsWith check whether the strings ends with
* \param value The full string
* \param end The end substring
* \return bool The result.
*/
inline bool EndsWith(std::string const& value, std::string const& end) {
if (end.size() <= value.size()) {
return std::equal(end.rbegin(), end.rend(), value.rbegin());
}
return false;
}
/*!
* \brief Execute the command
* \param cmd The command we want to execute
* \param err_msg The error message if we have
* \return executed output status
*/
#ifndef __hexagon__
inline int Execute(std::string cmd, std::string* err_msg) {
std::array<char, 128> buffer;
std::string result;
cmd += " 2>&1";
FILE* fd = TVMPOpen(cmd.c_str(), "r");
while (fgets(buffer.data(), buffer.size(), fd) != nullptr) {
*err_msg += buffer.data();
}
int status = TVMPClose(fd);
if (TVMWifexited(status)) {
return TVMWexitstatus(status);
}
return 255;
}
#endif // __hexagon__
/*!
* \brief hash an object and combines uint64_t key with previous keys
*
* This hash function is stable across platforms.
*
* \param key The left operand.
* \param value The right operand.
* \return the combined result.
*/
template <typename T, std::enable_if_t<std::is_convertible<T, uint64_t>::value, bool> = true>
inline uint64_t HashCombine(uint64_t key, const T& value) {
// XXX: do not use std::hash in this function. This hash must be stable
// across different platforms and std::hash is implementation dependent.
return key ^ (uint64_t(value) + 0x9e3779b9 + (key << 6) + (key >> 2));
}
/*!
* \brief Return whether a boolean flag is set as an environment variable.
*
* Returns true if the environment variable is set to a non-zero
* integer, or to a non-empty string that is not an integer.
*
* Returns false if the environment variable is unset, if the
* environment variable is set to the integer zero, or if the
* environment variable is an empty string.
*/
inline bool BoolEnvironmentVar(const char* varname) {
const char* var = std::getenv(varname);
if (!var) {
return false;
}
int x = 0;
std::istringstream is(var);
if (is >> x) {
return x;
}
return *var;
}
} // namespace support
} // namespace tvm
#endif // TVM_SUPPORT_UTILS_H_