Skip to content

Commit c644542

Browse files
authored
Alloc tests (#28)
1 parent a0edf72 commit c644542

23 files changed

+1173
-602
lines changed

.clang-tidy

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
---
2-
# Enable ALL the things! Except not really
2+
# Enable ALL the things! Except not really.
3+
#
4+
# NOTE(thinks):
5+
# Sadly, clang-analyzer-unix.Malloc gives false positives when using our
6+
# custom allocators.
37
Checks: "-*,\
48
-google-readability-todo,\
59
clang-analyzer-*,\
10+
-clang-analyzer-unix.Malloc,\
611
-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling,\
712
cert-*,\
813
bugprone-*,\
@@ -16,7 +21,7 @@ Checks: "-*,\
1621
-readability-magic-numbers,\
1722
-readability-identifier-length,\
1823
-readability-function-cognitive-complexity"
19-
WarningsAsErrors: ''
24+
WarningsAsErrors: '*'
2025
CheckOptions:
2126
- key: 'bugprone-argument-comment.StrictMode'
2227
value: 'true'

README.md

+53-32
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
22
[![Standard](https://img.shields.io/badge/c-11-blue.svg)](https://en.wikipedia.org/wiki/C11_(C_standard_revision))
33
[![Standard](https://img.shields.io/badge/c%2B%2B-17-blue.svg)](https://en.wikipedia.org/wiki/C%2B%2B17)
4+
45
![CI](https://github.com/thinks/poisson-disk-sampling/actions/workflows/ci.yml/badge.svg?branch=master)
56
[![codecov](https://codecov.io/github/thinks/poisson-disk-sampling/graph/badge.svg?token=NXIAKWPKAB)](https://codecov.io/github/thinks/poisson-disk-sampling)
67

@@ -11,7 +12,7 @@ This repository contains a [single file](include/thinks/tph_poisson.h), header-o
1112

1213
## Usage
1314

14-
Poisson disk sampling aims to generate a set of samples within a bounded region such that no two samples are closer than some user-specified radius to each other. Let's consider a simple [example](examples(simple_c.c)) written in C.
15+
Poisson disk sampling aims to generate a set of points within a bounded region such that no two points are closer than some user-specified radius to each other. Let's consider a simple [example](examples/simple.c) written in C.
1516

1617
```C
1718
/* C11 */
@@ -26,51 +27,62 @@ Poisson disk sampling aims to generate a set of samples within a bounded region
2627
#define TPH_POISSON_IMPLEMENTATION
2728
#include "thinks/tph_poisson.h"
2829

30+
static_assert(sizeof(tph_poisson_real) == sizeof(float), "");
31+
2932
int main(int argc, char *argv[])
3033
{
3134
(void)argc;
3235
(void)argv;
3336

34-
/* Configure arguments. */
3537
const tph_poisson_real bounds_min[2] = {
36-
(tph_poisson_real)-10,
37-
(tph_poisson_real)-10 };
38+
(tph_poisson_real)-10, (tph_poisson_real)-10 };
3839
const tph_poisson_real bounds_max[2] = {
39-
(tph_poisson_real)10,
40-
(tph_poisson_real)10 };
40+
(tph_poisson_real)10, (tph_poisson_real)10 };
41+
42+
/* Configure arguments. */
4143
const tph_poisson_args args = {
4244
.bounds_min = bounds_min,
4345
.bounds_max = bounds_max,
4446
.radius = (tph_poisson_real)3,
4547
.ndims = INT32_C(2),
4648
.max_sample_attempts = UINT32_C(30),
4749
.seed = UINT64_C(1981) };
50+
4851
/* Using default allocator (libc malloc). */
4952
const tph_poisson_allocator *alloc = NULL;
5053

51-
/* Create samples. */
54+
/* Initialize empty sampling. */
5255
tph_poisson_sampling sampling;
5356
memset(&sampling, 0, sizeof(tph_poisson_sampling));
57+
58+
/* Populate sampling with points. */
5459
const int ret = tph_poisson_create(&args, alloc, &sampling);
5560
if (ret != TPH_POISSON_SUCCESS) {
5661
/* No need to destroy sampling here! */
57-
printf("tph_poisson error, code: %d\n", ret);
62+
printf("Failed creating Poisson sampling! Error code: %d\n", ret);
5863
return EXIT_FAILURE;
5964
}
6065

61-
/* Retrieve samples. */
66+
/* Retrieve sampling points. */
6267
const tph_poisson_real *samples = tph_poisson_get_samples(&sampling);
63-
assert(samples != NULL);
68+
if (samples == NULL) {
69+
/* Shouldn't happen since we check the return value from tph_poisson_create! */
70+
printf("Bad samples!\n");
71+
tph_poisson_destroy(&sampling);
72+
return EXIT_FAILURE;
73+
}
6474

6575
/* Print first and last sample positions. */
66-
printf("\nsimple_c:\n");
67-
printf("samples[%td] = ( %.3f, %.3f )\n",
76+
assert(sampling.nsamples >= 2);
77+
printf("\n%s:\n"
78+
"samples[%td] = ( %.3f, %.3f )\n"
79+
"...\n"
80+
"samples[%td] = ( %.3f, %.3f )\n\n",
81+
"simple (C)",
6882
(ptrdiff_t)0,
6983
(double)samples[0],
70-
(double)samples[1]);
71-
printf("...\n");
72-
printf("samples[%td] = ( %.3f, %.3f )\n\n",
73-
sampling.nsamples - 1,
84+
(double)samples[1],
85+
(ptrdiff_t)(sampling.nsamples - 1),
7486
(double)samples[(sampling.nsamples - 1) * sampling.ndims],
7587
(double)samples[(sampling.nsamples - 1) * sampling.ndims + 1]);
7688

@@ -81,7 +93,7 @@ int main(int argc, char *argv[])
8193
}
8294
```
8395
84-
When using C++ it is possible to safely manage the memory allocated by the tph_poisson functions, as illustrated below:
96+
When using C++ it is possible to safely manage the memory allocated by the tph_poisson functions ([example](examples/simple.cpp)), as illustrated below:
8597
8698
```C++
8799
// C++17
@@ -96,14 +108,14 @@ When using C++ it is possible to safely manage the memory allocated by the tph_p
96108
#define TPH_POISSON_IMPLEMENTATION
97109
#include "thinks/tph_poisson.h"
98110
111+
static_assert(std::is_same_v<tph_poisson_real, float>);
112+
99113
int main(int /*argc*/, char * /*argv*/[])
100114
{
101115
constexpr std::array<tph_poisson_real, 2> bounds_min{
102-
static_cast<tph_poisson_real>(-10),
103-
static_cast<tph_poisson_real>(-10) };
116+
static_cast<tph_poisson_real>(-10), static_cast<tph_poisson_real>(-10) };
104117
constexpr std::array<tph_poisson_real, 2> bounds_max{
105-
static_cast<tph_poisson_real>(10),
106-
static_cast<tph_poisson_real>(10) };
118+
static_cast<tph_poisson_real>(10), static_cast<tph_poisson_real>(10) };
107119
108120
// Configure arguments.
109121
tph_poisson_args args = {};
@@ -113,35 +125,44 @@ int main(int /*argc*/, char * /*argv*/[])
113125
args.bounds_max = bounds_max.data();
114126
args.max_sample_attempts = UINT32_C(30);
115127
args.seed = UINT64_C(1981);
128+
116129
// Using default allocator (libc malloc).
117130
const tph_poisson_allocator *alloc = NULL;
118131
119-
// Create samples.
132+
// Initialize empty sampling.
120133
using unique_poisson_ptr =
121134
std::unique_ptr<tph_poisson_sampling, std::function<void(tph_poisson_sampling *)>>;
122135
auto sampling = unique_poisson_ptr{ new tph_poisson_sampling{}, [](tph_poisson_sampling *s) {
123136
tph_poisson_destroy(s);
124137
delete s;
125138
} };
139+
140+
// Populate sampling with points.
126141
if (const int ret = tph_poisson_create(&args, alloc, sampling.get());
127142
ret != TPH_POISSON_SUCCESS) {
128143
std::printf("tph_poisson error, code: %d\n", ret);
129144
return EXIT_FAILURE;
130145
};
131146
132-
// Retrieve samples.
147+
// Retrieve sampling points.
133148
const tph_poisson_real *samples = tph_poisson_get_samples(sampling.get());
134-
assert(samples != nullptr);
149+
if (samples == nullptr) {
150+
/* Shouldn't happen since we check the return value from tph_poisson_create! */
151+
std::printf("Bad samples!\n");
152+
return EXIT_FAILURE;
153+
}
135154
136155
// Print first and last sample positions.
137-
std::printf("\nsimple_cpp:\n");
138-
std::printf("sample[%td] = ( %.3f, %.3f )\n",
156+
assert(sampling->nsamples >= 2);
157+
std::printf("\n%s:\n"
158+
"samples[%td] = ( %.3f, %.3f )\n"
159+
"...\n"
160+
"samples[%td] = ( %.3f, %.3f )\n\n",
161+
"simple (Cpp)",
139162
(ptrdiff_t)0,
140163
(double)samples[0],
141-
(double)samples[1]);
142-
std::printf("...\n");
143-
std::printf("sample[%td] = ( %.3f, %.3f )\n\n",
144-
sampling->nsamples - 1,
164+
(double)samples[1],
165+
(ptrdiff_t)(sampling->nsamples - 1),
145166
(double)samples[(sampling->nsamples - 1) * sampling->ndims],
146167
(double)samples[(sampling->nsamples - 1) * sampling->ndims + 1]);
147168
@@ -163,9 +184,9 @@ Besides radius and bounds, there are two additional arguments: `seed` and `max_s
163184

164185
Poisson disk sampling generates samples from a blue noise distribution. We can verify this by plotting the corresponding periodogram, noticing that there are minimal low frequency components (close to the center) and no concentrated spikes in energy.
165186

166-
The image below was generated using the code in one of the provided [examples](https://github.com/thinks/poisson-disk-sampling/blob/master/thinks/poisson_disk_sampling/examples/periodogram_example.cc) and is an average over 100 sampling patterns (original pixel resolution was 2048x2048).
187+
The image below was generated using the provided [periodogram example](examples/periodogram_example.cc) and is an average over 100 sampling patterns (original pixel resolution was 2048x2048).
167188

168-
![Average periodogram](images/avg_periodogram_512.png "Average periodogram")
189+
![Average periodogram](images/tph_poisson_periodogram_512.png "Average periodogram")
169190

170191
# Building and installing
171192

cmake/dev-mode.cmake

+4-4
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ if(BUILD_TESTING)
55
add_subdirectory(test)
66
endif()
77

8-
option(BUILD_MCSS_DOCS "Build documentation using Doxygen and m.css" OFF)
9-
if(BUILD_MCSS_DOCS)
10-
include(cmake/docs.cmake)
11-
endif()
8+
# option(BUILD_MCSS_DOCS "Build documentation using Doxygen and m.css" OFF)
9+
# if(BUILD_MCSS_DOCS)
10+
# include(cmake/docs.cmake)
11+
# endif()
1212

1313
option(ENABLE_COVERAGE "Enable coverage support separate from CTest's" OFF)
1414
if(ENABLE_COVERAGE)

cmake/fetch-fftw.cmake

+136
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
# ---- Fetch and install FFTW ----
2+
3+
cmake_policy(PUSH)
4+
5+
if(POLICY CMP0169)
6+
# Allow calling FetchContent_Populate directly.
7+
cmake_policy(SET CMP0169 OLD)
8+
endif()
9+
if(POLICY CMP0135)
10+
# Set the timestamps of extracted contents to the time of extraction.
11+
cmake_policy(SET CMP0135 NEW)
12+
endif()
13+
14+
include(FetchContent)
15+
16+
function(fetch_fftw)
17+
set(options)
18+
set(oneValueArgs VERSION)
19+
set(multiValueArgs)
20+
cmake_parse_arguments(args
21+
"${options}"
22+
"${oneValueArgs}"
23+
"${multiValueArgs}"
24+
${ARGN}
25+
)
26+
27+
FetchContent_Declare(fftw
28+
URL "http://fftw.org/fftw-${args_VERSION}.tar.gz"
29+
)
30+
31+
FetchContent_GetProperties(fftw)
32+
if(NOT fftw_POPULATED)
33+
FetchContent_Populate(fftw)
34+
35+
set(fftw_CACHE_ARGS
36+
"-DCMAKE_INSTALL_PREFIX=${fftw_BINARY_DIR}/install"
37+
"-DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=ON" # PIC
38+
39+
"-DBUILD_SHARED_LIBS:BOOL=OFF" # static libs
40+
"-DBUILD_TESTS:BOOL=OFF" # no tests
41+
42+
"-DENABLE_THREADS:BOOL=ON" # Use pthread
43+
"-DWITH_COMBINED_THREADS:BOOL=ON" # Don't need to link in fftw3f_threads
44+
45+
# "-DENABLE_FLOAT:BOOL=ON" # <float>
46+
47+
# Use SSE, but not AVX.
48+
"-DENABLE_SSE:BOOL=ON"
49+
"-DENABLE_SSE2:BOOL=ON"
50+
"-DENABLE_AVX:BOOL=OFF"
51+
"-DENABLE_AVX2:BOOL=OFF"
52+
53+
"-DDISABLE_FORTRAN:BOOL=ON"
54+
)
55+
56+
if(CMAKE_TOOLCHAIN_FILE)
57+
list(APPEND fftw_CACHE_ARGS
58+
"-DCMAKE_TOOLCHAIN_FILE:FILEPATH=${CMAKE_TOOLCHAIN_FILE}"
59+
)
60+
else()
61+
list(APPEND fftw_CACHE_ARGS
62+
"-DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER}"
63+
)
64+
endif()
65+
66+
get_property(isMulti GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
67+
if(NOT isMulti)
68+
list(APPEND fftw_CACHE_ARGS "-DCMAKE_BUILD_TYPE:STRING=Release")
69+
endif()
70+
unset(isMulti)
71+
72+
set(fftw_GENERATOR_ARGS "")
73+
if(CMAKE_GENERATOR_PLATFORM)
74+
list(APPEND fftw_GENERATOR_ARGS
75+
--build-generator-platform "${CMAKE_GENERATOR_PLATFORM}"
76+
)
77+
endif()
78+
if(CMAKE_GENERATOR_TOOLSET)
79+
list(APPEND fftw_GENERATOR_ARGS
80+
--build-generator-toolset "${CMAKE_GENERATOR_TOOLSET}"
81+
)
82+
endif()
83+
84+
message(STATUS "Configuring and building FFTW-${args_VERSION} immediately")
85+
if (MSVC)
86+
set(generator "Visual Studio 17 2022")
87+
else()
88+
set(generator "Unix Makefiles")
89+
endif()
90+
91+
execute_process(
92+
COMMAND ${CMAKE_CTEST_COMMAND}
93+
--build-and-test ${fftw_SOURCE_DIR} ${fftw_BINARY_DIR}
94+
--build-generator ${generator} ${fftw_GENERATOR_ARGS}
95+
--build-target install
96+
--build-noclean
97+
--build-options ${fftw_CACHE_ARGS}
98+
WORKING_DIRECTORY ${fftw_SOURCE_DIR}
99+
OUTPUT_FILE ${fftw_BINARY_DIR}/build_output.log
100+
ERROR_FILE ${fftw_BINARY_DIR}/build_output.log
101+
RESULT_VARIABLE result
102+
)
103+
104+
unset(generator)
105+
106+
if(result)
107+
file(READ ${fftw_BINARY_DIR}/build_output.log build_log)
108+
message(FATAL_ERROR "Result = ${result}\nFailed FFTW-${args_VERSION} build, see build log:\n"
109+
"${build_log}")
110+
unset(build_log)
111+
endif()
112+
unset(result)
113+
message(STATUS "FFTW-${args_VERSION} build complete")
114+
endif() # fftw_POPULATED
115+
116+
# Confirm that we can find FFTW.
117+
118+
# Ugly work-around for CMake errors in CI builds.
119+
set(_cmake_import_check_xcframework_for_FFTW3::fftw3 "")
120+
121+
find_package(FFTW3
122+
QUIET
123+
REQUIRED
124+
CONFIG
125+
PATHS "${fftw_BINARY_DIR}/install"
126+
NO_DEFAULT_PATH
127+
)
128+
129+
unset(_cmake_import_check_xcframework_for_FFTW3::fftw3)
130+
131+
if(NOT FFTW3_FOUND)
132+
message(FATAL_ERROR "FFTW-${args_VERSION} not found")
133+
endif()
134+
endfunction()
135+
136+
cmake_policy(POP)

cmake/fetch-nlohmann_json.cmake

+6-5
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@
22

33
cmake_policy(PUSH)
44

5-
# Allow calling FetchContent_Populate directly.
65
if(POLICY CMP0169)
6+
# Allow calling FetchContent_Populate directly.
77
cmake_policy(SET CMP0169 OLD)
88
endif()
9+
if(POLICY CMP0135)
10+
# Set the timestamps of extracted contents to the time of extraction.
11+
cmake_policy(SET CMP0135 NEW)
12+
endif()
913

1014
include(FetchContent)
1115

@@ -21,10 +25,7 @@ function(fetch_nlohmann_json)
2125
)
2226

2327
FetchContent_Declare(nlohmann_json
24-
GIT_REPOSITORY https://github.com/nlohmann/json.git
25-
GIT_TAG v${args_VERSION}
26-
GIT_SHALLOW TRUE
27-
GIT_PROGRESS TRUE
28+
URL "https://github.com/nlohmann/json/releases/download/v${args_VERSION}/json.tar.xz"
2829
)
2930

3031
FetchContent_GetProperties(nlohmann_json)

0 commit comments

Comments
 (0)