|  | #include "util.hpp"
#include <stdarg.h>
#include <string.h>
#include <random>
#include <algorithm>
#include <libgen.h> // for dirname and basename
#include <sys/time.h>
#if ARCH_WIN
#include <windows.h>
#include <shellapi.h>
#endif
namespace rack {
////////////////////
// RNG
////////////////////
// xoroshiro128+
// from http://xoroshiro.di.unimi.it/xoroshiro128plus.c
static uint64_t xoroshiro128plus_state[2];
static uint64_t rotl(const uint64_t x, int k) {
	return (x << k) | (x >> (64 - k));
}
static uint64_t xoroshiro128plus_next(void) {
	const uint64_t s0 = xoroshiro128plus_state[0];
	uint64_t s1 = xoroshiro128plus_state[1];
	const uint64_t result = s0 + s1;
	s1 ^= s0;
	xoroshiro128plus_state[0] = rotl(s0, 55) ^ s1 ^ (s1 << 14); // a, b
	xoroshiro128plus_state[1] = rotl(s1, 36); // c
	return result;
}
void randomSeedTime() {
	struct timeval tv;
	gettimeofday(&tv, NULL);
	xoroshiro128plus_state[0] = tv.tv_sec;
	xoroshiro128plus_state[1] = tv.tv_usec;
	// Generate a few times to fix the fact that the time is not a uniform u64
	for (int i = 0; i < 10; i++) {
		xoroshiro128plus_next();
	}
}
uint32_t randomu32() {
	return xoroshiro128plus_next() >> 32;
}
uint64_t randomu64() {
	return xoroshiro128plus_next();
}
float randomf() {
	// 24 bits of granularity is the best that can be done with floats while ensuring that the return value lies in [0.0, 1.0).
	return (xoroshiro128plus_next() >> (64 - 24)) / powf(2, 24);
}
float randomNormal() {
	// Box-Muller transform
	float radius = sqrtf(-2.f * logf(1.f - randomf()));
	float theta = 2.f * M_PI * randomf();
	return radius * sinf(theta);
	// // Central Limit Theorem
	// const int n = 8;
	// float sum = 0.0;
	// for (int i = 0; i < n; i++) {
	// 	sum += randomf();
	// }
	// return (sum - n / 2.f) / sqrtf(n / 12.f);
}
////////////////////
// String functions
////////////////////
std::string stringf(const char *format, ...) {
	va_list args;
	va_start(args, format);
	// Compute size of required buffer
	int size = vsnprintf(NULL, 0, format, args);
	va_end(args);
	if (size < 0)
		return "";
	// Create buffer
	std::string s;
	s.resize(size);
	va_start(args, format);
	vsnprintf(&s[0], size + 1, format, args);
	va_end(args);
	return s;
}
std::string tolower(std::string s) {
	std::transform(s.begin(), s.end(), s.begin(), ::tolower);
	return s;
}
std::string toupper(std::string s) {
	std::transform(s.begin(), s.end(), s.begin(), ::toupper);
	return s;
}
std::string ellipsize(std::string s, size_t len) {
	if (s.size() <= len)
		return s;
	else
		return s.substr(0, len - 3) + "...";
}
std::string extractDirectory(std::string path) {
	char *pathDup = strdup(path.c_str());
	std::string directory = dirname(pathDup);
	free(pathDup);
	return directory;
}
std::string extractFilename(std::string path) {
	char *pathDup = strdup(path.c_str());
	std::string filename = basename(pathDup);
	free(pathDup);
	return filename;
}
std::string extractExtension(std::string path) {
	const char *ext = strrchr(path.c_str(), '.');
	if (!ext)
		return "";
	return ext + 1;
}
////////////////////
// Operating system functions
////////////////////
void openBrowser(std::string url) {
#if ARCH_LIN
	std::string command = "xdg-open " + url;
	(void)system(command.c_str());
#endif
#if ARCH_MAC
	std::string command = "open " + url;
	system(command.c_str());
#endif
#if ARCH_WIN
	ShellExecute(NULL, "open", url.c_str(), NULL, NULL, SW_SHOWNORMAL);
#endif
}
////////////////////
// logger
////////////////////
FILE *gLogFile = stderr;
void debug(const char *format, ...) {
	va_list args;
	va_start(args, format);
	fprintf(gLogFile, "[debug] ");
	vfprintf(gLogFile, format, args);
	fprintf(gLogFile, "\n");
	fflush(gLogFile);
	va_end(args);
}
void info(const char *format, ...) {
	va_list args;
	va_start(args, format);
	fprintf(gLogFile, "[info] ");
	vfprintf(gLogFile, format, args);
	fprintf(gLogFile, "\n");
	fflush(gLogFile);
	va_end(args);
}
void warn(const char *format, ...) {
	va_list args;
	va_start(args, format);
	fprintf(gLogFile, "[warning] ");
	vfprintf(gLogFile, format, args);
	fprintf(gLogFile, "\n");
	fflush(gLogFile);
	va_end(args);
}
void fatal(const char *format, ...) {
	va_list args;
	va_start(args, format);
	fprintf(gLogFile, "[fatal] ");
	vfprintf(gLogFile, format, args);
	fprintf(gLogFile, "\n");
	fflush(gLogFile);
	va_end(args);
}
} // namespace rack
 |