forked from ArchipelagoMW/Archipelago
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Speedups: remove dependency on c++ (ArchipelagoMW#2796)
* Speedups: remove dependency on c++ * Speedups: intset: handle malloc failing * Speedups: intset: fix corner case for int64 on 32bit systems original idea was to only use bucket->val if int<pointer, but we always have a union now anyway * Speedups: add size comment to player_set bucket configuration * test: more tests for LocationStore.find_item * test: require _speedups in CI This kind of tests that the build succeeds. * test: even more tests for LocationStore.find_item * Speedups: intset uniform comment style * Speedups: intset: avoid memory leak when realloc fails * Speedups: intset: make `gcc -pedantic -std=c99 -fanalyzer` without warnings Unnamed unions are not in C99, this got fixed. The overhead of setting count=0 is minimal or optimized-out and silences -fanalizer (see comment). * Speedups: don't leak memory in case of exception * Speedups: intset: validate alloc and free This won't happen in our cython, but it's still a good addition. * CI: add test framework for C/C++ code * CI: ctest: fix cwd * Speedups: intset: ignore msvc warning * Tests: intset: revert attempt at no-asan We solve this with env vars in ctest now, and this fails for msvc. * Test: cpp: docs: fix typo * Test: cpp: docs: fix another typo * Test: intset: proper bucket count for Negative test INTxx_MIN % 1 would not produce a negative number, so the test was flawed.
- Loading branch information
1 parent
b9d1d2c
commit 55d8580
Showing
10 changed files
with
450 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
# Run CMake / CTest C++ unit tests | ||
|
||
name: ctest | ||
|
||
on: | ||
push: | ||
paths: | ||
- '**.cc?' | ||
- '**.cpp' | ||
- '**.cxx' | ||
- '**.hh?' | ||
- '**.hpp' | ||
- '**.hxx' | ||
- '**.CMakeLists' | ||
- '.github/workflows/ctest.yml' | ||
pull_request: | ||
paths: | ||
- '**.cc?' | ||
- '**.cpp' | ||
- '**.cxx' | ||
- '**.hh?' | ||
- '**.hpp' | ||
- '**.hxx' | ||
- '**.CMakeLists' | ||
- '.github/workflows/ctest.yml' | ||
|
||
jobs: | ||
ctest: | ||
runs-on: ${{ matrix.os }} | ||
name: Test C++ ${{ matrix.os }} | ||
|
||
strategy: | ||
fail-fast: false | ||
matrix: | ||
os: [ubuntu-latest, windows-latest] | ||
|
||
steps: | ||
- uses: actions/checkout@v4 | ||
- uses: ilammy/msvc-dev-cmd@v1 | ||
if: startsWith(matrix.os,'windows') | ||
- uses: Bacondish2023/setup-googletest@v1 | ||
with: | ||
build-type: 'Release' | ||
- name: Build tests | ||
run: | | ||
cd test/cpp | ||
mkdir build | ||
cmake -S . -B build/ -DCMAKE_BUILD_TYPE=Release | ||
cmake --build build/ --config Release | ||
ls | ||
- name: Run tests | ||
run: | | ||
cd test/cpp | ||
ctest --test-dir build/ -C Release --output-on-failure |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -178,6 +178,7 @@ dmypy.json | |
cython_debug/ | ||
|
||
# Cython intermediates | ||
_speedups.c | ||
_speedups.cpp | ||
_speedups.html | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,10 @@ | ||
# This file is required to get pyximport to work with C++. | ||
# Switching from std::set to a pure C implementation is still on the table to simplify everything. | ||
# This file is used when doing pyximport | ||
import os | ||
|
||
def make_ext(modname, pyxfilename): | ||
from distutils.extension import Extension | ||
return Extension(name=modname, | ||
sources=[pyxfilename], | ||
language='c++') | ||
depends=["intset.h"], | ||
include_dirs=[os.getcwd()], | ||
language="c") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
/* A specialized unordered_set implementation for literals, where bucket_count | ||
* is defined at initialization rather than increased automatically. | ||
*/ | ||
#include <stddef.h> | ||
#include <stdbool.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
|
||
#ifndef INTSET_NAME | ||
#error "Please #define INTSET_NAME ... before including intset.h" | ||
#endif | ||
|
||
#ifndef INTSET_TYPE | ||
#error "Please #define INTSET_TYPE ... before including intset.h" | ||
#endif | ||
|
||
/* macros to generate unique names from INTSET_NAME */ | ||
#ifndef INTSET_CONCAT | ||
#define INTSET_CONCAT_(a, b) a ## b | ||
#define INTSET_CONCAT(a, b) INTSET_CONCAT_(a, b) | ||
#define INTSET_FUNC_(a, b) INTSET_CONCAT(a, _ ## b) | ||
#endif | ||
|
||
#define INTSET_FUNC(name) INTSET_FUNC_(INTSET_NAME, name) | ||
#define INTSET_BUCKET INTSET_CONCAT(INTSET_NAME, Bucket) | ||
#define INTSET_UNION INTSET_CONCAT(INTSET_NAME, Union) | ||
|
||
#if defined(_MSC_VER) | ||
#pragma warning(push) | ||
#pragma warning(disable : 4200) | ||
#endif | ||
|
||
|
||
typedef struct { | ||
size_t count; | ||
union INTSET_UNION { | ||
INTSET_TYPE val; | ||
INTSET_TYPE *data; | ||
} v; | ||
} INTSET_BUCKET; | ||
|
||
typedef struct { | ||
size_t bucket_count; | ||
INTSET_BUCKET buckets[]; | ||
} INTSET_NAME; | ||
|
||
static INTSET_NAME *INTSET_FUNC(new)(size_t buckets) | ||
{ | ||
size_t i, size; | ||
INTSET_NAME *set; | ||
|
||
if (buckets < 1) | ||
buckets = 1; | ||
if ((SIZE_MAX - sizeof(INTSET_NAME)) / sizeof(INTSET_BUCKET) < buckets) | ||
return NULL; | ||
size = sizeof(INTSET_NAME) + buckets * sizeof(INTSET_BUCKET); | ||
set = (INTSET_NAME*)malloc(size); | ||
if (!set) | ||
return NULL; | ||
memset(set, 0, size); /* gcc -fanalyzer does not understand this sets all buckets' count to 0 */ | ||
for (i = 0; i < buckets; i++) { | ||
set->buckets[i].count = 0; | ||
} | ||
set->bucket_count = buckets; | ||
return set; | ||
} | ||
|
||
static void INTSET_FUNC(free)(INTSET_NAME *set) | ||
{ | ||
size_t i; | ||
if (!set) | ||
return; | ||
for (i = 0; i < set->bucket_count; i++) { | ||
if (set->buckets[i].count > 1) | ||
free(set->buckets[i].v.data); | ||
} | ||
free(set); | ||
} | ||
|
||
static bool INTSET_FUNC(contains)(INTSET_NAME *set, INTSET_TYPE val) | ||
{ | ||
size_t i; | ||
INTSET_BUCKET* bucket = &set->buckets[(size_t)val % set->bucket_count]; | ||
if (bucket->count == 1) | ||
return bucket->v.val == val; | ||
for (i = 0; i < bucket->count; ++i) { | ||
if (bucket->v.data[i] == val) | ||
return true; | ||
} | ||
return false; | ||
} | ||
|
||
static bool INTSET_FUNC(add)(INTSET_NAME *set, INTSET_TYPE val) | ||
{ | ||
INTSET_BUCKET* bucket; | ||
|
||
if (INTSET_FUNC(contains)(set, val)) | ||
return true; /* ok */ | ||
|
||
bucket = &set->buckets[(size_t)val % set->bucket_count]; | ||
if (bucket->count == 0) { | ||
bucket->v.val = val; | ||
bucket->count = 1; | ||
} else if (bucket->count == 1) { | ||
INTSET_TYPE old = bucket->v.val; | ||
bucket->v.data = (INTSET_TYPE*)malloc(2 * sizeof(INTSET_TYPE)); | ||
if (!bucket->v.data) { | ||
bucket->v.val = old; | ||
return false; /* error */ | ||
} | ||
bucket->v.data[0] = old; | ||
bucket->v.data[1] = val; | ||
bucket->count = 2; | ||
} else { | ||
size_t new_bucket_size; | ||
INTSET_TYPE* new_bucket_data; | ||
|
||
new_bucket_size = (bucket->count + 1) * sizeof(INTSET_TYPE); | ||
new_bucket_data = (INTSET_TYPE*)realloc(bucket->v.data, new_bucket_size); | ||
if (!new_bucket_data) | ||
return false; /* error */ | ||
bucket->v.data = new_bucket_data; | ||
bucket->v.data[bucket->count++] = val; | ||
} | ||
return true; /* success */ | ||
} | ||
|
||
|
||
#if defined(_MSC_VER) | ||
#pragma warning(pop) | ||
#endif | ||
|
||
#undef INTSET_FUNC | ||
#undef INTSET_BUCKET | ||
#undef INTSET_UNION |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
cmake_minimum_required(VERSION 3.5) | ||
project(ap-cpp-tests) | ||
|
||
enable_testing() | ||
|
||
find_package(GTest REQUIRED) | ||
|
||
if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") | ||
add_definitions("/source-charset:utf-8") | ||
set(CMAKE_CXX_FLAGS_DEBUG "/MTd") | ||
set(CMAKE_CXX_FLAGS_RELEASE "/MT") | ||
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") | ||
# enable static analysis for gcc | ||
add_compile_options(-fanalyzer -Werror) | ||
# disable stuff that gets triggered by googletest | ||
add_compile_options(-Wno-analyzer-malloc-leak) | ||
# enable asan for gcc | ||
add_compile_options(-fsanitize=address) | ||
add_link_options(-fsanitize=address) | ||
endif () | ||
|
||
add_executable(test_default) | ||
|
||
target_include_directories(test_default | ||
PRIVATE | ||
${GTEST_INCLUDE_DIRS} | ||
) | ||
|
||
target_link_libraries(test_default | ||
${GTEST_BOTH_LIBRARIES} | ||
) | ||
|
||
add_test( | ||
NAME test_default | ||
COMMAND test_default | ||
) | ||
|
||
set_property( | ||
TEST test_default | ||
PROPERTY ENVIRONMENT "ASAN_OPTIONS=allocator_may_return_null=1" | ||
) | ||
|
||
file(GLOB ITEMS *) | ||
foreach(item ${ITEMS}) | ||
if(IS_DIRECTORY ${item} AND EXISTS ${item}/CMakeLists.txt) | ||
message(${item}) | ||
add_subdirectory(${item}) | ||
endif() | ||
endforeach() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# C++ tests | ||
|
||
Test framework for C and C++ code in AP. | ||
|
||
## Adding a Test | ||
|
||
### GoogleTest | ||
|
||
Adding GoogleTests is as simple as creating a directory with | ||
* one or more `test_*.cpp` files that define tests using | ||
[GoogleTest API](https://google.github.io/googletest/) | ||
* a `CMakeLists.txt` that adds the .cpp files to `test_default` target using | ||
[target_sources](https://cmake.org/cmake/help/latest/command/target_sources.html) | ||
|
||
### CTest | ||
|
||
If either GoogleTest is not suitable for the test or the build flags / sources / libraries are incompatible, | ||
you can add another CTest to the project using add_target and add_test, similar to how it's done for `test_default`. | ||
|
||
## Running Tests | ||
|
||
* Install [CMake](https://cmake.org/). | ||
* Build and/or install GoogleTest and make sure | ||
[CMake can find it](https://cmake.org/cmake/help/latest/module/FindGTest.html), or | ||
[create a parent `CMakeLists.txt` that fetches GoogleTest](https://google.github.io/googletest/quickstart-cmake.html). | ||
* Enter the directory with the top-most `CMakeLists.txt` and run | ||
```sh | ||
mkdir build | ||
cmake -S . -B build/ -DCMAKE_BUILD_TYPE=Release | ||
cmake --build build/ --config Release && \ | ||
ctest --test-dir build/ -C Release --output-on-failure | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
target_sources(test_default | ||
PRIVATE | ||
${CMAKE_CURRENT_SOURCE_DIR}/test_intset.cpp | ||
) |
Oops, something went wrong.