@@ -17,25 +17,161 @@ | |||
// -------------------- | |||
// | |||
#include <vector> | |||
#include <string> | |||
#include <cstring> | |||
namespace lol | |||
{ | |||
class getopt | |||
{ | |||
public: | |||
getopt(int argc, char ** _argv); | |||
getopt(int argc, char * const * _argv); | |||
~getopt(); | |||
getopt(int argc, char ** argv) | |||
: m_argc(argc), | |||
m_argv(argv) | |||
{ | |||
} | |||
getopt(int argc, char * const * argv) | |||
: m_argc(argc), | |||
m_argv(argv) | |||
{ | |||
} | |||
void add_opt(int short_opt, char const *long_opt, bool has_arg) | |||
{ | |||
optdesc o { long_opt, has_arg, nullptr, short_opt }; | |||
m_opts.push_back(o); | |||
/* “The standards require that the argument [to isalnum()] is either | |||
* EOF or a value that is representable in the type unsigned char.” */ | |||
if ((int)(unsigned char)short_opt == short_opt && isalnum(short_opt)) | |||
{ | |||
m_optstring += (char)short_opt; | |||
if (has_arg) | |||
m_optstring += ':'; | |||
} | |||
} | |||
int parse() | |||
{ | |||
int longindex = 0; // FIXME: what is this? | |||
/* XXX: this getopt_long implementation should not be trusted for other | |||
* applications without any serious peer reviewing. It “just works” with | |||
* zzuf and a few libcaca programs but may fail miserably in other | |||
* programs. */ | |||
char **argv = (char **)(uintptr_t)m_argv; | |||
char *flag; | |||
if (this->index >= m_argc) | |||
return -1; | |||
flag = argv[this->index]; | |||
if (flag[0] == '-' && flag[1] != '-') | |||
{ | |||
char const *tmp; | |||
int ret = flag[1]; | |||
if (ret == '\0') | |||
return -1; | |||
tmp = strchr(m_optstring.c_str(), ret); | |||
if (!tmp || ret == ':') | |||
return '?'; | |||
void add_opt(int short_opt, char const *long_opt, bool has_arg); | |||
int parse(); | |||
++this->index; | |||
if (tmp[1] == ':') | |||
{ | |||
if (flag[2] != '\0') | |||
this->arg = flag + 2; | |||
else | |||
{ | |||
if (this->index >= m_argc) | |||
goto too_few; | |||
this->arg = argv[this->index++]; | |||
} | |||
return ret; | |||
} | |||
int index; | |||
char *arg; | |||
if (flag[2] != '\0') | |||
{ | |||
flag[1] = '-'; | |||
--this->index; | |||
++argv[this->index]; | |||
} | |||
return ret; | |||
} | |||
if (flag[0] == '-' && flag[1] == '-') | |||
{ | |||
if (flag[2] == '\0') | |||
return -1; | |||
for (int i = 0; m_opts[i].name; ++i) | |||
{ | |||
size_t l = strlen(m_opts[i].name); | |||
if (strncmp(flag + 2, m_opts[i].name, l)) | |||
continue; | |||
switch (flag[2 + l]) | |||
{ | |||
case '=': | |||
if (!m_opts[i].has_arg) | |||
goto bad_opt; | |||
longindex = i; | |||
++this->index; | |||
this->arg = flag + 2 + l + 1; | |||
return m_opts[i].val; | |||
case '\0': | |||
longindex = i; | |||
++this->index; | |||
if (m_opts[i].has_arg) | |||
{ | |||
if (this->index >= m_argc) | |||
goto too_few; | |||
this->arg = argv[this->index++]; | |||
} | |||
return m_opts[i].val; | |||
default: | |||
break; | |||
} | |||
} | |||
bad_opt: | |||
fprintf(stderr, "%s: unrecognized option `%s'\n", argv[0], flag); | |||
return '?'; | |||
too_few: | |||
fprintf(stderr, "%s: option `%s' requires an argument\n", | |||
argv[0], flag); | |||
return '?'; | |||
} | |||
return -1; | |||
} | |||
int index = 1; | |||
char *arg = nullptr; | |||
private: | |||
std::unique_ptr<struct getopt_private> m_private; | |||
struct optdesc | |||
{ | |||
char const *name; | |||
int has_arg; | |||
int *flag; | |||
int val; | |||
}; | |||
int m_argc; | |||
char * const *m_argv; | |||
std::string m_optstring; | |||
std::vector<optdesc> m_opts; | |||
}; | |||
} | |||
} // namespace lol | |||
@@ -24,6 +24,7 @@ | |||
#include <thread> | |||
#include <mutex> | |||
#include <condition_variable> | |||
#include <chrono> // std::chrono | |||
#include <cassert> // assert() | |||
/* XXX: workaround for a bug in Visual Studio 2012 and 2013! | |||
@@ -233,5 +234,37 @@ private: | |||
std::condition_variable m_empty_cond, m_full_cond; | |||
}; | |||
class timer | |||
{ | |||
public: | |||
inline timer() { (void)get_seconds(true); } | |||
inline void reset() { (void)get_seconds(true); } | |||
inline float get() { return get_seconds(true); } | |||
inline float poll() { return get_seconds(false); } | |||
void wait(float seconds) | |||
{ | |||
if (seconds > 0.0f) | |||
{ | |||
float secs_elapsed = get_seconds(false); | |||
std::this_thread::sleep_for(std::chrono::duration<float>(seconds - secs_elapsed)); | |||
} | |||
} | |||
private: | |||
std::chrono::steady_clock::time_point m_tp; | |||
float get_seconds(bool do_reset) | |||
{ | |||
auto tp = std::chrono::steady_clock::now(), tp0 = m_tp; | |||
if (do_reset) | |||
m_tp = tp; | |||
return std::chrono::duration_cast<std::chrono::duration<float>>(tp - tp0).count(); | |||
} | |||
}; | |||
} /* namespace lol */ | |||
@@ -22,8 +22,9 @@ | |||
#include <lol/base/features.h> | |||
#include <lol/base/core.h> | |||
#include <tuple> // std::tuple | |||
#include <cassert> // assert() | |||
#include <functional> // std::function | |||
#include <tuple> // std::tuple | |||
#include <cassert> // assert() | |||
namespace lol | |||
{ | |||
@@ -54,7 +55,7 @@ struct LOL_ATTR_NODISCARD polynomial | |||
static polynomial<T> chebyshev(int n) | |||
{ | |||
/* Use T0(x) = 1, T1(x) = x, Tn(x) = 2 x Tn-1(x) - Tn-2(x) */ | |||
auto coeff = [&](int i, int j) -> int64_t | |||
std::function<int64_t (int, int)> coeff = [&](int i, int j) -> int64_t | |||
{ | |||
if (i > j || i < 0 || ((j ^ i) & 1)) | |||
return (int64_t)0; | |||
@@ -306,7 +307,7 @@ struct LOL_ATTR_NODISCARD polynomial | |||
/* Add two polynomials */ | |||
polynomial<T> &operator +=(polynomial<T> const &p) | |||
{ | |||
int min_degree = lol::min(p.degree(), degree()); | |||
int min_degree = std::min(p.degree(), degree()); | |||
for (int i = 0; i <= min_degree; ++i) | |||
m_coefficients[i] += p[i]; | |||
@@ -414,8 +415,8 @@ private: | |||
/* Enforce the non-zero leading coefficient rule. */ | |||
void reduce_degree() | |||
{ | |||
while (m_coefficients.count() && !m_coefficients.last()) | |||
(void)m_coefficients.pop(); | |||
while (m_coefficients.size() && !m_coefficients.back()) | |||
m_coefficients.pop_back(); | |||
} | |||
/* The polynomial coefficients */ | |||
@@ -1,20 +1,25 @@ | |||
// | |||
// Lol Engine | |||
// Lol Engine | |||
// | |||
// Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net> | |||
// This program is free software; you can redistribute it and/or | |||
// modify it under the terms of the Do What The Fuck You Want To | |||
// Public License, Version 2, as published by Sam Hocevar. See | |||
// http://www.wtfpl.net/ for more details. | |||
// Copyright © 2010—2020 Sam Hocevar <sam@hocevar.net> | |||
// | |||
// Lol Engine is free software. It comes without any warranty, to | |||
// the extent permitted by applicable law. You can redistribute it | |||
// and/or modify it under the terms of the Do What the Fuck You Want | |||
// to Public License, Version 2, as published by the WTFPL Task Force. | |||
// See http://www.wtfpl.net/ for more details. | |||
// | |||
#pragma once | |||
// | |||
// The Random number generators | |||
// ---------------------------- | |||
// ———————————————————————————— | |||
// | |||
#include <lol/base/features.h> | |||
#include <cassert> | |||
#include <cstdlib> | |||
#include <stdint.h> | |||
@@ -32,27 +37,29 @@ template<typename T> LOL_ATTR_NODISCARD static inline T rand(T a) | |||
return a ? rand<T>() % a : T(0); | |||
} | |||
#if 0 | |||
template<> LOL_ATTR_NODISCARD inline half rand<half>(half a) | |||
{ | |||
float f = (float)std::rand() / (float)RAND_MAX; | |||
return (half)(a * f); | |||
} | |||
#endif | |||
template<> LOL_ATTR_NODISCARD inline float rand<float>(float a) | |||
{ | |||
float f = (float)std::rand() / (float)RAND_MAX; | |||
auto f = (float)std::rand() / (float)RAND_MAX; | |||
return a * f; | |||
} | |||
template<> LOL_ATTR_NODISCARD inline double rand<double>(double a) | |||
{ | |||
double f = (double)std::rand() / (double)RAND_MAX; | |||
auto f = (double)std::rand() / (double)RAND_MAX; | |||
return a * f; | |||
} | |||
template<> LOL_ATTR_NODISCARD inline ldouble rand<ldouble>(ldouble a) | |||
template<> LOL_ATTR_NODISCARD inline long double rand<long double>(long double a) | |||
{ | |||
ldouble f = (ldouble)std::rand() / (ldouble)RAND_MAX; | |||
auto f = (long double)std::rand() / (long double)RAND_MAX; | |||
return a * f; | |||
} | |||
@@ -111,16 +118,17 @@ template<typename T> LOL_ATTR_NODISCARD static inline T rand() | |||
return static_cast<T>(ret & (~(uint64_t)0 >> 1)); | |||
} | |||
default: | |||
ASSERT(false, "rand() doesn’t support types of size %d\n", | |||
(int)sizeof(T)); | |||
assert(false); | |||
return 0; | |||
} | |||
} | |||
#if 0 | |||
template<> LOL_ATTR_NODISCARD inline half rand<half>() { return rand<half>(1.f); } | |||
#endif | |||
template<> LOL_ATTR_NODISCARD inline float rand<float>() { return rand<float>(1.f); } | |||
template<> LOL_ATTR_NODISCARD inline double rand<double>() { return rand<double>(1.0); } | |||
template<> LOL_ATTR_NODISCARD inline ldouble rand<ldouble>() { return rand<ldouble>(1.0); } | |||
template<> LOL_ATTR_NODISCARD inline long double rand<long double>() { return rand<long double>(1.0); } | |||
} /* namespace lol */ | |||
@@ -1,198 +0,0 @@ | |||
// | |||
// Lol Engine | |||
// | |||
// Copyright © 2002—2018 Sam Hocevar <sam@hocevar.net> | |||
// | |||
// Lol Engine is free software. It comes without any warranty, to | |||
// the extent permitted by applicable law. You can redistribute it | |||
// and/or modify it under the terms of the Do What the Fuck You Want | |||
// to Public License, Version 2, as published by the WTFPL Task Force. | |||
// See http://www.wtfpl.net/ for more details. | |||
// | |||
#include <lol/engine-internal.h> | |||
#if HAVE_GETOPT_H | |||
# include <getopt.h> | |||
#endif | |||
#if HAVE_UNISTD_H | |||
# include <unistd.h> | |||
#endif | |||
namespace lol | |||
{ | |||
struct getopt_private | |||
{ | |||
getopt_private(int argc, char * const * _argv) | |||
: m_argc(argc), | |||
m_argv(_argv) | |||
{} | |||
#if HAVE_GETOPT_LONG | |||
typedef option optdesc; | |||
#else | |||
struct optdesc | |||
{ | |||
char const *name; | |||
int has_arg; | |||
int *flag; | |||
int val; | |||
}; | |||
#endif | |||
int m_argc; | |||
char * const *m_argv; | |||
std::string m_optstring; | |||
array<optdesc> m_opts; | |||
}; | |||
getopt::getopt(int argc, char ** _argv) | |||
: index(1), | |||
arg(nullptr), | |||
m_private(new getopt_private(argc, _argv)) | |||
{ | |||
} | |||
getopt::getopt(int argc, char * const * _argv) | |||
: index(1), | |||
arg(nullptr), | |||
m_private(new getopt_private(argc, _argv)) | |||
{ | |||
} | |||
getopt::~getopt() | |||
{ | |||
} | |||
void getopt::add_opt(int short_opt, char const *long_opt, bool has_arg) | |||
{ | |||
getopt_private::optdesc o { long_opt, has_arg, nullptr, short_opt }; | |||
m_private->m_opts.push(o); | |||
/* “The standards require that the argument [to isalnum()] is either | |||
* EOF or a value that is representable in the type unsigned char.” */ | |||
if ((int)(unsigned char)short_opt == short_opt && isalnum(short_opt)) | |||
{ | |||
m_private->m_optstring += (char)short_opt; | |||
if (has_arg) | |||
m_private->m_optstring += ':'; | |||
} | |||
} | |||
int getopt::parse() | |||
{ | |||
int longindex = 0; // FIXME: what is this? | |||
#if HAVE_GETOPT_LONG | |||
int ret; | |||
optind = this->index; | |||
optarg = this->arg; | |||
m_private->m_opts.push(getopt_private::optdesc { nullptr, 0, nullptr, 0 }); | |||
ret = getopt_long(m_private->m_argc, m_private->m_argv, m_private->m_optstring.c_str(), | |||
(option const *)m_private->m_opts.data(), &longindex); | |||
this->index = optind; | |||
this->arg = optarg; | |||
return ret; | |||
#else | |||
/* XXX: this getopt_long implementation should not be trusted for other | |||
* applications without any serious peer reviewing. It “just works” with | |||
* zzuf and a few libcaca programs but may fail miserably in other | |||
* programs. */ | |||
char **argv = (char **)(uintptr_t)m_private->m_argv; | |||
char *flag; | |||
if (this->index >= m_private->m_argc) | |||
return -1; | |||
flag = argv[this->index]; | |||
if (flag[0] == '-' && flag[1] != '-') | |||
{ | |||
char const *tmp; | |||
int ret = flag[1]; | |||
if (ret == '\0') | |||
return -1; | |||
tmp = strchr(m_private->m_optstring.c_str(), ret); | |||
if (!tmp || ret == ':') | |||
return '?'; | |||
++this->index; | |||
if (tmp[1] == ':') | |||
{ | |||
if (flag[2] != '\0') | |||
this->arg = flag + 2; | |||
else | |||
{ | |||
if (this->index >= m_private->m_argc) | |||
goto too_few; | |||
this->arg = argv[this->index++]; | |||
} | |||
return ret; | |||
} | |||
if (flag[2] != '\0') | |||
{ | |||
flag[1] = '-'; | |||
--this->index; | |||
++argv[this->index]; | |||
} | |||
return ret; | |||
} | |||
if (flag[0] == '-' && flag[1] == '-') | |||
{ | |||
if (flag[2] == '\0') | |||
return -1; | |||
for (int i = 0; m_private->m_opts[i].name; ++i) | |||
{ | |||
size_t l = strlen(m_private->m_opts[i].name); | |||
if (strncmp(flag + 2, m_private->m_opts[i].name, l)) | |||
continue; | |||
switch (flag[2 + l]) | |||
{ | |||
case '=': | |||
if (!m_private->m_opts[i].has_arg) | |||
goto bad_opt; | |||
longindex = i; | |||
++this->index; | |||
this->arg = flag + 2 + l + 1; | |||
return m_private->m_opts[i].val; | |||
case '\0': | |||
longindex = i; | |||
++this->index; | |||
if (m_private->m_opts[i].has_arg) | |||
{ | |||
if (this->index >= m_private->m_argc) | |||
goto too_few; | |||
this->arg = argv[this->index++]; | |||
} | |||
return m_private->m_opts[i].val; | |||
default: | |||
break; | |||
} | |||
} | |||
bad_opt: | |||
fprintf(stderr, "%s: unrecognized option `%s'\n", argv[0], flag); | |||
return '?'; | |||
too_few: | |||
fprintf(stderr, "%s: option `%s' requires an argument\n", | |||
argv[0], flag); | |||
return '?'; | |||
} | |||
return -1; | |||
#endif | |||
} | |||
} // namespace lol | |||