mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-07-20 11:34:23 +08:00

atomically. The code was taken from the llvm project, it is complex and hopefully it covers all the Windows file system quirks. Vojtech has highest hopes, that this will fix the various PrusaSlicer.ini file corruptions. Enabled the locales switching and error handling on Linux as well, where now the missing locales are reported and running the locale-gen tool is recommended.
284 lines
9.9 KiB
C++
284 lines
9.9 KiB
C++
#ifndef slic3r_Utils_hpp_
|
|
#define slic3r_Utils_hpp_
|
|
|
|
#include <locale>
|
|
#include <utility>
|
|
#include <functional>
|
|
#include <type_traits>
|
|
|
|
#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);
|
|
|
|
// Copy a file, adjust the access attributes, so that the target is writable.
|
|
extern int copy_file(const std::string &from, const std::string &to);
|
|
|
|
// 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, ...);
|
|
|
|
// Timestamp formatted for header_slic3r_generated().
|
|
extern std::string timestamp_str();
|
|
// Standard "generated by Slic3r version xxx timestamp xxx" header string,
|
|
// to be placed at the top of Slic3r generated files.
|
|
inline std::string header_slic3r_generated() { return std::string("generated by " SLIC3R_APP_NAME " " SLIC3R_VERSION " " ) + timestamp_str(); }
|
|
|
|
// 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));
|
|
}
|
|
|
|
|
|
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_
|