Halide
Util.h
Go to the documentation of this file.
1 // Always use assert, even if llvm-config defines NDEBUG
2 #ifdef NDEBUG
3 #undef NDEBUG
4 #include <assert.h>
5 #define NDEBUG
6 #else
7 #include <assert.h>
8 #endif
9 
10 #ifndef HALIDE_UTIL_H
11 #define HALIDE_UTIL_H
12 
13 /** \file
14  * Various utility functions used internally Halide. */
15 
16 #include <cstdint>
17 #include <utility>
18 #include <vector>
19 #include <string>
20 #include <cstring>
21 
22 #ifndef EXPORT
23 #if defined(_MSC_VER)
24 #ifdef Halide_EXPORTS
25 #define EXPORT __declspec(dllexport)
26 #else
27 #define EXPORT __declspec(dllimport)
28 #endif
29 #else
30 #define EXPORT __attribute__((visibility("default")))
31 #endif
32 #endif
33 
34 // If we're in user code, we don't want certain functions to be inlined.
35 #if defined(COMPILING_HALIDE) || defined(BUILDING_PYTHON)
36 #define NO_INLINE
37 #else
38 #ifdef _WIN32
39 #define NO_INLINE __declspec(noinline)
40 #else
41 #define NO_INLINE __attribute__((noinline))
42 #endif
43 #endif
44 
45 // On windows, Halide needs a larger stack than the default MSVC provides
46 #ifdef _MSC_VER
47 #pragma comment(linker, "/STACK:8388608,1048576")
48 #endif
49 
50 namespace Halide {
51 namespace Internal {
52 
53 /** An aggressive form of reinterpret cast used for correct type-punning. */
54 template<typename DstType, typename SrcType>
55 DstType reinterpret_bits(const SrcType &src) {
56  static_assert(sizeof(SrcType) == sizeof(DstType), "Types must be same size");
57  DstType dst;
58  memcpy(&dst, &src, sizeof(SrcType));
59  return dst;
60 }
61 
62 /** Make a unique name for an object based on the name of the stack
63  * variable passed in. If introspection isn't working or there are no
64  * debug symbols, just uses unique_name with the given prefix. */
65 EXPORT std::string make_entity_name(void *stack_ptr, const std::string &type, char prefix);
66 
67 /** Get value of an environment variable. Returns its value
68  * is defined in the environment. If the var is not defined, an empty string
69  * is returned.
70  */
71 EXPORT std::string get_env_variable(char const *env_var_name);
72 
73 /** Get the name of the currently running executable. Platform-specific.
74  * If program name cannot be retrieved, function returns an empty string. */
75 EXPORT std::string running_program_name();
76 
77 /** Generate a unique name starting with the given prefix. It's unique
78  * relative to all other strings returned by unique_name in this
79  * process.
80  *
81  * The single-character version always appends a numeric suffix to the
82  * character.
83  *
84  * The string version will either return the input as-is (with high
85  * probability on the first time it is called with that input), or
86  * replace any existing '$' characters with underscores, then add a
87  * '$' sign and a numeric suffix to it.
88  *
89  * Note that unique_name('f') therefore differs from
90  * unique_name("f"). The former returns something like f123, and the
91  * latter returns either f or f$123.
92  */
93 // @{
94 EXPORT std::string unique_name(char prefix);
95 EXPORT std::string unique_name(const std::string &prefix);
96 // @}
97 
98 /** Test if the first string starts with the second string */
99 EXPORT bool starts_with(const std::string &str, const std::string &prefix);
100 
101 /** Test if the first string ends with the second string */
102 EXPORT bool ends_with(const std::string &str, const std::string &suffix);
103 
104 /** Replace all matches of the second string in the first string with the last string */
105 EXPORT std::string replace_all(const std::string &str, const std::string &find, const std::string &replace);
106 
107 /** Split the source string using 'delim' as the divider. */
108 EXPORT std::vector<std::string> split_string(const std::string &source, const std::string &delim);
109 
110 /** Perform a left fold of a vector. Returns a default-constructed
111  * vector element if the vector is empty. Similar to std::accumulate
112  * but with a less clunky syntax. */
113 template<typename T, typename Fn>
114 T fold_left(const std::vector<T> &vec, Fn f) {
115  T result;
116  if (vec.empty()) {
117  return result;
118  }
119  result = vec[0];
120  for (size_t i = 1; i < vec.size(); i++) {
121  result = f(result, vec[i]);
122  }
123  return result;
124 }
125 
126 /** Returns a right fold of a vector. Returns a default-constructed
127  * vector element if the vector is empty. */
128 template<typename T, typename Fn>
129 T fold_right(const std::vector<T> &vec, Fn f) {
130  T result;
131  if (vec.empty()) {
132  return result;
133  }
134  result = vec.back();
135  for (size_t i = vec.size()-1; i > 0; i--) {
136  result = f(vec[i-1], result);
137  }
138  return result;
139 }
140 
141 template <typename T1, typename T2, typename T3, typename T4 >
142 inline NO_INLINE void collect_paired_args(std::vector<std::pair<T1, T2>> &collected_args,
143  const T3 &a1, const T4 &a2) {
144  collected_args.push_back(std::pair<T1, T2>(a1, a2));
145 }
146 
147 template <typename T1, typename T2, typename T3, typename T4, typename ...Args>
148 inline NO_INLINE void collect_paired_args(std::vector<std::pair<T1, T2>> &collected_args,
149  const T3 &a1, const T4 &a2, Args&&... args) {
150  collected_args.push_back(std::pair<T1, T2>(a1, a2));
151  collect_paired_args(collected_args, std::forward<Args>(args)...);
152 }
153 
154 template<typename... T>
155 struct meta_and : std::true_type {};
156 
157 template<typename T1, typename... Args>
158 struct meta_and<T1, Args...> : std::integral_constant<bool, T1::value && meta_and<Args...>::value> {};
159 
160 template<typename... T>
161 struct meta_or : std::false_type {};
162 
163 template<typename T1, typename... Args>
164 struct meta_or<T1, Args...> : std::integral_constant<bool, T1::value || meta_or<Args...>::value> {};
165 
166 template<typename To, typename... Args>
167 struct all_are_convertible : meta_and<std::is_convertible<Args, To>...> {};
168 
169 /** Returns base name and fills in namespaces, outermost one first in vector. */
170 EXPORT std::string extract_namespaces(const std::string &name, std::vector<std::string> &namespaces);
171 
172 struct FileStat {
174  uint32_t mod_time; // Unix epoch time
178 };
179 
180 /** Create a unique file with a name of the form prefixXXXXXsuffix in an arbitrary
181  * (but writable) directory; this is typically /tmp, but the specific
182  * location is not guaranteed. (Note that the exact form of the file name
183  * may vary; in particular, the suffix may be ignored on Windows.)
184  * The file is created (but not opened), thus this can be called from
185  * different threads (or processes, e.g. when building with parallel make)
186  * without risking collision. Note that if this file is used as a temporary
187  * file, the caller is responsibly for deleting it. Neither the prefix nor suffix
188  * may contain a directory separator.
189  */
190 EXPORT std::string file_make_temp(const std::string &prefix, const std::string &suffix);
191 
192 /** Create a unique directory in an arbitrary (but writable) directory; this is
193  * typically somewhere inside /tmp, but the specific location is not guaranteed.
194  * The directory will be empty (i.e., this will never return /tmp itself,
195  * but rather a new directory inside /tmp). The caller is responsible for removing the
196  * directory after use.
197  */
198 EXPORT std::string dir_make_temp();
199 
200 /** Wrapper for access(). Quietly ignores errors. */
201 EXPORT bool file_exists(const std::string &name);
202 
203 /** assert-fail if the file doesn't exist. useful primarily for testing purposes. */
204 EXPORT void assert_file_exists(const std::string &name);
205 
206 /** assert-fail if the file DOES exist. useful primarily for testing purposes. */
207 EXPORT void assert_no_file_exists(const std::string &name);
208 
209 /** Wrapper for unlink(). Asserts upon error. */
210 EXPORT void file_unlink(const std::string &name);
211 
212 /** Wrapper for unlink(). Quietly ignores errors. */
213 EXPORT void file_unlink(const std::string &name);
214 
215 /** Ensure that no file with this path exists. If such a file
216  * exists and cannot be removed, assert-fail. */
217 EXPORT void ensure_no_file_exists(const std::string &name);
218 
219 /** Wrapper for rmdir(). Asserts upon error. */
220 EXPORT void dir_rmdir(const std::string &name);
221 
222 /** Wrapper for stat(). Asserts upon error. */
223 EXPORT FileStat file_stat(const std::string &name);
224 
225 /** A simple utility class that creates a temporary file in its ctor and
226  * deletes that file in its dtor; this is useful for temporary files that you
227  * want to ensure are deleted when exiting a certain scope. Since this is essentially
228  * just an RAII wrapper around file_make_temp() and file_unlink(), it has the same
229  * failure modes (i.e.: assertion upon error).
230  */
231 class TemporaryFile final {
232 public:
233  TemporaryFile(const std::string &prefix, const std::string &suffix)
234  : temp_path(file_make_temp(prefix, suffix)), do_unlink(true) {}
235  const std::string &pathname() const { return temp_path; }
236  ~TemporaryFile() { if (do_unlink) { file_unlink(temp_path); } }
237  // You can call this if you want to defeat the automatic deletion;
238  // this is rarely what you want to do (since it defeats the purpose
239  // of this class), but can be quite handy for debugging purposes.
240  void detach() { do_unlink = false; }
241 private:
242  const std::string temp_path;
243  bool do_unlink;
244  TemporaryFile(const TemporaryFile &) = delete;
245  void operator=(const TemporaryFile &) = delete;
246 };
247 
248 /** Routines to test if math would overflow for signed integers with
249  * the given number of bits. */
250 // @{
251 bool add_would_overflow(int bits, int64_t a, int64_t b);
252 bool sub_would_overflow(int bits, int64_t a, int64_t b);
253 bool mul_would_overflow(int bits, int64_t a, int64_t b);
254 // @}
255 
256 /** Helper class for saving/restoring variable values on the stack, to allow
257  * for early-exit that preserves correctness */
258 template<typename T>
259 struct ScopedValue {
260  T &var;
261  const T old_value;
262  /** Preserve the old value, restored at dtor time */
263  ScopedValue(T &var) : var(var), old_value(var) {}
264  /** Preserve the old value, then set the var to a new value. */
265  ScopedValue(T &var, T new_value) : var(var), old_value(var) { var = new_value; }
266  ~ScopedValue() { var = old_value; }
267  operator T() const { return old_value; }
268 };
269 
270 // Wrappers for some C++14-isms that are useful and trivially implementable
271 // in C++11; these are defined in the Halide::Internal namespace. If we
272 // are compiling under C++14 or later, we just use the standard implementations
273 // rather than our own.
274 #if __cplusplus >= 201402L
275 
276 // C++14: Use the standard implementations
277 using std::integer_sequence;
279 using std::index_sequence;
281 
282 #else
283 
284 // C++11: std::integer_sequence (etc) is standard in C++14 but not C++11, but
285 // is easily written in C++11. This is a simple version that could
286 // probably be improved.
287 
288 template<typename T, T... Ints>
290  static constexpr size_t size() { return sizeof...(Ints); }
291 };
292 
293 template<typename T>
295 
296 template<typename T, T... Ints>
298  using type = integer_sequence<T, Ints..., sizeof...(Ints)>;
299 };
300 
301 template<typename T, T I, T N>
303  using type = typename next_integer_sequence<
306 };
307 
308 template<typename T, T N>
310  using type = integer_sequence<T>;
311 };
312 
313 template<typename T, T N>
315 
316 template<size_t... Ints>
318 
319 template<size_t N>
321 
322 #endif
323 
324 } // namespace Internal
325 } // namespace Halide
326 
327 #endif
EXPORT bool ends_with(const std::string &str, const std::string &suffix)
Test if the first string ends with the second string.
EXPORT std::string make_entity_name(void *stack_ptr, const std::string &type, char prefix)
Make a unique name for an object based on the name of the stack variable passed in.
EXPORT std::string running_program_name()
Get the name of the currently running executable.
EXPORT std::string get_env_variable(char const *env_var_name)
Get value of an environment variable.
DstType reinterpret_bits(const SrcType &src)
An aggressive form of reinterpret cast used for correct type-punning.
Definition: Util.h:55
NO_INLINE void collect_paired_args(std::vector< std::pair< T1, T2 >> &collected_args, const T3 &a1, const T4 &a2)
Definition: Util.h:142
T fold_left(const std::vector< T > &vec, Fn f)
Perform a left fold of a vector.
Definition: Util.h:114
EXPORT FileStat file_stat(const std::string &name)
Wrapper for stat().
ScopedValue(T &var, T new_value)
Preserve the old value, then set the var to a new value.
Definition: Util.h:265
EXPORT std::string replace_all(const std::string &str, const std::string &find, const std::string &replace)
Replace all matches of the second string in the first string with the last string.
void * memcpy(void *s1, const void *s2, size_t n)
EXPORT bool file_exists(const std::string &name)
Wrapper for access().
typename make_integer_sequence_helper< T, 0, N >::type make_integer_sequence
Definition: Util.h:314
EXPORT std::string dir_make_temp()
Create a unique directory in an arbitrary (but writable) directory; this is typically somewhere insid...
Defines methods for manipulating and analyzing boolean expressions.
EXPORT void ensure_no_file_exists(const std::string &name)
Ensure that no file with this path exists.
EXPORT bool starts_with(const std::string &str, const std::string &prefix)
Test if the first string starts with the second string.
EXPORT void dir_rmdir(const std::string &name)
Wrapper for rmdir().
EXPORT std::vector< std::string > split_string(const std::string &source, const std::string &delim)
Split the source string using &#39;delim&#39; as the divider.
EXPORT std::string unique_name(char prefix)
Generate a unique name starting with the given prefix.
static constexpr size_t size()
Definition: Util.h:290
EXPORT std::string file_make_temp(const std::string &prefix, const std::string &suffix)
Create a unique file with a name of the form prefixXXXXXsuffix in an arbitrary (but writable) directo...
ScopedValue(T &var)
Preserve the old value, restored at dtor time.
Definition: Util.h:263
make_integer_sequence< size_t, N > make_index_sequence
Definition: Util.h:320
#define NO_INLINE
Definition: Util.h:41
typename next_integer_sequence< typename make_integer_sequence_helper< T, I+1, N >::type >::type type
Definition: Util.h:305
EXPORT void file_unlink(const std::string &name)
Wrapper for unlink().
unsigned __INT32_TYPE__ uint32_t
EXPORT void assert_no_file_exists(const std::string &name)
assert-fail if the file DOES exist.
char * dst
Definition: printer.h:30
EXPORT void assert_file_exists(const std::string &name)
assert-fail if the file doesn&#39;t exist.
EXPORT std::string extract_namespaces(const std::string &name, std::vector< std::string > &namespaces)
Returns base name and fills in namespaces, outermost one first in vector.
signed __INT64_TYPE__ int64_t
bool mul_would_overflow(int bits, int64_t a, int64_t b)
Routines to test if math would overflow for signed integers with the given number of bits...
TemporaryFile(const std::string &prefix, const std::string &suffix)
Definition: Util.h:233
__SIZE_TYPE__ size_t
T fold_right(const std::vector< T > &vec, Fn f)
Returns a right fold of a vector.
Definition: Util.h:129
bool sub_would_overflow(int bits, int64_t a, int64_t b)
Routines to test if math would overflow for signed integers with the given number of bits...
A simple utility class that creates a temporary file in its ctor and deletes that file in its dtor; t...
Definition: Util.h:231
#define EXPORT
Definition: Util.h:30
unsigned __INT64_TYPE__ uint64_t
integer_sequence< size_t, Ints... > index_sequence
Definition: Util.h:317
bool add_would_overflow(int bits, int64_t a, int64_t b)
Routines to test if math would overflow for signed integers with the given number of bits...
Helper class for saving/restoring variable values on the stack, to allow for early-exit that preserve...
Definition: Util.h:259
const std::string & pathname() const
Definition: Util.h:235