diff --git a/.github/workflows/cplusplus.yml b/.github/workflows/cplusplus.yml new file mode 100644 index 00000000..24a5c346 --- /dev/null +++ b/.github/workflows/cplusplus.yml @@ -0,0 +1,95 @@ +name: C++ + +on: + push: + paths-ignore: + - 'docs/**' + - 'README.rst' + schedule: + - cron: "0 0 1 * *" + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + c-lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + submodules: true + + - name: Setup clang-tidy + uses: awalsh128/cache-apt-pkgs-action@latest + with: + packages: clang-tidy + version: 1.0 + + - name: Run tests + run: make cpp_lint + + cpp: + strategy: + fail-fast: false + matrix: +# compiler: ["llvm", "gcc"] +# # compiler targets (ideally): clang, gcc, MSVCC, pcc, tcc, icc, + os: [ubuntu-latest, windows-latest, macos-latest, macos-13, 'ubuntu-20.04'] +# include: +# - os: windows-latest +# compiler: msvc +# - os: windows-latest +# compiler: mingw + runs-on: ${{ matrix.os }} + + steps: + - uses: actions/checkout@v3 + with: + submodules: true + + - name: Use Python 3.10 + uses: actions/setup-python@v5 + with: + python-version: "3.10" + cache-dependency-path: '*/requirements.txt' + + - name: Setup tcc, pcc + uses: awalsh128/cache-apt-pkgs-action@latest + if: ${{ matrix.os == 'ubuntu-latest' }} + with: + packages: tcc pcc + version: 1.0 + + - name: Setup MSVC + uses: aminya/setup-cpp@v1 + if: ${{ contains(matrix.os, 'windows') }} + with: + compiler: msvc + vcvarsall: true + +# - name: Set up MinGW +# if: ${{ contains(matrix.os, 'windows') }} +# uses: egor-tensin/setup-mingw@v2 +# with: +# platform: x64 + + - name: Run tests (linux) + if: ${{ contains(matrix.os, 'ubuntu') }} + run: make c_test${{ (matrix.os != 'ubuntu-latest' && '_auto') || '' }} COV=true + + - name: Run tests (windows) + if: ${{ contains(matrix.os, 'windows') }} + run: make c_test_auto + + - name: Run tests (macos) + if: ${{ contains(matrix.os, 'macos') }} + run: make c_test_auto + env: + NO_OPTIONAL_TESTS: true + COMPILER_OVERRIDE: clang + + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v4.0.1 + with: + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/Makefile b/Makefile index 94ec389a..d1b1dcc1 100644 --- a/Makefile +++ b/Makefile @@ -18,6 +18,9 @@ help: @echo "The following jobs are available under the c_ prefix" @$(MAKE) c_help $(MFLAGS) --no-print-directory @echo + @echo "The following jobs are available under the cp_ prefix" + @$(MAKE) cp_help $(MFLAGS) --no-print-directory + @echo @echo "The following jobs are available under the cs_ prefix" @$(MAKE) cs_help $(MFLAGS) --no-print-directory @echo @@ -34,11 +37,14 @@ help: html dirhtml singlehtml epub latex: @$(MAKE) docs_$@ $(MFLAGS) -clean: cs_clean c_clean js_clean py_clean rs_clean docs_clean +clean: cs_clean cp_clean c_clean js_clean py_clean rs_clean docs_clean cs_%: @cd csharp && $(MAKE) $* $(MFLAGS) +cp_%: + @cd csharp && $(MAKE) $* $(MFLAGS) + c_%: @cd c && $(MAKE) $* $(MFLAGS) @@ -55,4 +61,4 @@ rs_%: @cd rust && $(MAKE) $* $(MFLAGS) %: - @$(MAKE) c_$* cs_$* js_$* py_$* rs_$* $(MFLAGS) + @$(MAKE) c_$* cp_$* cs_$* js_$* py_$* rs_$* $(MFLAGS) diff --git a/README.rst b/README.rst index 8843b002..6102dbd5 100644 --- a/README.rst +++ b/README.rst @@ -5,6 +5,8 @@ LivInTheLookingGlass’s Project Euler solutions :target: https://github.com/LivInTheLookingGlass/Euler/actions/workflows/c.yml .. |C#i| image:: https://github.com/LivInTheLookingGlass/Euler/actions/workflows/csharp.yml/badge.svg :target: https://github.com/LivInTheLookingGlass/Euler/actions/workflows/csharp.yml +.. |Cpi| image:: https://github.com/LivInTheLookingGlass/Euler/actions/workflows/cplusplus.yml/badge.svg + :target: https://github.com/LivInTheLookingGlass/Euler/actions/workflows/cplusplus.yml .. |JavaScript| image:: https://github.com/LivInTheLookingGlass/Euler/actions/workflows/javascript.yml/badge.svg :target: https://github.com/LivInTheLookingGlass/Euler/actions/workflows/javascript.yml .. |Python| image:: https://github.com/LivInTheLookingGlass/Euler/actions/workflows/python.yml/badge.svg @@ -28,11 +30,13 @@ LivInTheLookingGlass’s Project Euler solutions +------------+---------------------+--------+---------------+ | Language | Version | Solved | Status | +============+=====================+========+===============+ -| C | C11+ in: ``gcc``, | 17 | |Ci| | +| C | C99+ in: ``gcc``, | 17 | |Ci| | | | |br| ``clang``, | | | | | ``msvc``, |br| | | | | | ``pcc``, ``tcc`` | | | +------------+---------------------+--------+---------------+ +| C++ | C++98+ | 1 | |Cpi| | ++------------+---------------------+--------+---------------+ | C# | .NET 2+ | 5 | |C#i| | +------------+---------------------+--------+---------------+ | JavaScript | Node 12+ | 5 | |JavaScript| | @@ -77,6 +81,7 @@ The repo is divided into sections for each language. The top-level Makefile will direct recipes using prefixes - ``make c_*`` will go to the c Makefile +- ``make cp_*`` will go to the csharp Makefile - ``make cs_*`` will go to the csharp Makefile - ``make docs_*`` will go to the docs Makefile - ``make js_*`` will go to the javascript Makefile diff --git a/c/p0000_template.c b/c/p0000_template.c index 6d0f0103..8e08e86a 100644 --- a/c/p0000_template.c +++ b/c/p0000_template.c @@ -18,7 +18,7 @@ unsigned long long p0000() { #ifndef UNITY_END int main(int argc, char const *argv[]) { unsigned long long answer = p0000(); - printf("%llu", answer); + printf("%llu\n", answer); return 0; } #endif diff --git a/cplusplus/Makefile b/cplusplus/Makefile new file mode 100644 index 00000000..2f5b5fe6 --- /dev/null +++ b/cplusplus/Makefile @@ -0,0 +1,42 @@ +PY?=python3 +USER_FLAG?=--user +PIP?=$(PY) -m pip +BLUE=\033[0;34m +NC=\033[0m # No Color + +ifneq ($(https_proxy), ) +PROXY_ARG=--proxy=$(https_proxy) +else +ifneq ($(http_proxy), ) +PROXY_ARG=--proxy=$(http_proxy) +else +PROXY_ARG= +endif +endif + +help: + @echo " $(BLUE)test$(NC) run through all tests in sequence. Utilizes the Python test runner infrastructure" + @echo " $(BLUE)test_*$(NC) run through all tests in parallel with the given number of threads. Use auto to allow the test runner to determine it. Utilizes the Python test runner infrastructure" + @echo " $(BLUE)dependencies$(NC) initialize submodules and install any Python dependencies" + @echo " $(BLUE)lint$(NC) run clang-tidy across each of the .cpp and .h files" + @echo " $(BLUE)clean$(NC) clean up any stray files" + +test_%: dependencies + cd ../python; $(MAKE) dependencies $(MFLAGS) + $(PY) -m pytest -vl -n$* test_euler.py --cov + +test: dependencies + $(PY) -m pytest -vl --benchmark-sort=fullname --benchmark-group-by=fullfunc --benchmark-verbose test_euler.py --cov + +dependencies: + $(PIP) install -r requirements.txt -r ../python/requirements.txt $(USER_FLAG) $(PROXY_ARG) + +lint: + if test -z "$(clang-tidy p0000_template.cpp -warnings-as-errors=* 2>&1 | grep "Unknown command line argument")"; then \ + clang-tidy *.cpp -warnings-as-errors=-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling; \ + else \ + clang-tidy *.cpp; \ + fi + +clean: + rm -r build ./{*,*/*}{.pyc,__pycache__,.mypy_cache} || echo diff --git a/cplusplus/include/macros.h b/cplusplus/include/macros.h new file mode 100644 index 00000000..fa195bad --- /dev/null +++ b/cplusplus/include/macros.h @@ -0,0 +1,85 @@ +#ifndef MACROS_H +#define MACROS_H + +// compiler info section + +#if (defined(_MSC_VER) && !defined(__clang__)) + #define CL_COMPILER 1 +#else + #define CL_COMPILER 0 +#endif +#if (defined(__clang__) && (!defined(AMD_COMPILER) || !AMD_COMPILER)) + #define CLANG_COMPILER 1 +#else + #define CLANG_COMPILER 0 +#endif +#if (defined(__GNUC__) && !defined(__clang__)) && !defined(__INTEL_COMPILER) + #define GCC_COMPILER 1 +#else + #define GCC_COMPILER 0 +#endif +#ifdef __INTEL_COMPILER + #define INTEL_COMPILER 1 +#else + #define INTEL_COMPILER 0 +#endif +#ifndef AMD_COMPILER + #if CLANG_COMPILER + #warning "This suite can't detect the difference between clang and aocc. You need to specify -DAMD_COMPILER={0 or 1}" + #endif + #define AMD_COMPILER 0 +#endif + +#if (defined(_M_X64) || defined(_M_AMD64) || defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)) + #define X64_COMPILER 1 +#else + #define X64_COMPILER 0 +#endif +#if (!X64_COMPILER && (defined(_M_X86) || defined(_M_IX86) || defined(i386) || defined(__i386) || defined(__i386__) || defined(_X86_))) + #define X86_COMPILER 1 +#else + #define X86_COMPILER 0 +#endif +#if (defined(__arm__) || defined(__aarch64__) || defined(__thumb__) || defined(_M_ARM) || defined(_M_ARMT) || defined(__ARM_ARCH)) + #define ARM_COMPILER 1 +#else + #define ARM_COMPILER 0 +#endif +#if (ARM_COMPILER && (defined(__thumb__) || defined(_M_ARMT))) + #define ARM_THUMB 1 +#else + #define ARM_THUMB 0 +#endif + +// helper macro function section + +#ifndef max + #define max(a, b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef min + #define min(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +#if !(CL_COMPILER) + #define likely(x) __builtin_expect(!!(x), 1) + #define unlikely(x) __builtin_expect(!!(x), 0) +#else + #define likely(x) x + #define unlikely(x) x +#endif + +// constants section + +#define MAX_FACTORIAL_64 20 +#define MAX_FACTORIAL_128 34 +#define MAX_POW_10_16 10000U +#define POW_OF_MAX_POW_10_16 4 +#define MAX_POW_10_32 1000000000UL +#define POW_OF_MAX_POW_10_32 9 +#define MAX_POW_10_64 10000000000000000000ULL +#define POW_OF_MAX_POW_10_64 19 +#define MAX_POW_10_128 ((uintmax_t) MAX_POW_10_64 * (uintmax_t) MAX_POW_10_64) +#define POW_OF_MAX_POW_10_128 38 + +#endif diff --git a/cplusplus/p0000_template.cpp b/cplusplus/p0000_template.cpp new file mode 100644 index 00000000..8e08e86a --- /dev/null +++ b/cplusplus/p0000_template.cpp @@ -0,0 +1,25 @@ +/* +Project Euler Template + +This template is used to format Project Euler solution scripts. This paragraph +should be replaced by a description of how I approached the problem, as well as +critque. + +This paragraph should be replaced by the problem description, excluding images. +*/ +#ifndef EULER_P0000 +#define EULER_P0000 +#include + +unsigned long long p0000() { + return 0; +} + +#ifndef UNITY_END +int main(int argc, char const *argv[]) { + unsigned long long answer = p0000(); + printf("%llu\n", answer); + return 0; +} +#endif +#endif diff --git a/cplusplus/p0001.cpp b/cplusplus/p0001.cpp new file mode 100644 index 00000000..26724a1f --- /dev/null +++ b/cplusplus/p0001.cpp @@ -0,0 +1,40 @@ +/** + * Project Euler Problem 1 + * + * I did this the traditional way in C++, mostly because I want to see if there + * is a way to do iteration in native C++ before hacking together a solution just + * because I can. + * + * Problem: + * + * If we list all the natural numbers below 10 that are multiples of 3 or 5, we + * get 3, 5, 6 and 9. The sum of these multiples is 23. + * + * Find the sum of all the multiples of 3 or 5 below 1000. + */ +#ifndef EULER_P0001 +#define EULER_P0001 +#include + +unsigned long long p0001() { + unsigned long long answer = 0; + for (int i = 0; i < 1000; i += 3) { + answer += i; + } + for (int i = 0; i < 1000; i += 5) { + answer += i; + } + for (int i = 0; i < 1000; i += 15) { + answer -= i; + } + return answer; +} + +#ifndef UNITY_END +int main(int argc, char const *argv[]) { + unsigned long long answer = p0001(); + printf("%llu\n", answer); + return 0; +} +#endif +#endif diff --git a/cplusplus/requirements.txt b/cplusplus/requirements.txt new file mode 100644 index 00000000..484438c7 --- /dev/null +++ b/cplusplus/requirements.txt @@ -0,0 +1,4 @@ +pytest +pytest-benchmark +sortedcontainers +u-msgpack-python diff --git a/cplusplus/test_euler.py b/cplusplus/test_euler.py new file mode 100644 index 00000000..1e6d3224 --- /dev/null +++ b/cplusplus/test_euler.py @@ -0,0 +1,256 @@ +from atexit import register +from functools import partial +from itertools import chain +from os import environ, listdir, sep +from pathlib import Path +from platform import machine, processor, system, uname +from shutil import rmtree, which +from subprocess import check_call, check_output, run +from sys import path +from tempfile import TemporaryFile +from time import sleep +from typing import List, Set, Union +from uuid import uuid4 +from warnings import warn + +from pytest import fail, fixture, mark, skip, xfail + +CPP_FOLDER = Path(__file__).parent +BUILD_FOLDER = CPP_FOLDER.joinpath('build') +path.append(str(CPP_FOLDER.parent.joinpath("python"))) + +answers = { + 1: 233168, +} + +# this is the set of problems where I have the right answer but wrong solution +known_slow: Set[int] = set() + +# platform variables section +IN_WINDOWS = system() == 'Windows' +IN_OSX = system() == 'Darwin' +IN_TERMUX = bool(which('termux-setup-storage')) +IN_LINUX = (not IN_TERMUX) and (system() == 'Linux') +STANDARDS = ('c++98', 'c++03', 'c++11', 'c++14', 'c++17', 'c++20') + +if IN_TERMUX: + BUILD_FOLDER = Path.home().joinpath('build') # Termux can't make executable files outside of $HOME + +_raw_NO_SLOW = environ.get('NO_SLOW') +try: + _parsed_NO_SLOW: Union[str, int, None] = int(_raw_NO_SLOW) # type: ignore +except Exception: + _parsed_NO_SLOW = _raw_NO_SLOW +_raw_ONLY_SLOW = environ.get('ONLY_SLOW') +try: + _parsed_ONLY_SLOW: Union[str, int, None] = int(_raw_ONLY_SLOW) # type: ignore +except Exception: + _parsed_ONLY_SLOW = _raw_ONLY_SLOW +_raw_NO_OPTIONAL_TESTS = environ.get('NO_OPTIONAL_TESTS') +try: + _parsed_NO_OPTIONAL_TESTS: Union[str, int, None] = int(_raw_NO_OPTIONAL_TESTS) # type: ignore +except Exception: + _parsed_NO_OPTIONAL_TESTS = _raw_NO_OPTIONAL_TESTS + +if _parsed_NO_SLOW and _parsed_ONLY_SLOW: + warn("Test suite told to ignore slow tests AND run only slow tests. Ignoring conflicing options") + +# if in Termux, default to NO_SLOW, but allow users to explicitly override that decision +NO_SLOW = ((IN_TERMUX and _parsed_NO_SLOW is None) or _parsed_NO_SLOW) and not _parsed_ONLY_SLOW +ONLY_SLOW = _parsed_ONLY_SLOW and not _parsed_NO_SLOW +NO_OPTIONAL_TESTS = (_parsed_NO_OPTIONAL_TESTS is None and ONLY_SLOW) or _parsed_NO_OPTIONAL_TESTS + +# this part isn't necessary, but I like having the binaries include their compile architecture +if IN_LINUX and processor() and ' ' not in processor(): + EXE_EXT = processor() +elif IN_WINDOWS: + # processor() returns something too verbose in Windows + EXE_EXT = "x86" + if machine().endswith('64'): + EXE_EXT += "_64" +elif IN_OSX: + # processor() on OSX returns something too vague to be useful + EXE_EXT = uname().machine.replace('i3', 'x') +elif IN_TERMUX: + # processor() doesn't seem to work on Termux + EXE_EXT = check_output('lscpu').split()[1].decode() +else: + warn("Could not detect system architecture, defaulting to .exe") + EXE_EXT = "exe" + +GCC_BINARY = environ.get('GCC_OVERRIDE', 'g++') +AOCC_BINARY = environ.get('AOCC_OVERRIDE', 'clang') + +# compiler variables section +compilers: List[str] = [] + +if 'COMPILER_OVERRIDE' in environ: + compilers.extend(environ['COMPILER_OVERRIDE'].upper().split(',')) +else: + if not (IN_TERMUX and GCC_BINARY == 'g++') and which(GCC_BINARY): # Termux maps gcc->clang + compilers.extend(f'GCC+{std}' for std in STANDARDS) + if which('clang'): + if b'AOCC' in check_output(['clang', '--version']): + compilers.extend(f'AOCC+{std}' for std in STANDARDS) + else: + compilers.extend(f'CLANG+{std}' for std in STANDARDS) + if AOCC_BINARY != 'clang' and which(AOCC_BINARY): + compilers.extend(f'AOCC+{std}' for std in STANDARDS) + for x in ('icc', 'icc'): + if which(x): + compilers.extend(f'{x.upper()}+{std}' for std in STANDARDS) +if not compilers: + raise RuntimeError("No compilers detected!") + +COMPILER_LEN = len(max(compilers, key=len)) # make sure compiler fixtures are evenly spaced +BUILD_FOLDER.mkdir(parents=True, exist_ok=True) +CL_NO_64 = False +if 'CL' in compilers: + OBJ_FOLDER = BUILD_FOLDER.joinpath('objs') + OBJ_FOLDER.mkdir(exist_ok=True) + _test_file = str(CPP_FOLDER.joinpath('assertions', 'x64_assert.cpp')) + _test_exe = str(BUILD_FOLDER.joinpath('test_cl_64_support.out')) + CL_NO_64 = not (run(['cl', '-Fe:{}'.format(_test_exe), '-Fo{}\\'.format(OBJ_FOLDER), str(_test_file)]).returncode) + +_test_file = str(CPP_FOLDER.joinpath('p0000_template.cpp')) +GCC_NO_64 = False +if EXE_EXT == 'x86_64' and 'GCC' in compilers: + # MingW GCC sometimes doesn't have 64-bit support on 64-bit targets + # not knowing this will make the compiler macro test fail + _test_exe = str(BUILD_FOLDER.joinpath('test_gcc_64_support.out')) + GCC_NO_64 = bool(run([GCC_BINARY, _test_file, '-O0', '-m64', '-o', str(_test_exe)]).returncode) + +CLANG_LINK_MATH = CLANG_ARCH = '' +if not IN_WINDOWS: + CLANG_LINK_MATH = '-lm' +if 'CLANG' in compilers: + _test_exe = str(BUILD_FOLDER.joinpath('test_clang_arch_native.out')) + CLANG_ARCH = '-march=native' * (not run(['clang', _test_file, '-O0', '-march=native', '-o', _test_exe]).returncode) + +SOURCE_TEMPLATE = "{}{}p{{:0>4}}.cpp".format(CPP_FOLDER, sep) +EXE_TEMPLATE = "{}{}p{{:0>4}}.{{}}.{}".format(BUILD_FOLDER, sep, EXE_EXT) +# include sep in the recipe so that Windows won't complain + +GCC_TEMPLATE = "{} {{}} -O2 -lm -Wall -Werror -std={} -march=native -flto -fwhole-program -o {{}}" +if environ.get('COV') == 'true': + GCC_TEMPLATE += ' -ftest-coverage -fprofile-arcs' +CLANG_TEMPLATE = "{} {{}} -O2 {} {} -Wall -Werror -std={} {} -o {{}}" + +templates = {} +for std in STANDARDS: + templates.update({ + f'GCC+{std}': GCC_TEMPLATE.format(GCC_BINARY, std), + f'CLANG+{std}': CLANG_TEMPLATE.format('clang', CLANG_LINK_MATH, CLANG_ARCH, std, '-DAMD_COMPILER=0'), + f'ICC+{std}': GCC_TEMPLATE.format('icc', std), + f'AOCC+{std}': CLANG_TEMPLATE.format(AOCC_BINARY, CLANG_LINK_MATH, CLANG_ARCH, std, '-DAMD_COMPILER=1'), + }) + if std in ('c++14', 'c++17', 'c++20'): + templates[f'CL+{std}'] = "cl -Fe:{{1}} -Fo{}\\ /std:{} -O2 -GL -GF -GW -Brepro -TC {{0}}".format(BUILD_FOLDER.joinpath('objs'), std) + + +@register +def cleanup(): + if 'PYTEST_XDIST_WORKER' not in environ: + rmtree(BUILD_FOLDER) + + +@fixture(params=sorted(x.ljust(COMPILER_LEN) for x in compilers)) +def compiler(request): # type: ignore + return request.param.strip() + + +# to make sure the benchmarks sort correctly +@fixture(params=("{:03}".format(x) for x in sorted(answers))) +def key(request): # type: ignore + return int(request.param) # reduce casting burden on test + + +# to make sure the benchmarks sort correctly +@fixture(params=sorted(chain(listdir(CPP_FOLDER.joinpath("tests")), ("{:03}".format(x) for x in answers)))) +def c_file(request): # type: ignore + try: + return SOURCE_TEMPLATE.format(int(request.param)) + except Exception: + return CPP_FOLDER.joinpath("tests", request.param) + + +@mark.skipif('NO_OPTIONAL_TESTS') +def test_compiler_macros(compiler): + exename = EXE_TEMPLATE.format("test_compiler_macros", compiler) + test_path = CPP_FOLDER.joinpath("tests", "test_compiler_macros.cpp") + check_call(templates[compiler].format(test_path, exename).split()) + buff = check_output([exename]) + flags = [bool(int(x)) for x in buff.split()] + expect_32 = (compiler == 'GCC' and GCC_NO_64) or (compiler == 'CL' and CL_NO_64) + assert flags[0] == compiler.startswith("CL+") + assert flags[1] == compiler.startswith("CLANG") + assert flags[2] == compiler.startswith("GCC") + assert flags[3] == compiler.startswith("ICC") + assert flags[4] == compiler.startswith("AOCC") + assert flags[5] == (EXE_EXT == "x86" or expect_32) + assert flags[6] == (EXE_EXT == "x86_64" and not expect_32) + assert flags[7] == (EXE_EXT not in ("x86", "x86_64", "exe")) + + +@mark.skipif('NO_OPTIONAL_TESTS') +def test_deterministic_build(c_file, compiler): + exename1 = EXE_TEMPLATE.format("dbuild{}".format(uuid4()), compiler) + exename2 = EXE_TEMPLATE.format("dbuild{}".format(uuid4()), compiler) + environ['SOURCE_DATE_EPOCH'] = '1' + environ['ZERO_AR_DATE'] = 'true' + check_call(templates[compiler].format(c_file, exename1).split()) + sleep(2) + check_call(templates[compiler].format(c_file, exename2).split()) + try: + with open(exename1, "rb") as f, open(exename2, "rb") as g: + assert f.read() == g.read() + except AssertionError: + if IN_WINDOWS and compiler != 'CL': # mingw gcc doesn't seem to make reproducible builds + xfail() + elif compiler == 'GCC' and environ.get('COV') == 'true': + xfail() # GCC doesn't do reproducible builds w/ code coverage + raise + + +# @mark.skipif('NO_OPTIONAL_TESTS or ONLY_SLOW') +# def test_is_prime(benchmark, compiler): +# from p0007 import is_prime, prime_factors, primes +# MAX_PRIME = 1_000_000 +# exename = EXE_TEMPLATE.format("test_is_prime", compiler) +# test_path = CPP_FOLDER.joinpath("tests", "test_is_prime.cpp") +# args = templates[compiler].format(test_path, exename) + " -DMAX_PRIME={}".format(MAX_PRIME) +# check_call(args.split()) +# with TemporaryFile('wb+') as f: +# run_test = partial(check_call, [exename], stdout=f) +# benchmark.pedantic(run_test, iterations=1, rounds=1) +# prime_cache = tuple(primes(MAX_PRIME)) +# for line in f.readlines(): +# num, prime, composite, idx = (int(x) for x in line.split()) +# assert bool(prime) == bool(is_prime(num)) +# assert bool(composite) == (not is_prime(num)) +# assert composite == 0 or composite == next(iter(prime_factors(num))) +# assert idx == -1 or prime_cache[idx] == num + +# # sometimes benchmark disables itself, so check for .stats +# if hasattr(benchmark, 'stats') and benchmark.stats.stats.max > 200 * MAX_PRIME // 1000000: +# fail("Exceeding 200ns average! (time={}s)".format(benchmark.stats.stats.max)) + + +def test_problem(benchmark, key, compiler): + if (NO_SLOW and key in known_slow) or (ONLY_SLOW and key not in known_slow): + skip() + filename = SOURCE_TEMPLATE.format(key) + exename = EXE_TEMPLATE.format(key, compiler) # need to have both to keep name unique + check_call(templates[compiler].format(filename, exename).split()) + run_test = partial(check_output, [exename]) + + if key in known_slow: + answer = benchmark.pedantic(run_test, iterations=1, rounds=1) + else: + answer = benchmark(run_test) + assert answers[key] == int(answer.strip()) + # sometimes benchmark disables itself, so check for .stats + if hasattr(benchmark, 'stats') and benchmark.stats.stats.median > 60: + fail_func = xfail if key in known_slow else fail + stats = benchmark.stats.stats + fail_func("Exceeding 60s! (Max={:.6}s, Median={:.6}s)".format(stats.max, stats.median)) diff --git a/cplusplus/tests/test_compiler_macros.cpp b/cplusplus/tests/test_compiler_macros.cpp new file mode 100644 index 00000000..eaa4aec5 --- /dev/null +++ b/cplusplus/tests/test_compiler_macros.cpp @@ -0,0 +1,17 @@ +#include +#include "../include/macros.h" + +int main(int argc, char const *argv[]) { + printf( + "%d %d %d %d %d %d %d %d", + CL_COMPILER, + CLANG_COMPILER, + GCC_COMPILER, + INTEL_COMPILER, + AMD_COMPILER, + X86_COMPILER, + X64_COMPILER, + ARM_COMPILER + ); + return 0; +} diff --git a/docs/cplusplus.rst b/docs/cplusplus.rst new file mode 100644 index 00000000..87485f01 --- /dev/null +++ b/docs/cplusplus.rst @@ -0,0 +1,33 @@ +Euler C++ Implementation +====================== + +.. include:: ../cplusplus/README.rst + :start-line: 2 + :end-before: Problems Solved + +Library Code +------------ + +.. toctree:: + :glob: + :numbered: + :maxdepth: 1 + + cplusplus/bcd + cplusplus/digits + cplusplus/factors + cplusplus/fibonacci + cplusplus/iterator + cplusplus/macros + cplusplus/math + cplusplus/primes + +Problems Solved +--------------- + +.. toctree:: + :glob: + :numbered: + :maxdepth: 1 + + cplusplus/p[0-9][0-9][0-9][0-9] diff --git a/docs/cplusplus/p0001.rst b/docs/cplusplus/p0001.rst new file mode 100644 index 00000000..4aa262a9 --- /dev/null +++ b/docs/cplusplus/p0001.rst @@ -0,0 +1,8 @@ +C++ Implementation of Problem 1 +=============================== + +View source code `here on GitHub! `_ + +.. literalinclude:: ../../cplusplus/p0001.cpp + :language: C++ + :linenos: diff --git a/docs/index.rst b/docs/index.rst index 3aaab0fb..cff294ee 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -72,6 +72,7 @@ This project is divided into several Makefiles, connected by a root Makefile whi ``make test`` would be translated to ``make cs_test c_test js_test py_test rs_test`` .. |C| replace:: **C** +.. |Cp| replace:: **C++** .. |C#| replace:: **C#** .. |Js| replace:: **JavaScript** .. |Py| replace:: **Python** @@ -87,163 +88,164 @@ This project is divided into several Makefiles, connected by a root Makefile whi .. rst-class:: centertable -+-----------+------+------+------+------+------+ -| | |C| | |C#| | |Js| | |Py| | |Rs| | -+===========+======+======+======+======+======+ -|Coverage | |d| | |d| | |d| | |d| | |d| | -+-----------+------+------+------+------+------+ -|Docs | |ip| | |d| | |d| | |d| | |d| | -+-----------+------+------+------+------+------+ -|Linting | |d| | |d| | |d| | |d| | |d| | -+-----------+------+------+------+------+------+ -|Testing | |d| | |d| | |d| | |d| | |d| | -+-----------+------+------+------+------+------+ -+-----------+------+------+------+------+------+ -|:prob:`1` | |d| | |d| | |d| | |d| | |d| | -+-----------+------+------+------+------+------+ -|:prob:`2` | |d| | |d| | |d| | |d| | |d| | -+-----------+------+------+------+------+------+ -|:prob:`3` | |d| | | | |d| | |d| | -+-----------+------+------+------+------+------+ -|:prob:`4` | |d| | | | |d| | |d| | -+-----------+------+------+------+------+------+ -|:prob:`5` | |d| | | | |d| | |d| | -+-----------+------+------+------+------+------+ -|:prob:`6` | |d| | |d| | |d| | |d| | |d| | -+-----------+------+------+------+------+------+ -|:prob:`7` | |d| | | | |d| | |d| | -+-----------+------+------+------+------+------+ -|:prob:`8` | |d| | |d| | |d| | |d| | |d| | -+-----------+------+------+------+------+------+ -|:prob:`9` | |d| | |d| | |d| | |d| | |d| | -+-----------+------+------+------+------+------+ -|:prob:`10` | |d| | | | |d| | |d| | -+-----------+------+------+------+------+------+ -|:prob:`11` | |d| | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`12` | |ip| | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`13` | |d| | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`14` | |d| | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`15` | |d| | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`16` | |d| | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`17` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`18` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`19` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`20` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`21` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`22` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`23` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`24` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`25` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`27` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`29` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`30` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`31` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`32` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`33` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`34` | |d| | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`35` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`36` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`37` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`38` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`39` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`40` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`41` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`42` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`43` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`44` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`45` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`46` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`47` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`48` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`49` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`50` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`52` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`53` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`55` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`56` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`57` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`59` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`67` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`69` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`71` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`73` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`74` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`76` | |d| | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`77` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`87` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`92` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`97` | | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`118`| | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`123`| | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`134`| | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`145`| | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`187`| | | | |d| | | -+-----------+------+------+------+------+------+ -|:prob:`206`| | | | |d| | | -+-----------+------+------+------+------+------+ ++-----------+------+------+------+------+------+------+ +| | |C| | |Cp| | |C#| | |Js| | |Py| | |Rs| | ++===========+======+======+======+======+======+======+ +|Coverage | |d| | |d| | |d| | |d| | |d| | |d| | ++-----------+------+------+------+------+------+------+ +|Docs | |ip| | |ip| | |d| | |d| | |d| | |d| | ++-----------+------+------+------+------+------+------+ +|Linting | |d| | |ip| | |d| | |d| | |d| | |d| | ++-----------+------+------+------+------+------+------+ +|Testing | |d| | |d| | |d| | |d| | |d| | |d| | ++-----------+------+------+------+------+------+------+ ++-----------+------+------+------+------+------+------+ +|:prob:`1` | |d| | |d| | |d| | |d| | |d| | |d| | ++-----------+------+------+------+------+------+------+ +|:prob:`2` | |d| | | |d| | |d| | |d| | |d| | ++-----------+------+------+------+------+------+------+ +|:prob:`3` | |d| | | | | |d| | |d| | ++-----------+------+------+------+------+------+------+ +|:prob:`4` | |d| | | | | |d| | |d| | ++-----------+------+------+------+------+------+------+ +|:prob:`5` | |d| | | | | |d| | |d| | ++-----------+------+------+------+------+------+------+ +|:prob:`6` | |d| | | |d| | |d| | |d| | |d| | ++-----------+------+------+------+------+------+------+ +|:prob:`7` | |d| | | | | |d| | |d| | ++-----------+------+------+------+------+------+------+ +|:prob:`8` | |d| | | |d| | |d| | |d| | |d| | ++-----------+------+------+------+------+------+------+ +|:prob:`9` | |d| | | |d| | |d| | |d| | |d| | ++-----------+------+------+------+------+------+------+ +|:prob:`10` | |d| | | | | |d| | |d| | ++-----------+------+------+------+------+------+------+ +|:prob:`11` | |d| | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`12` | |ip| | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`13` | |d| | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`14` | |d| | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`15` | |d| | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`16` | |d| | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`17` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`18` | | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`19` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`20` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`21` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`22` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`23` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`24` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`25` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`27` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`29` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`30` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`31` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`32` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`33` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`34` | |d| | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`35` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`36` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`37` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`38` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`39` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`40` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`41` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`42` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`43` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`44` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`45` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`46` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`47` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`48` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`49` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`50` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`52` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`53` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`55` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`56` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`57` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`59` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`67` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`69` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`71` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`73` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`74` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`76` | |d| | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`77` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`87` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`92` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`97` | | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`118`| | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`123`| | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`134`| | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`145`| | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`187`| | | | | |d| | | ++-----------+------+------+------+------+------+------+ +|:prob:`206`| | | | | |d| | | ++-----------+------+------+------+------+------+------+ .. toctree:: :maxdepth: 2 c + cplusplus csharp javascript python