BLI: Replace some macros with inlined functions for C++
Covers the macro ARRAY_SIZE() and STRNCPY. The problem this change is aimed to solve it to provide cross-platform compiler-independent safe way pf ensuring that the functions are used correctly. The type safety was only ensured for GCC and only for C. The C++ language and Clang compiler would not have detected issues of passing bare pointer to neither of those macros. Now the STRNCPY() will only accept a bounded array as the destination argument, on any compiler. The ARRAY_SIZE as well, but there are a bit more complications to it in terms of transparency of the change. In one place the ARRAY_SIZE was used on float3 type. This worked in the old code because the type implements subscript operator, and the type consists of 3 floats. One would argue this is somewhat hidden/implicit behavior, which better be avoided. So an in-lined value of 3 is used now there. Another place is the ARRAY_SIZE used to define a bounded array of the size which matches bounded array which is a member of a struct. While the ARRAY_SIZE provides proper size in this case, the compiler does not believe that the value is known at compile time and errors out with a message that construction of variable-size arrays is not supported. Solved by converting the field to std::array<> and adding dedicated utility to get size of std::array at compile time. There might be a better way of achieving the same result, or maybe the approach is fine and just need to find a better place for such utility. Surely, more macro from the BLI_string.h can be covered with the C++ inlined functions, but need to start somewhere. There are also quite some changes to ensure the C linkage is not enforced by code which includes the headers. Pull Request: https://projects.blender.org/blender/blender/pulls/108041
This commit is contained in:
parent
a5677d225b
commit
793446cbdc
@ -8,10 +8,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "GHOST_Event.hh"
|
||||
extern "C" {
|
||||
#include "IMB_imbuf.h"
|
||||
#include "IMB_imbuf_types.h"
|
||||
};
|
||||
|
||||
/**
|
||||
* Drag & drop event
|
||||
|
@ -7,12 +7,12 @@
|
||||
#ifndef __MEM_CACHELIMITERC_API_H__
|
||||
#define __MEM_CACHELIMITERC_API_H__
|
||||
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
struct MEM_CacheLimiter_s;
|
||||
struct MEM_CacheLimiterHandle_s;
|
||||
|
||||
|
@ -71,7 +71,8 @@ using blender::Vector;
|
||||
#define CUSTOMDATA_GROW 5
|
||||
|
||||
/* ensure typemap size is ok */
|
||||
BLI_STATIC_ASSERT(ARRAY_SIZE(((CustomData *)nullptr)->typemap) == CD_NUMTYPES, "size mismatch");
|
||||
BLI_STATIC_ASSERT(BOUNDED_ARRAY_TYPE_SIZE<decltype(CustomData::typemap)>() == CD_NUMTYPES,
|
||||
"size mismatch");
|
||||
|
||||
static CLG_LogRef LOG = {"bke.customdata"};
|
||||
|
||||
|
@ -1227,7 +1227,7 @@ static IDProperty *object_asset_dimensions_property(Object *ob)
|
||||
}
|
||||
|
||||
IDPropertyTemplate idprop{};
|
||||
idprop.array.len = ARRAY_SIZE(dimensions);
|
||||
idprop.array.len = 3;
|
||||
idprop.array.type = IDP_FLOAT;
|
||||
|
||||
IDProperty *property = IDP_New(IDP_ARRAY, &idprop, "dimensions");
|
||||
|
@ -201,12 +201,12 @@ void lift_gamma_gain_to_asc_cdl(const float *lift,
|
||||
float *slope,
|
||||
float *power);
|
||||
|
||||
#if BLI_MATH_DO_INLINE
|
||||
# include "intern/math_color_inline.c"
|
||||
#endif
|
||||
|
||||
/** \} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#if BLI_MATH_DO_INLINE
|
||||
# include "intern/math_color_inline.c"
|
||||
#endif
|
||||
|
@ -1402,6 +1402,10 @@ float geodesic_distance_propagate_across_triangle(
|
||||
|
||||
/** \} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Inline Definitions
|
||||
* \{ */
|
||||
@ -1415,7 +1419,3 @@ float geodesic_distance_propagate_across_triangle(
|
||||
#endif
|
||||
|
||||
/** \} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -551,7 +551,10 @@ int BLI_string_find_split_words(const char *str,
|
||||
* \note `ARRAY_SIZE` allows pointers on some platforms.
|
||||
* \{ */
|
||||
|
||||
#define STRNCPY(dst, src) BLI_strncpy(dst, src, ARRAY_SIZE(dst))
|
||||
#ifndef __cplusplus
|
||||
# define STRNCPY(dst, src) BLI_strncpy(dst, src, ARRAY_SIZE(dst))
|
||||
#endif
|
||||
|
||||
#define STRNCPY_RLEN(dst, src) BLI_strncpy_rlen(dst, src, ARRAY_SIZE(dst))
|
||||
#define SNPRINTF(dst, format, ...) BLI_snprintf(dst, ARRAY_SIZE(dst), format, __VA_ARGS__)
|
||||
#define SNPRINTF_RLEN(dst, format, ...) \
|
||||
@ -635,4 +638,17 @@ void BLI_string_debug_size_after_nil(char *str, size_t str_maxncpy);
|
||||
/** \} */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy source string str into the destination dst of a size known at a compile time.
|
||||
* Ensures that the destination is not overflown, and that the destination is always
|
||||
* null-terminated.
|
||||
*
|
||||
* Returns the dst.
|
||||
*/
|
||||
template<size_t N> inline char *STRNCPY(char (&dst)[N], const char *src)
|
||||
{
|
||||
return BLI_strncpy(dst, src, N);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -21,6 +21,9 @@
|
||||
#include "BLI_compiler_typecheck.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
# include <type_traits>
|
||||
# include <utility>
|
||||
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
@ -493,12 +496,15 @@ extern "C" {
|
||||
((void)0)
|
||||
|
||||
/* assuming a static array */
|
||||
#if defined(__GNUC__) && !defined(__cplusplus) && !defined(__clang__) && !defined(__INTEL_COMPILER)
|
||||
# define ARRAY_SIZE(arr) \
|
||||
((sizeof(struct { int isnt_array : ((const void *)&(arr) == &(arr)[0]); }) * 0) + \
|
||||
(sizeof(arr) / sizeof(*(arr))))
|
||||
#else
|
||||
# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(*(arr)))
|
||||
#ifndef __cplusplus
|
||||
# if defined(__GNUC__) && !defined(__cplusplus) && !defined(__clang__) && \
|
||||
!defined(__INTEL_COMPILER)
|
||||
# define ARRAY_SIZE(arr) \
|
||||
((sizeof(struct { int isnt_array : ((const void *)&(arr) == &(arr)[0]); }) * 0) + \
|
||||
(sizeof(arr) / sizeof(*(arr))))
|
||||
# else
|
||||
# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(*(arr)))
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* ARRAY_SET_ITEMS#(v, ...): set indices of array 'v' */
|
||||
@ -867,6 +873,46 @@ extern bool BLI_memory_is_zero(const void *arr, size_t arr_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
namespace blender::blenlib_internal {
|
||||
|
||||
/* A replacement for std::is_bounded_array_v until we go C++20. */
|
||||
template<class T> struct IsBoundedArray : std::false_type {
|
||||
};
|
||||
template<class T, std::size_t N> struct IsBoundedArray<T[N]> : std::true_type {
|
||||
};
|
||||
|
||||
} // namespace blender::blenlib_internal
|
||||
|
||||
/**
|
||||
* Size of a bounded array provided as an arg.
|
||||
*
|
||||
* The arg must be a bounded array, such as int[7] or MyType[11].
|
||||
* Returns the number of elements in the array, known at the compile time.
|
||||
*/
|
||||
template<class T, size_t N> constexpr size_t ARRAY_SIZE(const T (&arg)[N]) noexcept
|
||||
{
|
||||
(void)arg;
|
||||
return N;
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of elements in a type which defines a bounded array.
|
||||
*
|
||||
* For example,
|
||||
* struct MyType {
|
||||
* int array[12];
|
||||
* };
|
||||
*
|
||||
* `BOUNDED_ARRAY_TYPE_SIZE<decltype(MyType::array)>` returns 12.
|
||||
*/
|
||||
template<class T>
|
||||
constexpr std::enable_if_t<blender::blenlib_internal::IsBoundedArray<T>::value, size_t>
|
||||
BOUNDED_ARRAY_TYPE_SIZE() noexcept
|
||||
{
|
||||
return sizeof(std::declval<T>()) / sizeof(std::declval<T>()[0]);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* __BLI_UTILDEFINES_H__ */
|
||||
|
@ -546,6 +546,7 @@ if(WITH_GTESTS)
|
||||
tests/BLI_task_graph_test.cc
|
||||
tests/BLI_task_test.cc
|
||||
tests/BLI_tempfile_test.cc
|
||||
tests/BLI_utildefines_test.cc
|
||||
tests/BLI_uuid_test.cc
|
||||
tests/BLI_vector_set_test.cc
|
||||
tests/BLI_vector_test.cc
|
||||
|
@ -11,6 +11,10 @@
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef __MATH_COLOR_INLINE_C__
|
||||
# define __MATH_COLOR_INLINE_C__
|
||||
|
||||
@ -379,3 +383,7 @@ MINLINE void premul_float_to_straight_uchar(unsigned char *result, const float c
|
||||
}
|
||||
|
||||
#endif /* __MATH_COLOR_INLINE_C__ */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -4,11 +4,9 @@
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
extern "C" {
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_rand.h"
|
||||
#include "PIL_time.h"
|
||||
}
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
@ -1332,3 +1332,18 @@ TEST_F(StringEscape, Control)
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
TEST(BLI_string, bounded_strcpy)
|
||||
{
|
||||
{
|
||||
char str[8];
|
||||
STRNCPY(str, "Hello");
|
||||
EXPECT_STREQ(str, "Hello");
|
||||
}
|
||||
|
||||
{
|
||||
char str[8];
|
||||
STRNCPY(str, "Hello, World!");
|
||||
EXPECT_STREQ(str, "Hello, ");
|
||||
}
|
||||
}
|
||||
|
43
source/blender/blenlib/tests/BLI_utildefines_test.cc
Normal file
43
source/blender/blenlib/tests/BLI_utildefines_test.cc
Normal file
@ -0,0 +1,43 @@
|
||||
/* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "testing/testing.h"
|
||||
|
||||
namespace blender::tests {
|
||||
|
||||
TEST(BLI_utildefines, ARRAY_SIZE)
|
||||
{
|
||||
{
|
||||
int bounded_char[5];
|
||||
static_assert(ARRAY_SIZE(bounded_char) == 5);
|
||||
}
|
||||
|
||||
{
|
||||
int *bounded_char[5];
|
||||
static_assert(ARRAY_SIZE(bounded_char) == 5);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BLI_utildefines, BOUNDED_ARRAY_TYPE_SIZE)
|
||||
{
|
||||
{
|
||||
int bounded_char[5];
|
||||
static_assert(BOUNDED_ARRAY_TYPE_SIZE<decltype(bounded_char)>() == 5);
|
||||
}
|
||||
|
||||
{
|
||||
int *bounded_char[5];
|
||||
static_assert(BOUNDED_ARRAY_TYPE_SIZE<decltype(bounded_char)>() == 5);
|
||||
}
|
||||
|
||||
{
|
||||
struct MyType {
|
||||
int array[12];
|
||||
};
|
||||
|
||||
static_assert(BOUNDED_ARRAY_TYPE_SIZE<decltype(MyType::array)>() == 12);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::tests
|
@ -51,7 +51,7 @@ void View::frustum_boundbox_calc(int view_id)
|
||||
#endif
|
||||
|
||||
MutableSpan<float4> corners = {culling_[view_id].frustum_corners.corners,
|
||||
ARRAY_SIZE(culling_[view_id].frustum_corners.corners)};
|
||||
int64_t(ARRAY_SIZE(culling_[view_id].frustum_corners.corners))};
|
||||
|
||||
float left, right, bottom, top, near, far;
|
||||
bool is_persp = data_[view_id].winmat[3][3] == 0.0f;
|
||||
@ -107,7 +107,7 @@ void View::frustum_culling_sphere_calc(int view_id)
|
||||
{
|
||||
BoundSphere &bsphere = *reinterpret_cast<BoundSphere *>(&culling_[view_id].bound_sphere);
|
||||
Span<float4> corners = {culling_[view_id].frustum_corners.corners,
|
||||
ARRAY_SIZE(culling_[view_id].frustum_corners.corners)};
|
||||
int64_t(ARRAY_SIZE(culling_[view_id].frustum_corners.corners))};
|
||||
|
||||
/* Extract Bounding Sphere */
|
||||
if (data_[view_id].winmat[3][3] != 0.0f) {
|
||||
|
@ -6,12 +6,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ED_file_indexer.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "ED_file_indexer.h"
|
||||
|
||||
/**
|
||||
* File Indexer Service for indexing asset files.
|
||||
*
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <utility>
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
@ -190,6 +191,8 @@ BLI_INLINE uchar f_to_char(const float val)
|
||||
/* to avoid locking in tile initialization */
|
||||
#define TILE_PENDING POINTER_FROM_INT(-1)
|
||||
|
||||
struct ProjPaintState;
|
||||
|
||||
/**
|
||||
* This is mainly a convenience struct used so we can keep an array of images we use -
|
||||
* their #ImBuf's, etc, in 1 array, When using threads this array is copied for each thread
|
||||
@ -217,7 +220,8 @@ struct ProjStrokeHandle {
|
||||
/* Support for painting from multiple views at once,
|
||||
* currently used to implement symmetry painting,
|
||||
* we can assume at least the first is set while painting. */
|
||||
struct ProjPaintState *ps_views[8];
|
||||
ProjPaintState *ps_views[8];
|
||||
|
||||
int ps_views_tot;
|
||||
int symmetry_flags;
|
||||
|
||||
@ -5985,9 +5989,9 @@ void *paint_proj_new_stroke(bContext *C, Object *ob, const float mouse[2], int m
|
||||
ProjStrokeHandle *ps_handle;
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
ToolSettings *settings = scene->toolsettings;
|
||||
char symmetry_flag_views[ARRAY_SIZE(ps_handle->ps_views)] = {0};
|
||||
char symmetry_flag_views[BOUNDED_ARRAY_TYPE_SIZE<decltype(ps_handle->ps_views)>()] = {0};
|
||||
|
||||
ps_handle = MEM_cnew<ProjStrokeHandle>("ProjStrokeHandle");
|
||||
ps_handle = MEM_new<ProjStrokeHandle>("ProjStrokeHandle");
|
||||
ps_handle->scene = scene;
|
||||
ps_handle->brush = BKE_paint_brush(&settings->imapaint.paint);
|
||||
|
||||
|
@ -4526,7 +4526,7 @@ static void wm_event_get_keymap_from_toolsystem_ex(wmWindowManager *wm,
|
||||
{
|
||||
memset(km_result, 0x0, sizeof(*km_result));
|
||||
|
||||
const char *keymap_id_list[ARRAY_SIZE(km_result->keymaps)];
|
||||
const char *keymap_id_list[BOUNDED_ARRAY_TYPE_SIZE<decltype(km_result->keymaps)>()];
|
||||
int keymap_id_list_len = 0;
|
||||
|
||||
/* NOTE(@ideasman42): If `win` is nullptr, this function may not behave as expected.
|
||||
|
Loading…
Reference in New Issue
Block a user