| @@ -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 | |||