| @@ -17,25 +17,161 @@ | |||||
| // -------------------- | // -------------------- | ||||
| // | // | ||||
| #include <vector> | |||||
| #include <string> | |||||
| #include <cstring> | |||||
| namespace lol | namespace lol | ||||
| { | { | ||||
| class getopt | class getopt | ||||
| { | { | ||||
| public: | 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: | 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 <thread> | ||||
| #include <mutex> | #include <mutex> | ||||
| #include <condition_variable> | #include <condition_variable> | ||||
| #include <chrono> // std::chrono | |||||
| #include <cassert> // assert() | #include <cassert> // assert() | ||||
| /* XXX: workaround for a bug in Visual Studio 2012 and 2013! | /* 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; | 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 */ | } /* namespace lol */ | ||||
| @@ -22,8 +22,9 @@ | |||||
| #include <lol/base/features.h> | #include <lol/base/features.h> | ||||
| #include <lol/base/core.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 | namespace lol | ||||
| { | { | ||||
| @@ -54,7 +55,7 @@ struct LOL_ATTR_NODISCARD polynomial | |||||
| static polynomial<T> chebyshev(int n) | static polynomial<T> chebyshev(int n) | ||||
| { | { | ||||
| /* Use T0(x) = 1, T1(x) = x, Tn(x) = 2 x Tn-1(x) - Tn-2(x) */ | /* 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)) | if (i > j || i < 0 || ((j ^ i) & 1)) | ||||
| return (int64_t)0; | return (int64_t)0; | ||||
| @@ -306,7 +307,7 @@ struct LOL_ATTR_NODISCARD polynomial | |||||
| /* Add two polynomials */ | /* Add two polynomials */ | ||||
| polynomial<T> &operator +=(polynomial<T> const &p) | 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) | for (int i = 0; i <= min_degree; ++i) | ||||
| m_coefficients[i] += p[i]; | m_coefficients[i] += p[i]; | ||||
| @@ -414,8 +415,8 @@ private: | |||||
| /* Enforce the non-zero leading coefficient rule. */ | /* Enforce the non-zero leading coefficient rule. */ | ||||
| void reduce_degree() | 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 */ | /* 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 | #pragma once | ||||
| // | // | ||||
| // The Random number generators | // The Random number generators | ||||
| // ---------------------------- | |||||
| // ———————————————————————————— | |||||
| // | // | ||||
| #include <lol/base/features.h> | |||||
| #include <cassert> | |||||
| #include <cstdlib> | #include <cstdlib> | ||||
| #include <stdint.h> | #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); | return a ? rand<T>() % a : T(0); | ||||
| } | } | ||||
| #if 0 | |||||
| template<> LOL_ATTR_NODISCARD inline half rand<half>(half a) | template<> LOL_ATTR_NODISCARD inline half rand<half>(half a) | ||||
| { | { | ||||
| float f = (float)std::rand() / (float)RAND_MAX; | float f = (float)std::rand() / (float)RAND_MAX; | ||||
| return (half)(a * f); | return (half)(a * f); | ||||
| } | } | ||||
| #endif | |||||
| template<> LOL_ATTR_NODISCARD inline float rand<float>(float a) | 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; | return a * f; | ||||
| } | } | ||||
| template<> LOL_ATTR_NODISCARD inline double rand<double>(double a) | 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; | 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; | 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)); | return static_cast<T>(ret & (~(uint64_t)0 >> 1)); | ||||
| } | } | ||||
| default: | default: | ||||
| ASSERT(false, "rand() doesn’t support types of size %d\n", | |||||
| (int)sizeof(T)); | |||||
| assert(false); | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| } | } | ||||
| #if 0 | |||||
| template<> LOL_ATTR_NODISCARD inline half rand<half>() { return rand<half>(1.f); } | 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 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 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 */ | } /* 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 | |||||