1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
|
#ifndef slic3r_Utils_hpp_
#define slic3r_Utils_hpp_
#include <locale>
#include <utility>
#include <functional>
#include <type_traits>
#include <system_error>
#include "libslic3r.h"
namespace boost { namespace filesystem { class directory_entry; }}
namespace Slic3r {
extern void set_logging_level(unsigned int level);
extern unsigned get_logging_level();
extern void trace(unsigned int level, const char *message);
// Format memory allocated, separate thousands by comma.
extern std::string format_memsize_MB(size_t n);
// Return string to be added to the boost::log output to inform about the current process memory allocation.
// The string is non-empty if the loglevel >= info (3) or ignore_loglevel==true.
// Latter is used to get the memory info from SysInfoDialog.
extern std::string log_memory_info(bool ignore_loglevel = false);
extern void disable_multi_threading();
// Returns the size of physical memory (RAM) in bytes.
extern size_t total_physical_memory();
// Set a path with GUI resource files.
void set_var_dir(const std::string &path);
// Return a full path to the GUI resource files.
const std::string& var_dir();
// Return a full resource path for a file_name.
std::string var(const std::string &file_name);
// Set a path with various static definition data (for example the initial config bundles).
void set_resources_dir(const std::string &path);
// Return a full path to the resources directory.
const std::string& resources_dir();
// Set a path with GUI localization files.
void set_local_dir(const std::string &path);
// Return a full path to the localization directory.
const std::string& localization_dir();
// Set a path with preset files.
void set_data_dir(const std::string &path);
// Return a full path to the GUI resource files.
const std::string& data_dir();
// A special type for strings encoded in the local Windows 8-bit code page.
// This type is only needed for Perl bindings to relay to Perl that the string is raw, not UTF-8 encoded.
typedef std::string local_encoded_string;
// Convert an UTF-8 encoded string into local coding.
// On Windows, the UTF-8 string is converted to a local 8-bit code page.
// On OSX and Linux, this function does no conversion and returns a copy of the source string.
extern local_encoded_string encode_path(const char *src);
extern std::string decode_path(const char *src);
extern std::string normalize_utf8_nfc(const char *src);
// Safely rename a file even if the target exists.
// On Windows, the file explorer (or anti-virus or whatever else) often locks the file
// for a short while, so the file may not be movable. Retry while we see recoverable errors.
extern std::error_code rename_file(const std::string &from, const std::string &to);
enum CopyFileResult {
SUCCESS = 0,
FAIL_COPY_FILE,
FAIL_FILES_DIFFERENT,
FAIL_RENAMING,
FAIL_CHECK_ORIGIN_NOT_OPENED,
FAIL_CHECK_TARGET_NOT_OPENED
};
// Copy a file, adjust the access attributes, so that the target is writable.
CopyFileResult copy_file_inner(const std::string &from, const std::string &to);
// Copy file to a temp file first, then rename it to the final file name.
// If with_check is true, then the content of the copied file is compared to the content
// of the source file before renaming.
extern CopyFileResult copy_file(const std::string &from, const std::string &to, const bool with_check = false);
// Compares two files if identical.
extern CopyFileResult check_copy(const std::string& origin, const std::string& copy);
// Ignore system and hidden files, which may be created by the DropBox synchronisation process.
// https://github.com/prusa3d/PrusaSlicer/issues/1298
extern bool is_plain_file(const boost::filesystem::directory_entry &path);
extern bool is_ini_file(const boost::filesystem::directory_entry &path);
extern bool is_idx_file(const boost::filesystem::directory_entry &path);
// File path / name / extension splitting utilities, working with UTF-8,
// to be published to Perl.
namespace PerlUtils {
// Get a file name including the extension.
extern std::string path_to_filename(const char *src);
// Get a file name without the extension.
extern std::string path_to_stem(const char *src);
// Get just the extension.
extern std::string path_to_extension(const char *src);
// Get a directory without the trailing slash.
extern std::string path_to_parent_path(const char *src);
};
std::string string_printf(const char *format, ...);
// Standard "generated by Slic3r version xxx timestamp xxx" header string,
// to be placed at the top of Slic3r generated files.
std::string header_slic3r_generated();
// getpid platform wrapper
extern unsigned get_current_pid();
template <typename Real>
Real round_nearest(Real value, unsigned int decimals)
{
Real res = (Real)0;
if (decimals == 0)
res = ::round(value);
else
{
Real power = ::pow((Real)10, (int)decimals);
res = ::round(value * power + (Real)0.5) / power;
}
return res;
}
// Compute the next highest power of 2 of 32-bit v
// http://graphics.stanford.edu/~seander/bithacks.html
inline uint16_t next_highest_power_of_2(uint16_t v)
{
if (v != 0)
-- v;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
return ++ v;
}
inline uint32_t next_highest_power_of_2(uint32_t v)
{
if (v != 0)
-- v;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
return ++ v;
}
inline uint64_t next_highest_power_of_2(uint64_t v)
{
if (v != 0)
-- v;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v |= v >> 32;
return ++ v;
}
// On some implementations (such as some versions of clang), the size_t is a type of its own, so we need to overload for size_t.
// Typically, though, the size_t type aliases to uint64_t / uint32_t.
// We distinguish that here and provide implementation for size_t if and only if it is a distinct type
template<class T> size_t next_highest_power_of_2(T v,
typename std::enable_if<std::is_same<T, size_t>::value, T>::type = 0, // T is size_t
typename std::enable_if<!std::is_same<T, uint64_t>::value, T>::type = 0, // T is not uint64_t
typename std::enable_if<!std::is_same<T, uint32_t>::value, T>::type = 0, // T is not uint32_t
typename std::enable_if<sizeof(T) == 8, T>::type = 0) // T is 64 bits
{
return next_highest_power_of_2(uint64_t(v));
}
template<class T> size_t next_highest_power_of_2(T v,
typename std::enable_if<std::is_same<T, size_t>::value, T>::type = 0, // T is size_t
typename std::enable_if<!std::is_same<T, uint64_t>::value, T>::type = 0, // T is not uint64_t
typename std::enable_if<!std::is_same<T, uint32_t>::value, T>::type = 0, // T is not uint32_t
typename std::enable_if<sizeof(T) == 4, T>::type = 0) // T is 32 bits
{
return next_highest_power_of_2(uint32_t(v));
}
template<typename INDEX_TYPE>
inline INDEX_TYPE prev_idx_modulo(INDEX_TYPE idx, const INDEX_TYPE count)
{
if (idx == 0)
idx = count;
return -- idx;
}
template<typename INDEX_TYPE>
inline INDEX_TYPE next_idx_modulo(INDEX_TYPE idx, const INDEX_TYPE count)
{
if (++ idx == count)
idx = 0;
return idx;
}
template<typename CONTAINER_TYPE>
inline typename CONTAINER_TYPE::size_type prev_idx_modulo(typename CONTAINER_TYPE::size_type idx, const CONTAINER_TYPE &container)
{
return prev_idx_modulo(idx, container.size());
}
template<typename CONTAINER_TYPE>
inline typename CONTAINER_TYPE::size_type next_idx_modulo(typename CONTAINER_TYPE::size_type idx, const CONTAINER_TYPE &container)
{
return next_idx_modulo(idx, container.size());
}
template<typename CONTAINER_TYPE>
inline const typename CONTAINER_TYPE::value_type& prev_value_modulo(typename CONTAINER_TYPE::size_type idx, const CONTAINER_TYPE &container)
{
return container[prev_idx_modulo(idx, container.size())];
}
template<typename CONTAINER_TYPE>
inline typename CONTAINER_TYPE::value_type& prev_value_modulo(typename CONTAINER_TYPE::size_type idx, CONTAINER_TYPE &container)
{
return container[prev_idx_modulo(idx, container.size())];
}
template<typename CONTAINER_TYPE>
inline const typename CONTAINER_TYPE::value_type& next_value_modulo(typename CONTAINER_TYPE::size_type idx, const CONTAINER_TYPE &container)
{
return container[next_idx_modulo(idx, container.size())];
}
template<typename CONTAINER_TYPE>
inline typename CONTAINER_TYPE::value_type& next_value_modulo(typename CONTAINER_TYPE::size_type idx, CONTAINER_TYPE &container)
{
return container[next_idx_modulo(idx, container.size())];
}
extern std::string xml_escape(std::string text);
#if defined __GNUC__ && __GNUC__ < 5 && !defined __clang__
// Older GCCs don't have std::is_trivially_copyable
// cf. https://gcc.gnu.org/onlinedocs/gcc-4.9.4/libstdc++/manual/manual/status.html#status.iso.2011
// #warning "GCC version < 5, faking std::is_trivially_copyable"
template<typename T> struct IsTriviallyCopyable { static constexpr bool value = true; };
#else
template<typename T> struct IsTriviallyCopyable : public std::is_trivially_copyable<T> {};
#endif
class ScopeGuard
{
public:
typedef std::function<void()> Closure;
private:
// bool committed;
Closure closure;
public:
ScopeGuard() {}
ScopeGuard(Closure closure) : closure(std::move(closure)) {}
ScopeGuard(const ScopeGuard&) = delete;
ScopeGuard(ScopeGuard &&other) : closure(std::move(other.closure)) {}
~ScopeGuard()
{
if (closure) { closure(); }
}
ScopeGuard& operator=(const ScopeGuard&) = delete;
ScopeGuard& operator=(ScopeGuard &&other)
{
closure = std::move(other.closure);
return *this;
}
void reset() { closure = Closure(); }
};
// Shorten the dhms time by removing the seconds, rounding the dhm to full minutes
// and removing spaces.
inline std::string short_time(const std::string &time)
{
// Parse the dhms time format.
int days = 0;
int hours = 0;
int minutes = 0;
int seconds = 0;
if (time.find('d') != std::string::npos)
::sscanf(time.c_str(), "%dd %dh %dm %ds", &days, &hours, &minutes, &seconds);
else if (time.find('h') != std::string::npos)
::sscanf(time.c_str(), "%dh %dm %ds", &hours, &minutes, &seconds);
else if (time.find('m') != std::string::npos)
::sscanf(time.c_str(), "%dm %ds", &minutes, &seconds);
else if (time.find('s') != std::string::npos)
::sscanf(time.c_str(), "%ds", &seconds);
// Round to full minutes.
if (days + hours + minutes > 0 && seconds >= 30) {
if (++minutes == 60) {
minutes = 0;
if (++hours == 24) {
hours = 0;
++days;
}
}
}
// Format the dhm time.
char buffer[64];
if (days > 0)
::sprintf(buffer, "%dd%dh%dm", days, hours, minutes);
else if (hours > 0)
::sprintf(buffer, "%dh%dm", hours, minutes);
else if (minutes > 0)
::sprintf(buffer, "%dm", minutes);
else
::sprintf(buffer, "%ds", seconds);
return buffer;
}
// Returns the given time is seconds in format DDd HHh MMm SSs
inline std::string get_time_dhms(float time_in_secs)
{
int days = (int)(time_in_secs / 86400.0f);
time_in_secs -= (float)days * 86400.0f;
int hours = (int)(time_in_secs / 3600.0f);
time_in_secs -= (float)hours * 3600.0f;
int minutes = (int)(time_in_secs / 60.0f);
time_in_secs -= (float)minutes * 60.0f;
char buffer[64];
if (days > 0)
::sprintf(buffer, "%dd %dh %dm %ds", days, hours, minutes, (int)time_in_secs);
else if (hours > 0)
::sprintf(buffer, "%dh %dm %ds", hours, minutes, (int)time_in_secs);
else if (minutes > 0)
::sprintf(buffer, "%dm %ds", minutes, (int)time_in_secs);
else
::sprintf(buffer, "%ds", (int)time_in_secs);
return buffer;
}
} // namespace Slic3r
#if WIN32
#define SLIC3R_STDVEC_MEMSIZE(NAME, TYPE) NAME.capacity() * ((sizeof(TYPE) + __alignof(TYPE) - 1) / __alignof(TYPE)) * __alignof(TYPE)
#else
#define SLIC3R_STDVEC_MEMSIZE(NAME, TYPE) NAME.capacity() * ((sizeof(TYPE) + alignof(TYPE) - 1) / alignof(TYPE)) * alignof(TYPE)
#endif
#endif // slic3r_Utils_hpp_
|