summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libdimension/compiler-internal.h45
-rw-r--r--libdimension/dimension.h7
-rw-r--r--libdimension/dimension/compiler.h86
-rw-r--r--libdimension/dimension/error.h27
-rw-r--r--libdimension/error.c19
-rw-r--r--libdimension/map.c14
-rw-r--r--libdimension/platform.c6
-rw-r--r--libdimension/tests/tests.h6
8 files changed, 163 insertions, 47 deletions
diff --git a/libdimension/compiler-internal.h b/libdimension/compiler-internal.h
index ffe8de3..8b35b4a 100644
--- a/libdimension/compiler-internal.h
+++ b/libdimension/compiler-internal.h
@@ -23,14 +23,26 @@
* Internally-used compiler abstractions.
*/
-#include <stdbool.h>
+#include <stdalign.h>
+/**
+ * @def dmnsn_likely
+ * Indicate that a test is likely to succeed.
+ * @param test The test to perform.
+ * @return The truth value of \p test.
+ */
+/**
+ * @def dmnsn_unlikely
+ * Indicate that a test is unlikely to succeed.
+ * @param test The test to perform.
+ * @return The truth value of \p test.
+ */
#ifdef DMNSN_PROFILE
#define dmnsn_likely(test) \
dmnsn_expect(!!(test), true, DMNSN_FUNC, __FILE__, __LINE__)
#define dmnsn_unlikely(test) \
dmnsn_expect(!!(test), false, DMNSN_FUNC, __FILE__, __LINE__)
-#elif defined(__GNUC__)
+#elif DMNSN_GNUC
#define dmnsn_likely(test) __builtin_expect(!!(test), true)
#define dmnsn_unlikely(test) __builtin_expect(!!(test), false)
#else
@@ -38,7 +50,24 @@
#define dmnsn_unlikely(test) (!!(test))
#endif
-#ifdef __GNUC__
+/**
+ * @def DMNSN_HOT
+ * Mark a function as a hot path.
+ */
+/**
+ * @def DMNSN_INTERNAL
+ * Mark a function as internal linkage.
+ */
+/**
+ * @def DMNSN_DESTRUCTOR
+ * Queue a function to run at program termination.
+ */
+/**
+ * @def DMNSN_LATE_DESTRUCTOR
+ * Queue a function to run at program termination, after those labeled
+ * DMNSN_DESTRUCTOR.
+ */
+#if DMNSN_GNUC
#define DMNSN_HOT __attribute__((hot))
#define DMNSN_INTERNAL __attribute__((visibility("hidden")))
#define DMNSN_DESTRUCTOR __attribute__((destructor(102)))
@@ -50,4 +79,14 @@
#define DMNSN_LATE_DESTRUCTOR
#endif
+/// Synonym for _Atomic that stdatomic.h doesn't define for some reason
#define atomic _Atomic
+
+/// C11-compliant alloca variant
+#define DMNSN_ALLOCA(var, size) DMNSN_ALLOCA_IMPL(var, size, __LINE__)
+
+#define DMNSN_ALLOCA_IMPL(var, size, ctr) DMNSN_ALLOCA_IMPL2(var, size, ctr)
+
+#define DMNSN_ALLOCA_IMPL2(var, size, ctr) \
+ alignas(max_align_t) char dmnsn_alloca##ctr[size]; \
+ var = (void *)dmnsn_alloca##ctr
diff --git a/libdimension/dimension.h b/libdimension/dimension.h
index b6c1559..71c68fa 100644
--- a/libdimension/dimension.h
+++ b/libdimension/dimension.h
@@ -39,7 +39,9 @@
#ifndef DIMENSION_H
#define DIMENSION_H
-#ifdef __cplusplus
+#include <dimension/compiler.h>
+
+#if DMNSN_CXX
/* We've been included from a C++ file; mark everything here as extern "C" */
extern "C" {
#endif
@@ -53,7 +55,6 @@ extern "C" {
typedef void dmnsn_callback_fn(void *ptr);
/* Include all the libdimension headers */
-#include <dimension/compiler.h>
#include <dimension/error.h>
#include <dimension/malloc.h>
#include <dimension/pool.h>
@@ -87,7 +88,7 @@ typedef void dmnsn_callback_fn(void *ptr);
#include <dimension/scene.h>
#include <dimension/ray_trace.h>
-#ifdef __cplusplus
+#if DMNSN_CXX
}
#endif
diff --git a/libdimension/dimension/compiler.h b/libdimension/dimension/compiler.h
index 3d392b5..af3f4c8 100644
--- a/libdimension/dimension/compiler.h
+++ b/libdimension/dimension/compiler.h
@@ -1,5 +1,5 @@
/*************************************************************************
- * Copyright (C) 2009-2010 Tavian Barnes <tavianator@tavianator.com> *
+ * Copyright (C) 2009-2014 Tavian Barnes <tavianator@tavianator.com> *
* *
* This file is part of The Dimension Library. *
* *
@@ -24,18 +24,70 @@
*/
/**
+ * @internal
+ * @def DMNSN_C_VERSION
+ * The C version according to \p __STDC_VERSION__ if available, otherwise 0.
+ */
+#ifdef __STDC_VERSION__
+ #define DMNSN_C_VERSION __STDC_VERSION__
+#else
+ #define DMNSN_C_VERSION 0L
+#endif
+
+/**
+ * @internal
+ * @def DMNSN_CXX_VERSION
+ * The C++ version according to \p __cplusplus if available, otherwise 0.
+ */
+#ifdef __cplusplus
+ #define DMNSN_CXX_VERSION __cplusplus
+#else
+ #define DMNSN_CXX_VERSION 0L
+#endif
+
+/**
+ * @internal
+ * Whether we're being compiled as C++.
+ */
+#define DMNSN_CXX (DMNSN_CXX_VERSION > 0)
+
+/**
+ * @internal
+ * Whether C++11 features are supported.
+ */
+#define DMNSN_CXX11 (DMNSN_CXX_VERSION >= 201103L)
+
+/**
+ * @internal
+ * Whether C99 features are supported.
+ */
+#define DMNSN_C99 (DMNSN_C_VERSION >= 199901L || DMNSN_CXX11)
+
+/**
+ * @internal
+ * Whether C11 features are supported.
+ */
+#define DMNSN_C11 (DMNSN_C_VERSION >= 201112L)
+
+/**
+ * @internal
+ * Whether GNU C features are supported.
+ */
+#define DMNSN_GNUC defined(__GNUC__)
+
+/**
* @def DMNSN_INLINE
* A portable inline specifier. Expands to the correct method of declaring
* inline functions for the version of C you are using.
*/
#ifndef DMNSN_INLINE
- #ifdef __cplusplus
+ #if DMNSN_CXX
/* C++ inline semantics */
#define DMNSN_INLINE inline
- #elif __STDC_VERSION__ >= 199901L
+ #elif DMNSN_C99
/* C99 inline semantics */
#define DMNSN_INLINE inline
- #elif defined(__GNUC__)
+ #elif DMNSN_GNUC
/* GCC inline semantics */
#define DMNSN_INLINE __extension__ extern __inline__
#else
@@ -46,13 +98,27 @@
#endif
/**
+ * @def DMNSN_NORETURN
+ * A portable noreturn attribute.
+ */
+#if DMNSN_CXX11
+ #define DMNSN_NORETURN [[noreturn]] void
+#elif DMNSN_C11
+ #define DMNSN_NORETURN _Noreturn void
+#elif DMNSN_GNUC
+ #define DMNSN_NORETURN __attribute__((noreturn)) void
+#else
+ #define DMNSN_NORETURN void
+#endif
+
+/**
* @internal
* @def DMNSN_FUNC
* @brief Expands to the name of the current function
*/
-#ifdef __GNUC__
+#if DMNSN_GNUC
#define DMNSN_FUNC __PRETTY_FUNCTION__
-#elif __STDC_VERSION__ >= 199901L
+#elif DMNSN_C99
#define DMNSN_FUNC __func__
#else
#define DMNSN_FUNC "<unknown function>"
@@ -62,14 +128,8 @@
* @internal
* An unreachable statement.
*/
-#ifdef __GNUC__
+#if DMNSN_GNUC
#define DMNSN_UNREACHABLE() __builtin_unreachable()
#else
#define DMNSN_UNREACHABLE() ((void)0)
#endif
-
-/**
- * @internal
- * Whether C99 features are supported.
- */
-#define DMNSN_C99 (__STDC_VERSION__ >= 199901L || __cplusplus >= 201103L)
diff --git a/libdimension/dimension/error.h b/libdimension/dimension/error.h
index f07261e..0561b8a 100644
--- a/libdimension/dimension/error.h
+++ b/libdimension/dimension/error.h
@@ -32,18 +32,15 @@
* Report a warning.
* @param[in] str A string to print explaining the warning.
*/
-#define dmnsn_warning(str) \
- dmnsn_report_error(false, DMNSN_FUNC, __FILE__, __LINE__, str)
+#define dmnsn_warning(str) \
+ dmnsn_report_warning(DMNSN_FUNC, __FILE__, __LINE__, str)
/**
* Report an error.
* @param[in] str A string to print explaining the error.
*/
-#define dmnsn_error(str) \
- do { \
- dmnsn_report_error(true, DMNSN_FUNC, __FILE__, __LINE__, str); \
- DMNSN_UNREACHABLE(); \
- } while (0)
+#define dmnsn_error(str) \
+ dmnsn_report_error(DMNSN_FUNC, __FILE__, __LINE__, str)
/**
* @def dmnsn_assert
@@ -75,15 +72,23 @@
/**
* @internal
- * Called by dmnsn_warning() and dmnsn_error(); don't call directly.
- * @param[in] die Whether the error is fatal.
+ * Called by dmnsn_warning(); don't call directly.
* @param[in] func The name of the function where the error originated.
* @param[in] file The file where the error originated.
* @param[in] line The line number where the error originated.
* @param[in] str A string describing the error.
*/
-void dmnsn_report_error(bool die, const char *func, const char *file,
- unsigned int line, const char *str);
+void dmnsn_report_warning(const char *func, const char *file, unsigned int line, const char *str);
+
+/**
+ * @internal
+ * Called by dmnsn_error(); don't call directly.
+ * @param[in] func The name of the function where the error originated.
+ * @param[in] file The file where the error originated.
+ * @param[in] line The line number where the error originated.
+ * @param[in] str A string describing the error.
+ */
+DMNSN_NORETURN dmnsn_report_error(const char *func, const char *file, unsigned int line, const char *str);
/**
* Treat warnings as errors.
diff --git a/libdimension/error.c b/libdimension/error.c
index 1366c4c..e9e7cf1 100644
--- a/libdimension/error.c
+++ b/libdimension/error.c
@@ -49,10 +49,8 @@ static atomic(dmnsn_fatal_error_fn *) dmnsn_fatal = ATOMIC_VAR_INIT(dmnsn_defaul
/// The current resilience.
static atomic_bool dmnsn_always_die = ATOMIC_VAR_INIT(false);
-// Called by dmnsn_error macro (don't call directly)
void
-dmnsn_report_error(bool die, const char *func, const char *file,
- unsigned int line, const char *str)
+dmnsn_report_impl(bool die, const char *func, const char *file, unsigned int line, const char *str)
{
// Save the value of errno
int err = errno;
@@ -89,7 +87,7 @@ dmnsn_report_error(bool die, const char *func, const char *file,
if (thread_exiting) {
if (die) {
// Prevent infinite recursion if the fatal error function itself calls
- // dmnsn_error() (not dmnsn_warning()) */
+ // dmnsn_error() (not dmnsn_warning())
DMNSN_LOCAL_ERROR("Error raised while in error handler, aborting.");
}
} else {
@@ -103,6 +101,19 @@ dmnsn_report_error(bool die, const char *func, const char *file,
}
void
+dmnsn_report_warning(const char *func, const char *file, unsigned int line, const char *str)
+{
+ dmnsn_report_impl(false, func, file, line, str);
+}
+
+DMNSN_NORETURN
+dmnsn_report_error(const char *func, const char *file, unsigned int line, const char *str)
+{
+ dmnsn_report_impl(true, func, file, line, str);
+ DMNSN_UNREACHABLE();
+}
+
+void
dmnsn_die_on_warnings(bool always_die)
{
atomic_store(&dmnsn_always_die, always_die);
diff --git a/libdimension/map.c b/libdimension/map.c
index 1ae2a10..f5454b1 100644
--- a/libdimension/map.c
+++ b/libdimension/map.c
@@ -23,7 +23,7 @@
* Generic maps.
*/
-#include "dimension.h"
+#include "dimension-internal.h"
/// dmnsn_map definition.
struct dmnsn_map {
@@ -49,8 +49,9 @@ dmnsn_new_map(dmnsn_pool *pool, size_t size)
void
dmnsn_map_add_entry(dmnsn_map *map, double n, const void *obj)
{
- char mem[sizeof(dmnsn_map_entry) + map->obj_size];
- dmnsn_map_entry *entry = (dmnsn_map_entry *)mem;
+ dmnsn_map_entry *entry;
+ DMNSN_ALLOCA(entry, sizeof(dmnsn_map_entry) + map->obj_size);
+
entry->n = n;
memcpy(entry->object, obj, map->obj_size);
@@ -91,11 +92,10 @@ dmnsn_map_evaluate(const dmnsn_map *map, double n,
return;
}
- const dmnsn_map_entry *last = dmnsn_array_last(map->array);
ptrdiff_t skip = sizeof(dmnsn_map_entry) + map->obj_size;
- for (; entry <= last;
- entry = (const dmnsn_map_entry *)((const char *)entry + skip))
- {
+ for (const dmnsn_map_entry *last = dmnsn_array_last(map->array);
+ entry <= last;
+ entry = (const dmnsn_map_entry *)((const char *)entry + skip)) {
n1 = n2;
o1 = o2;
diff --git a/libdimension/platform.c b/libdimension/platform.c
index e0de578..b5d23cc 100644
--- a/libdimension/platform.c
+++ b/libdimension/platform.c
@@ -53,10 +53,10 @@ void
dmnsn_backtrace(FILE *file)
{
#if DMNSN_BACKTRACE
- const size_t size = 128;
- void *buffer[size];
+#define DMNSN_BACKTRACE_SIZE 128
+ void *buffer[DMNSN_BACKTRACE_SIZE];
- int nptrs = backtrace(buffer, size);
+ int nptrs = backtrace(buffer, DMNSN_BACKTRACE_SIZE);
int fd = fileno(file);
if (fd != -1) {
backtrace_symbols_fd(buffer, nptrs, fd);
diff --git a/libdimension/tests/tests.h b/libdimension/tests/tests.h
index afa7c11..2ce2f01 100644
--- a/libdimension/tests/tests.h
+++ b/libdimension/tests/tests.h
@@ -1,5 +1,5 @@
/*************************************************************************
- * Copyright (C) 2009-2012 Tavian Barnes <tavianator@tavianator.com> *
+ * Copyright (C) 2009-2014 Tavian Barnes <tavianator@tavianator.com> *
* *
* This file is part of The Dimension Test Suite. *
* *
@@ -23,7 +23,7 @@
#include "dimension.h"
#include <check.h>
-#ifdef __cplusplus
+#if DMNSN_CXX
// We've been included from a C++ file; mark everything here as extern "C"
extern "C" {
#endif
@@ -122,7 +122,7 @@ void dmnsn_delete_display(dmnsn_display *display);
// Flush the GL buffers
void dmnsn_display_flush(dmnsn_display *display);
-#ifdef __cplusplus
+#if DMNSN_CXX
}
#endif